Cyber security information center

Microsoft Internet Explorer 11 Zero-day

Posted by Vectra Threat Labs on Jul 14, 2015 10:35:00 AM


Summary

On July 6th, information spread that the Italian company known as the Hacking Team were themselves the victims of a cyber attack. In the aftermath of this leak, Vectra researchers have analyzed the leaked data, and identified a previously unknown vulnerability in Internet Explorer 11 that impacts a fully patched IE 11 on both Windows 7 and Windows 8.1.

The hunt for the vulnerability began when we noticed an email from an external researcher who attempted to sell a proof-of-concept exploit to Hacking Team. The email was sent on 02/06/2015 and described an exploitable use-after-free bug in Internet Explorer 11. While Hacking Team ultimately declined to buy the PoC exploit, the email gave enough information for Vectra researchers to find and analyze the vulnerability.

While Hacking Team declined to purchase the PoC exploit, there is a chance the researcher went elsewhere to sell it, meaning that it may have been exploited in the wild.

Severity

High

Versions Affected

Internet Explorer 11.0.9600.17631 / 11.0.16 and also prior versions of IE11.

Overview

The vulnerability is an exploitable use-after-free (UAF) vulnerability that occurs within a custom heap in JSCRIPT9 JIT. Since the vulnerability exists within a custom heap, it may allow an attacker to bypass memory protection technologies.

Vendor Status

Microsoft was notified on July 9th, 2015

Solution

Microsoft has published a fix for this vulnerability on July 14, 2015 and additional information can be found at https://technet.microsoft.com/en-us/library/security/ms15-065.aspx. We recommend users apply this update as soon as possible.


Technical Analysis

When perusing the HackingTeam dumps, we came across an email exchange in which an individual was attempting to sell HT a zero-day. Snippets of the conversation are below (via google translate):

"""
Are you by any chance interested in a PoC (DEP violation) last update to IE11, running on Win7 and Win 8.1? Let me know
Hello is an execution violation sull'eip, I can not control the eip deterministically but seems controllable by the user and should allow code execution.
"""

The researcher does not mention the class of bug at all which is odd and provides no analysis.  If we look further in the email chains, we find the POC and an employee of HT saying basically that it looks interesting and could be a use after free but basically it looks hard.
"""
I did some testing with fast poc sent, at a glance:>> - only crashes with IE11> - sounds interesting, the value of EIP and EAX, should be a use after free> - the poc contains about 80 mutations of the Sun, on the poc old style of Rosario, which is why the root causes> analysis and exploitation does not seem trivial.
"""
We got curious about the details of the crash and downloaded the PoC (803C696C.94C798F2.131_2.html) and removed all the irrelevant artifacts from the researcher's fuzzer.  The result can be seen below.

Screen_Shot_2015-07-13_at_6.14.04_PM
Our question is -- Is this bug a use after free, or something else?  Lets get in a debugger and find out!
(note offsets may be different due to output being from multiple debugging sessions)

If we turn on GFLAGS and load this file into IE11 with windbg attached we see this promising crash
(334.b28): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=047e0000 ebx=04668d20 ecx=65e9c76d edx=00862f84 esi=00000003 edi=04a2c7b4 eip=047e0000 esp=04a2c5dc ebp=04a2c628 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
047e0000 ?? ???

We can certainly see what the HT employee was saying about EAX and EIP at the time of the crash.

At the time, the top of our callstack looks like this:
028ec510 660082cd 02409d20 00000003 03416f30 0x33e0000
028ec560 66008a05 00000003 028ec6ec ffab2388 jscript9!Js::JavascriptFunction::CallFunction<1>+0x91 (FPO: [Non-Fpo])
028ec5d4 6600893f 01cd50f0 00000003 028ec6ec jscript9!Js::JavascriptFunction::CallRootFunction+0xc1 (FPO: [Non-Fpo])
028ec61c 660088bf 028ec644 00000003 028ec6ec jscript9!ScriptSite::CallRootFunction+0x42 (FPO: [Non-Fpo])
028ec64c 6600d0f0 02409d20 028ec674 00000000 jscript9!ScriptSite::Execute+0x61 (FPO: [Non-Fpo])
028ec6a8 6600d02c 00000003 028ec6ec 00000000 jscript9!ScriptEngineBase::ExecuteInternal<0>+0xbb (FPO: [Non-Fpo])
028ec6c0 66e32258 01d1ad10 02409d20 00000003 jscript9!ScriptEngineBase::Execute+0x1c (FPO: [Non-Fpo])
028ec700 66e32166 006eafa8 00000000 00000000 MSHTML!CMutationObserver::PerformMicrotaskCheckpoint+0x97 (FPO: [Non-Fpo])
028ec784 66ed4211 006fda30 028ec79c 006eafa8 MSHTML!CObserverManager::InvokeObserversForCheckpoint+0x78 (FPO: [Non-Fpo])
028ec794 66f3f51e 006eafa8 00000000 00008002 MSHTML!PerformMicrotaskCheckpoint+0x2e (FPO: [0,1,0])
We clearly have corrupted EIP and cannot totally rely on the callstack. We should probably figure out what the callstack actually looks like leading up to the crash. We can breakpoint at jscript9!Js::JavascriptFunction::CallFunction<1> to accomplish this.

This breakpoint is hit several times. On the last time, we step forward until the next relevant call, which is as below.
eax=06996f30 ebx=04619d20 ecx=6600c780 edx=04a8c738 esi=00000003 edi=04a8c904
eip=660082ca esp=04a8c730 ebp=04a8c778 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Js::JavascriptFunction::CallFunction<1>+0x8e:
660082ca ff55f4          call    dword ptr [ebp-0Ch]  ss:0023:04a8c76c=6600c780
0:007> dt 6600c780
NativeCodeGenerator::CheckCodeGen
So it looks like we are making an indirect call into CheckCodeGen. Lets step in.  Here jscript9!NativeCodeGenerator immediately drops into jscript9!NativeCodeGenerator::CheckCodeGenThunk.  There is one subsequent call into jscript9!NativeCodeGenerator::CheckCodeGen, then we end up in this situation
eax=04870000 ebx=04619d20 ecx=6600c76d edx=057aef84 esi=00000003 edi=04a8c904
eip=6600c78f esp=04a8c72c ebp=04a8c778 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGenThunk+0xd:
6600c78f ffe0            jmp     eax {04870000}
Here is where EIP gets corrupted.  If we take a look at the top of the callstack
04a8c728 660082cd 04619d20 00000003 06996f30 jscript9!NativeCodeGenerator::CheckCodeGenThunk+0xd (FPO: [2,0,0])
04a8c778 66008a05 00000003 04a8c904 02fd0849 jscript9!Js::JavascriptFunction::CallFunction<1>+0x91 (FPO: [Non-Fpo])
04a8c7ec 6600893f 057928b8 00000003 04a8c904 jscript9!Js::JavascriptFunction::CallRootFunction+0xc1 (FPO: [Non-Fpo])
04a8c834 660088bf 04a8c85c 00000003 04a8c904 jscript9!ScriptSite::CallRootFunction+0x42 (FPO: [Non-Fpo])
04a8c864 6600d0f0 04619d20 04a8c88c 00000000 jscript9!ScriptSite::Execute+0x61 (FPO: [Non-Fpo])
04a8c8c0 6600d02c 00000003 04a8c904 00000000 jscript9!ScriptEngineBase::ExecuteInternal<0>+0xbb (FPO: [Non-Fpo])
04a8c8d8 66e32258 09afcde0 04619d20 00000003 jscript9!ScriptEngineBase::Execute+0x1c (FPO: [Non-Fpo])
04a8c918 66e32166 0674ecc8 00000000 00000080 MSHTML!CMutationObserver::PerformMicrotaskCheckpoint+0x97 (FPO: [Non-Fpo])
04a8c99c 66ed4211 068a6f98 04a8c9b4 0674ecc8 MSHTML!CObserverManager::InvokeObserversForCheckpoint+0x78 (FPO: [Non-Fpo])
04a8c9ac 66f3f51e 0674ecc8 00000000 00008002 MSHTML!PerformMicrotaskCheckpoint+0x2e (FPO: [0,1,0])
04a8c9f0 667fde4a 02f3f428 04a8cabc 00008002 MSHTML!GlobalWndOnMethodCall+0x18b (FPO: [Non-Fpo])
04a8ca40 77a6c4e7 007c016e 00008002 00000000 MSHTML!GlobalWndProc+0x2e5 (FPO: [Non-Fpo])
We'd like next to know where this value for EAX in our jmp eax came from.  Lets unassemble CheckCodeGenThunk
0:007> u jscript9!NativeCodeGenerator::CheckCodeGenThunk
jscript9!NativeCodeGenerator::CheckCodeGenThunk:
6600c782 55              push    ebp
6600c783 8bec            mov     ebp,esp
6600c785 ff742408        push    dword ptr [esp+8]
6600c789 e812ffffff      call    jscript9!NativeCodeGenerator::CheckCodeGen (6600c6a0)
6600c78e 5d              pop     ebp
6600c78f ffe0            jmp     eax
6600c791 66894daa        mov     word ptr [ebp-56h],cx
6600c795 e909faffff      jmp     jscript9!Js::InterpreterStackFrame::Process+0x9b6 (6600c1a3)
It appears to come from the return value of jscript9!NativeCodeGenerator::CheckCodeGen.  If we look in IDA, there are 3 paths that lead to the return of this function.
 
IE_blog_image1
We will need to single step this function to get a better grasp. Restarting the program with a breakpoint at jscript9!NativeCodeGenerator::CheckCodeGen.
On the last bp hit before the crash, we can set a new breakpoint and follow to the end of the function.
0:007> bc *
0:007> bp jscript9!NativeCodeGenerator::CheckCodeGen+CD
0:007> pa
eax=07416f30 ebx=05209d20 ecx=6600c780 edx=0541c558 esi=00000003 edi=0541c724
eip=6600c6a2 esp=0541c53c ebp=0541c548 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGen+0x2:
6600c6a2 b8e9b72166      mov     eax,offset jscript9!DListBase::DListBase+0x3119 (6621b7e9)
/// SNIP ///
eax=0541c518 ebx=00000001 ecx=05209d20 edx=06189f88 esi=05836100 edi=06258f50
eip=660074ec esp=0541c504 ebp=0541c53c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
jscript9!NativeCodeGenerator::CheckCodeGen+0x113:
660074ec e80a000000      call    jscript9!NativeCodeGenerator::CheckCodeGenDone (660074fb)
eax=073e0000 ebx=00000001 ecx=073e0000 edx=06189f84 esi=05836100 edi=06258f50
eip=660074f1 esp=0541c504 ebp=0541c53c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGen+0x118:
660074f1 e972520000      jmp     jscript9!NativeCodeGenerator::CheckCodeGen+0xc0 (6600c768)
eax=073e0000 ebx=00000001 ecx=073e0000 edx=06189f84 esi=05836100 edi=06258f50
eip=6600c768 esp=0541c504 ebp=0541c53c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGen+0xc0:
6600c768 e8e3cbfeff      call    jscript9!_EH_epilog3 (65ff9350)
Above, we can see our return value is 073e0000, which will later be the address that will be jumped to, corrupting EIP.  This value traces to the return value of jscript9!NativeCodeGenerator::CheckCodeGenDone, as indicated in the image. 
IE_blog_image2
We'd like to check out NativeCodeGenerator::CheckCodeGenDone, pulling a similar trick
Breakpoint 0 hit
eax=04aac728 ebx=00000001 ecx=045c9d20 edx=058e4f88 esi=047e6100 edi=05a88f50
eip=660074fb esp=04aac710 ebp=04aac74c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
jscript9!NativeCodeGenerator::CheckCodeGenDone:
660074fb 8bff            mov     edi,edi
0:007> bp jscript9!NativeCodeGenerator::CheckCodeGenDone+0x81
0:007> pa
eax=04aac728 ebx=00000001 ecx=045c9d20 edx=058e4f88 esi=047e6100 edi=05a88f50
eip=660074fd esp=04aac710 ebp=04aac74c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x2:
660074fd 55              push    ebp
/// SNIP ///
Breakpoint 1 hit
eax=04870000 ebx=00000001 ecx=04870000 edx=058e4f84 esi=047e6100 edi=05a88f50
eip=6600757c esp=04aac710 ebp=04aac74c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x7d:
6600757c c3              ret
Our return value here is our familiarly thrashed EIP 04870000.  Lets see where EAX gets set - 
eax=04870000 ebx=047e6100 ecx=04870000 edx=058e4f84 esi=047e7120 edi=04870000
eip=66007574 esp=04aac6f8 ebp=04aac70c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x75:
66007574 8bc7            mov     eax,edi
Tracing EDI backwards, we can see it was a parameter to jscript9!Js::ScriptFunction::UpdateThunkEntryPoint.
 
eax=058d08b8 ebx=047e6100 ecx=045c9d20 edx=058e4f84 esi=047e7120 edi=04870000
eip=6600756d esp=04aac6f8 ebp=04aac70c iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x6e:
6600756d 57              push    edi
eax=058d08b8 ebx=047e6100 ecx=045c9d20 edx=058e4f84 esi=047e7120 edi=04870000
eip=6600756e esp=04aac6f4 ebp=04aac70c iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x6f:
6600756e 53              push    ebx
eax=058d08b8 ebx=047e6100 ecx=045c9d20 edx=058e4f84 esi=047e7120 edi=04870000
eip=6600756f esp=04aac6f0 ebp=04aac70c iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x70:
6600756f e8c7540000      call    jscript9!Js::ScriptFunction::UpdateThunkEntryPoint (6600ca3b)
eax=04870000 ebx=047e6100 ecx=04870000 edx=058e4f84 esi=047e7120 edi=04870000
eip=66007574 esp=04aac6f8 ebp=04aac70c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x75:
66007574 8bc7            mov     eax,edi
Furthermore, we see it is the same going into the function as coming out of it, so we will make the bold assumption that it was not modified inside there.  We need to trace EDI back further.  The next write operation performed on EDI occurs as a dereference
eax=058d08b8 ebx=047e6100 ecx=00000000 edx=058e4f84 esi=047e7120 edi=662ef9a0
eip=662371c5 esp=04aac6f8 ebp=04aac70c iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x22fcca:
662371c5 8b7e04          mov     edi,dword ptr [esi+4] ds:0023:047e7124=04870000

We now need to trace ESI. We can see that ESI comes from a dereference of EAX.

eax=047e7120 ebx=00000001 ecx=045c9d20 edx=058e4f88 esi=047e6100 edi=05a88f50
eip=66007508 esp=04aac6f8 ebp=04aac70c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
jscript9!NativeCodeGenerator::CheckCodeGenDone+0xd:
66007508 8b7010 mov esi,dword ptr [eax+10h] ds:0023:047e7130=047e7120
Following EAX backwards, we finally get to the source
eax=04aac728 ebx=00000001 ecx=045c9d20 edx=058e4f88 esi=047e6100 edi=05a88f50
eip=66007502 esp=04aac704 ebp=04aac70c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
jscript9!NativeCodeGenerator::CheckCodeGenDone+0x7:
66007502 8b4114 mov eax,dword ptr [ecx+14h] ds:0023:045c9d34=047e7120
ECX here is the 'this' pointer.

So our return value from jscript9!NativeCodeGenerator::CheckCodeGenDone, in this circumstance is is poi(poi(poi(this+0x14)+0x10)+0x04), and that is what is corrupted.

We can check this assumption by performing the dereference on the this pointer at the beginning of CheckCodeGenDone:
0:007> dd poi(poi(poi(073d9d20+0x14)+0x10)+4)
07560000  ???????? ???????? ???????? ????????
07560010  ???????? ???????? ???????? ????????
07560020  ???????? ???????? ???????? ????????
07560030  ???????? ???????? ???????? ????????
07560040  ???????? ???????? ???????? ????????
07560050  ???????? ???????? ???????? ????????
07560060  ???????? ???????? ???????? ????????
07560070  ???????? ???????? ???????? ????????
And continuing the process
(c8c.b84): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07560000 ebx=073d9d20 ecx=6600c76d edx=050aef84 esi=00000003 edi=04ecca3c
eip=07560000 esp=04ecc864 ebp=04ecc8b0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
07560000 ??              ???
We need to figure out how it is corrupted. Lets bounce our debugger again and set a breakpoint again at jscript9!NativeCodeGenerator::CheckCodeGen. The crash happens on the 4th break, so on the third break we check out the this pointer:

0:007> dd poi(poi(068c8d20 + 0x14)+0x10)+4
068a7124  6600cc20 00000002 00000000 068a7120
068a7134  00000000 0000011c 018358b8 068a3210
068a7144  068a5121 00000024 068a4300 00000000
068a7154  068a6100 00000000 00000023 00000000
068a7164  00000001 00000000 05121ea7 000004a7
068a7174  0000002c 0000001d 00000003 000004a7
068a7184  0000002c 050f76a0 00002001 00000000
068a7194  068c8b80 00000000 00000000 00000000
The relevant pointer here is 6600cc20.  We can check out what exactly this member is pointing to
 0:007> dt 6600cc20 
Js::FunctionBody::EnsureDynamicInterpreterThunk
So it looks like the next code path will fail when attempting to call this function above.  We can set a memory write breakpoint to see where this value is getting messed with:
0:007> ba w 4 068a7124
Breakpoint 1 hit
eax=068d0000 ebx=068a7120 ecx=068a7160 edx=068d0fc7 esi=068a7120 edi=05b4afcc
eip=6600cbc6 esp=04ccab68 ebp=04ccab98 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
jscript9!Js::FunctionBody::GenerateDynamicInterpreterThunk+0x22:
6600cbc6 f605405e3c6604  test    byte ptr [jscript9!Microsoft_JScriptEnableBits (663c5e40)],4 ds:0023:663c5e40=00
0:007> kv
ChildEBP RetAddr  Args to Child              
04ccab70 6600cb7c d7314443 04ccad94 068c8d20 jscript9!Js::FunctionBody::GenerateDynamicInterpreterThunk+0x22 (FPO: [0,0,4])
04ccab98 6600cbf7 068a6100 04ccad94 00000003 jscript9!Js::FunctionBody::EnsureDynamicInterpreterThunk+0x64 (FPO: [Non-Fpo])
04ccabac 6600cc2e 068c8d20 04ccac08 660082cd jscript9!Js::InterpreterStackFrame::EnsureDynamicInterpreterThunk+0x1b (FPO: [Non-Fpo])
04ccabb8 660082cd 068c8d20 00000003 06d26f30 jscript9!Js::InterpreterStackFrame::DelayDynamicInterpreterThunk+0xc (FPO: [2,0,0])
04ccac08 66008a05 00000003 04ccad94 d73143a7 jscript9!Js::JavascriptFunction::CallFunction<1>+0x91 (FPO: [Non-Fpo])
04ccac7c 6600893f 018358b8 00000003 04ccad94 jscript9!Js::JavascriptFunction::CallRootFunction+0xc1 (FPO: [Non-Fpo])
04ccacc4 660088bf 04ccacec 00000003 04ccad94 jscript9!ScriptSite::CallRootFunction+0x42 (FPO: [Non-Fpo])
04ccacf4 6600d0f0 068c8d20 04ccad1c 00000000 jscript9!ScriptSite::Execute+0x61 (FPO: [Non-Fpo])
04ccad50 6600d02c 00000003 04ccad94 00000000 jscript9!ScriptEngineBase::ExecuteInternal<0>+0xbb (FPO: [Non-Fpo])
04ccad68 66e32258 0ad22de0 068c8d20 00000003 jscript9!ScriptEngineBase::Execute+0x1c (FPO: [Non-Fpo])
04ccada8 66e32166 00000000 04ccae74 08d50bb8 MSHTML!CMutationObserver::PerformMicrotaskCheckpoint+0x97 (FPO: [Non-Fpo])
04ccae28 66bb6f27 00000000 00000000 04ccae74 MSHTML!CObserverManager::InvokeObserversForCheckpoint+0x78 (FPO: [Non-Fpo])
04ccae40 66bb6297 04ccaeb8 66bb8080 08cd4f6c MSHTML!CMarkup::CScriptExecution::LeaveScriptExecution+0xa8 (FPO: [Non-Fpo])
04ccaeb0 668cfe33 04ccafc0 08cd4f38 08c60bb8 MSHTML!CScriptData::Execute+0x33c (FPO: [Non-Fpo])
04ccaedc 66bb77c7 04ccafc0 04ccaf00 66a03870 MSHTML!CScriptData::ScriptData_OnEnterTree+0x631 (FPO: [Non-Fpo])
04ccaef4 66fa2312 04ccafc0 06bc9bd0 00000000 MSHTML!CScriptElement::Notify+0x3e (FPO: [Non-Fpo])
04ccb208 66eb70fb 04ccb4a0 00000000 04ccb528 MSHTML!CSpliceTreeEngine::InsertSplice+0x1403 (FPO: [0,192,0])
04ccb330 66ee39d9 04ccb37c 04ccb388 08d50bb8 MSHTML!CMarkup::SpliceTreeInternal+0xba (FPO: [6,69,4])
04ccb40c 66896db2 04ccb4a0 04ccb458 04ccb528 MSHTML!CDoc::CutCopyMove+0x27f (FPO: [5,43,4])
04ccb428 66a0cc0f 04ccb4a0 04ccb458 04ccb528 MSHTML!CDoc::Move+0x18 (FPO: [Non-Fpo])
04ccb4e8 66a0ca96 04ccb528 00000000 04ccb618 MSHTML!InsertDOMNodeHelper+0xef (FPO: [Non-Fpo])
04ccb5a8 66a0cc73 08cd4f38 00000000 00000003 MSHTML!CElement::InsertBeforeHelper+0x22b (FPO: [Non-Fpo])
04ccb5cc 66a0cff3 08cd4f38 00000001 00000000 MSHTML!CElement::InsertBefore+0x2f (FPO: [Non-Fpo])
04ccb660 66a0cf06 0ad22de0 04ccb6a0 00000002 MSHTML!CElement::Var_appendChild+0xb3 (FPO: [Non-Fpo])
The actual write is happening one instruction before this. We can see this from the disassembly around:
6600cbbe e8ec000000      call    jscript9!InterpreterThunkEmitter::GetNextThunk (6600ccaf)
6600cbc3 894304          mov     dword ptr [ebx+4],eax
6600cbc6 f605405e3c6604  test    byte ptr [jscript9!Microsoft_JScriptEnableBits (663c5e40)],4
Note that EAX (068d0000) is being moved to [ebx+4] (068a7124).  Also of note is we are still in the MSHTML!CElement::InsertBefore callstack, which we can trace back to the PoC.
Thus the return value of jscript9!InterpreterThunkEmitter::GetNextThunk must be invalid. Lets investigate.
0:016> bp  jscript9!InterpreterThunkEmitter::GetNextThunk
Breakpoint 0 hit
eax=00000000 ebx=04e07120 ecx=055faed0 edx=04e07160 esi=04e07120 edi=063f8fcc
eip=6600ccaf esp=0542a7d0 ebp=0542a808 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!InterpreterThunkEmitter::GetNextThunk:
6600ccaf 8bff            mov     edi,edi
0:007> bp jscript9!InterpreterThunkEmitter::GetNextThunk+0x33
0:007> pa
eax=00000000 ebx=04e07120 ecx=055faed0 edx=04e07160 esi=04e07120 edi=063f8fcc
eip=6600ccb1 esp=0542a7d0 ebp=0542a808 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!InterpreterThunkEmitter::GetNextThunk+0x2:
6600ccb1 55              push    ebp
/// SNIP ///
eax=00000000 ebx=04e07120 ecx=055faed0 edx=04e07160 esi=04e07120 edi=063f8fcc
eip=6600ccb5 esp=0542a7c8 ebp=0542a7cc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!InterpreterThunkEmitter::GetNextThunk+0x6:
6600ccb5 8bf1            mov     esi,ecx
/// SNIP ///
eax=00000000 ebx=04e07120 ecx=000001f6 edx=04e07160 esi=055faed0 edi=063f8fcc
eip=6600ccd0 esp=0542a7c8 ebp=0542a7cc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
jscript9!InterpreterThunkEmitter::GetNextThunk+0x1d:
6600ccd0 8b8620010000    mov     eax,dword ptr [esi+120h] ds:0023:055faff0=051a0000
So this function is basically returning a member of the this instance.  If we look at the heap details

0:007> !heap -p -a  055faed0+0x120
    address 055faff0 found in
    _DPH_HEAP_ROOT @ 1771000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 17730d0:          55faed0              12c -          55fa000             2000
    70eb8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    779961fe ntdll!RtlDebugAllocateHeap+0x00000030
    7795a6bb ntdll!RtlpAllocateHeap+0x000000c4
    77925ca0 ntdll!RtlAllocateHeap+0x0000023a
    76ac9d45 msvcrt!malloc+0x0000008d
    6600048e jscript9!HeapAllocator::Alloc+0x0000000e
    66088a96 jscript9!Js::ScriptContext::InitializePostGlobal+0x000000b5
    660889ca jscript9!Js::ScriptContext::Initialize+0x00000052
    6608894e jscript9!ScriptEngine::EnsureScriptContext+0x000000e3
    6608881b jscript9!ScriptSite::Init+0x00000026
    660848a9 jscript9!ScriptSite::Create+0x0000003f
    6608485f jscript9!ScriptEngine::SetScriptSite+0x00000051
    6698716d MSHTML!CActiveScriptHolder::Init+0x00000146
    66986ef4 MSHTML!CScriptCollection::GetHolderForLanguageHelper+0x000006a8
    6697e3f1 MSHTML!CScriptCollection::ParseScriptText+0x00000095
    66bb6669 MSHTML!CScriptData::CommitCode+0x00000370
    66bb6204 MSHTML!CScriptData::Execute+0x000002a9
    66bb6ca4 MSHTML!CHtmScriptParseCtx::Execute+0x00000130
    669c2c60 MSHTML!CHtmParseBase::Execute+0x00000196
And we can see there is code here
0:007> u poi(055faed0+0x120)
051a0000 55              push    ebp
051a0001 8bec            mov     ebp,esp
051a0003 8b4508          mov     eax,dword ptr [ebp+8]
051a0006 8b4014          mov     eax,dword ptr [eax+14h]
051a0009 8b4840          mov     ecx,dword ptr [eax+40h]
051a000c 8d4508          lea     eax,[ebp+8]
051a000f 50              push    eax
051a0010 b8a0c70066      mov     eax,offset jscript9!Js::InterpreterStackFrame::InterpreterThunk<1> (6600c7a0)
Lets continue the process and break on memory access to both the member and the this pointer (offsets are different because they are a different session)
0:018> ba r1 04f5ced0   ; this ptr
0:018> ba r1 06c70000   ; this.annoying_member
Breakpoint 2 hit
eax=04f5cfe8 ebx=00000000 ecx=04f5ced0 edx=00000000 esi=04485240 edi=04f5ced0
eip=660f7d6a esp=04e6c1a8 ebp=04e6c1b4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!EmitBufferManager::FreeAllocations+0xf:
660f7d6a 85f6            test    esi,esi
Our breakpoint for the this ptr got hit. Lets unassemble and look at the callstack.
0:007> u 660f7d6a - 4
jscript9!EmitBufferManager::FreeAllocations+0xb:
660f7d66 8bf9            mov     edi,ecx
660f7d68 8b37            mov     esi,dword ptr [edi]
660f7d6a 85f6            test    esi,esi
660f7d6c 0f85c21a0000    jne     jscript9!EmitBufferManager::FreeAllocations+0x21 (660f9834)
660f7d72 84db            test    bl,bl
660f7d74 7403            je      jscript9!EmitBufferManager::FreeAllocations+0x1a (660f7d79)
660f7d76 832700          and     dword ptr [edi],0
660f7d79 5f              pop     edi

0:007> kv
ChildEBP RetAddr  Args to Child              
04e6c1b4 660f8629 00000000 05bd0f68 660f8b2c jscript9!EmitBufferManager::FreeAllocations+0xf (FPO: [Non-Fpo])
04e6c1c0 660f8b2c 7ab2217d 04f3a8b8 05bd0f68 jscript9!InterpreterThunkEmitter::Close+0x30 (FPO: [0,0,4])
04e6c1f0 660f7d1a 7ab22291 04f3cf98 04f3a8b8 jscript9!Js::ScriptContext::InternalClose+0x76 (FPO: [Non-Fpo])
04e6c21c 660f8d53 00000000 00000000 660f8a3c jscript9!Js::ScriptContext::Close+0x38 (FPO: [Non-Fpo])
04e6c228 660f8a3c 7ab222fd 04e6c278 660f8cc0 jscript9!Js::ScriptContext::MarkForClose+0x3d (FPO: [0,0,4])
04e6c270 660f883f 04e6c2cc 04ea2dfc 07b83ac8 jscript9!ScriptSite::Close+0x147 (FPO: [Non-Fpo])
04e6c298 660f7e0b 7ab2224d 04e6c2cc 660f7de0 jscript9!ScriptEngine::CloseInternal+0xbc (FPO: [Non-Fpo])
04e6c2c0 66b7d47b 04ea2dfc 04e6c2f0 65ffa790 jscript9!ScriptEngine::Close+0x2b (FPO: [Non-Fpo])
04e6c2e8 66b7dd05 07b83ac8 66b7db00 04e6c320 MSHTML!CActiveScriptHolder::Close+0x6b (FPO: [Non-Fpo])
04e6c318 66b7d4f8 08d44fa8 08d44fa8 050adbb8 MSHTML!CJScript9Holder::Close+0x220 (FPO: [Non-Fpo])
04e6c334 67059005 00000000 66ebe337 06b78f68 MSHTML!CScriptCollection::~CScriptCollection+0x3f (FPO: [Non-Fpo])
04e6c34c 6698199a 08d44fa8 04e6c3b8 667fda00 MSHTML!CScriptCollection::SubRelease+0x83631c
04e6c3b0 66981431 06abdbd0 091cef48 06abdbec MSHTML!CMarkup::OnLoadStatusDone+0x52c (FPO: [Non-Fpo])
04e6c3c4 6698078b 00000004 06bd2f98 04e6c824 MSHTML!CMarkup::OnLoadStatus+0xfa (FPO: [Non-Fpo])
04e6c808 6697a322 10000019 04e6c860 667fe541 MSHTML!CProgSink::DoUpdate+0x4c7 (FPO: [Non-Fpo])
04e6c814 667fe541 091cef48 091cef48 06a7acc8 MSHTML!CProgSink::OnMethodCall+0x12 (FPO: [2,0,0])
04e6c860 667fde4a 7aa93778 04e6c92c 00008002 MSHTML!GlobalWndOnMethodCall+0x16d (FPO: [Non-Fpo])
04e6c8b0 77a6c4e7 01300252 00008002 00000000 MSHTML!GlobalWndProc+0x2e5 (FPO: [Non-Fpo])
04e6c8dc 77a6c5e7 667fd020 01300252 00008002 user32!InternalCallWinProc+0x23
So it does indeed appear that our this pointer is being freed.

As we have broken at the top of this free, we can still inspect the member that is causing our headaches and observe it still contains code
0:007> dd poi(04f5ced0+120)
06c70000  8bec8b55 408b0845 40488b14 5008458d
06c70010  00c7a0b8 ffe1ff66 0fd2e9d0 ff900000
06c70020  0fcae9d0 ff900000 0fc2e9d0 ff900000
06c70030  0fbae9d0 ff900000 0fb2e9d0 ff900000
06c70040  0faae9d0 ff900000 0fa2e9d0 ff900000
06c70050  0f9ae9d0 ff900000 0f92e9d0 ff900000
06c70060  0f8ae9d0 ff900000 0f82e9d0 ff900000
06c70070  0f7ae9d0 ff900000 0f72e9d0 ff900000
Now lets get out of FreeAllocations()
0:007> gu
And inspect again
0:007> dd poi(04f5ced0+120)
06c70000  ???????? ???????? ???????? ????????
06c70010  ???????? ???????? ???????? ????????
06c70020  ???????? ???????? ???????? ????????
06c70030  ???????? ???????? ???????? ????????
06c70040  ???????? ???????? ???????? ????????
06c70050  ???????? ???????? ???????? ????????
06c70060  ???????? ???????? ???????? ????????
06c70070  ???????? ???????? ???????? ????????
Cool! Our memory has indeed become free'd.  Lets continue execution for good measure.

0:007> g

(820.9ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=06c70000 ebx=046f9d20 ecx=6600c76d edx=04f50f84 esi=00000003 edi=04e6c774
eip=06c70000 esp=04e6c59c ebp=04e6c5e8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
06c70000 ??              ???
What is odd now, is that although our memory breakpoint didnt fire again, there is no pageheap information about 06c70000.  Lets start from the beginning and just set a breakpoint where it appears our ptr has been free'd.
0:015> bp  jscript9!EmitBufferManager::FreeAllocations
0:015> g
(6ac.93c): C++ EH exception - code e06d7363 (first chance)

Breakpoint 0 hit
eax=056fafe8 ebx=00000000 ecx=056faed0 edx=00000000 esi=056faed0 edi=056308b8
eip=666c7d5b esp=0562c120 ebp=0562c158 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!EmitBufferManager::FreeAllocations:
666c7d5b 8bff            mov     edi,edi

0:007> dd @ecx
056faed0  04da5240 05630a60 00000000 665d21c8
056faee0  0572cfd0 0572cfd0 056faee8 056faee8
056faef0  056faef0 056faef0 056faef8 056faef8
056faf00  056faf00 056faf00 00000020 00000000
056faf10  00000000 0000001f 00000000 c0000000
056faf20  00000000 00000000 01000000 00000000
056faf30  00000001 00001000 c0c0c000 05630a60
056faf40  056faf40 056faf40 056faf48 056faf48
0:007> dd @ecx+120
056faff0  053e0000 05630a60 000001f6 d0d0d0d0
056fb000  ???????? ???????? ???????? ????????
056fb010  ???????? ???????? ???????? ????????
056fb020  ???????? ???????? ???????? ????????
056fb030  ???????? ???????? ???????? ????????
056fb040  ???????? ???????? ???????? ????????
056fb050  ???????? ???????? ???????? ????????
056fb060  ???????? ???????? ???????? ????????
0:007> dd poi(@ecx+120)
053e0000  8bec8b55 408b0845 40488b14 5008458d
053e0010  5dc7a0b8 ffe1ff66 0fd2e9d0 ff900000
053e0020  0fcae9d0 ff900000 0fc2e9d0 ff900000
053e0030  0fbae9d0 ff900000 0fb2e9d0 ff900000
053e0040  0faae9d0 ff900000 0fa2e9d0 ff900000
053e0050  0f9ae9d0 ff900000 0f92e9d0 ff900000
053e0060  0f8ae9d0 ff900000 0f82e9d0 ff900000
053e0070  0f7ae9d0 ff900000 0f72e9d0 ff900000
Here, poi(@ecx+120) is code as we expect.  Lets set a memory breakpoint on 056faff0, which contains the ptr to that code.
0:007> ba w1 056faff0
0:007> g
Breakpoint 1 hit

eax=056faedc ebx=00000000 ecx=056fafb8 edx=04da5210 esi=056faed0 edi=056308b8
eip=666c8630 esp=0562c128 ebp=0562c158 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!InterpreterThunkEmitter::Close+0x37:
666c8630 83a62801000000  and     dword ptr [esi+128h],0 ds:0023:056faff8=000001f6

0:007> dd 056faff0  
056faff0  00000000 05630a60 000001f6 d0d0d0d0
056fb000  ???????? ???????? ???????? ????????
056fb010  ???????? ???????? ???????? ????????
056fb020  ???????? ???????? ???????? ????????
056fb030  ???????? ???????? ???????? ????????
056fb040  ???????? ???????? ???????? ????????
056fb050  ???????? ???????? ???????? ????????
056fb060  ???????? ???????? ???????? ????????
Ok, so our ptr has been nulled out in the object inside jscript9!InterpreterThunkEmitter::Close.  The origin of this appears to be the destructor for CScriptCollection (the same as our free above)
0:007> kv
ChildEBP RetAddr  Args to Child              
0562c128 666c8b2c ef1f07e1 056308b8 063e0f68 jscript9!InterpreterThunkEmitter::Close+0x37 (FPO: [0,0,4])
0562c158 666c7d1a ef1f073d 00788f98 056308b8 jscript9!Js::ScriptContext::InternalClose+0x76 (FPO: [Non-Fpo])
0562c184 666c8d53 00000000 00000000 666c8a3c jscript9!Js::ScriptContext::Close+0x38 (FPO: [Non-Fpo])
0562c190 666c8a3c ef1f0761 0562c1e0 666c8cc0 jscript9!Js::ScriptContext::MarkForClose+0x3d (FPO: [0,0,4])
0562c1d8 666c883f 0562c234 00786dfc 09402ac8 jscript9!ScriptSite::Close+0x147 (FPO: [Non-Fpo])
0562c200 666c7e0b ef1f0491 0562c234 666c7de0 jscript9!ScriptEngine::CloseInternal+0xbc (FPO: [Non-Fpo])
0562c228 6b0bd47b 00786dfc 0562c258 665ca790 jscript9!ScriptEngine::Close+0x2b (FPO: [Non-Fpo])
0562c250 6b0bdd05 09402ac8 6b0bdb00 0562c288 MSHTML!CActiveScriptHolder::Close+0x6b (FPO: [Non-Fpo])
0562c280 6b0bd4f8 08aeefa8 08aeefa8 0586dbb8 MSHTML!CJScript9Holder::Close+0x220 (FPO: [Non-Fpo])
0562c29c 6b599005 00000000 6b3fe337 07459f68 MSHTML!CScriptCollection::~CScriptCollection+0x3f (FPO: [Non-Fpo])
0562c2b4 6aec199a 08aeefa8 0562c320 6ad3da00 MSHTML!CScriptCollection::SubRelease+0x83631c
0562c318 6aec1431 0739ebd0 08acef48 0739ebec MSHTML!CMarkup::OnLoadStatusDone+0x52c (FPO: [Non-Fpo])
0562c32c 6aec078b 00000004 075d4f98 0562c78c MSHTML!CMarkup::OnLoadStatus+0xfa (FPO: [Non-Fpo])
0562c770 6aeba322 10000019 0562c7c8 6ad3e541 MSHTML!CProgSink::DoUpdate+0x4c7 (FPO: [Non-Fpo])
0562c77c 6ad3e541 08acef48 08acef48 0735bcc8 MSHTML!CProgSink::OnMethodCall+0x12 (FPO: [2,0,0])
0562c7c8 6ad3de4a ef37235b 0562c894 00008002 MSHTML!GlobalWndOnMethodCall+0x16d (FPO: [Non-Fpo])
0562c818 7684c4e7 000e02de 00008002 00000000 MSHTML!GlobalWndProc+0x2e5 (FPO: [Non-Fpo])
0562c844 7684c5e7 6ad3d020 000e02de 00008002 user32!InternalCallWinProc+0x23
0562c8bc 7684cc19 00000000 6ad3d020 000e02de user32!UserCallWinProcCheckWow+0x14b (FPO: [Non-Fpo])
0562c91c 7684cc70 6ad3d020 00000000 0562fafc user32!DispatchMessageWorker+0x35e (FPO: [Non-Fpo])
0562c92c 6ddcf7c8 0562c96c 0077ee48 051cefe0 user32!DispatchMessageW+0xf (FPO: [Non-Fpo])
0562fafc 6df1f738 0562fbc8 6df1f3b0 00780ff0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x464 (FPO: [Non-Fpo])
0562fbbc 7643e61c 0077ee48 0562fbe0 6df230d0 IEFRAME!LCIETab_ThreadProc+0x37b (FPO: [Non-Fpo])
0562fbd4 70833991 00780ff0 00000000 00000000 iertutil!_IsoThreadProc_WrapperToReleaseScope+0x1c (FPO: [Non-Fpo])
0562fc0c 760cee6c 050eefe8 0562fc58 77b7399b IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x94 (FPO: [Non-Fpo])
0562fc18 77b7399b 050eefe8 72ca3051 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0562fc58 77b7396e 70833900 050eefe8 ffffffff ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0562fc70 00000000 70833900 050eefe8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
This looks reasonably normal. So what gives?

The trick is in the callstack we examined previously, where we see our headache region being freed. Lets take another look
60f8629 00000000 05bd0f68 660f8b2c jscript9!EmitBufferManager::FreeAllocations+0xf (FPO: [Non-Fpo])
04e6c1c0 660f8b2c 7ab2217d 04f3a8b8 05bd0f68 jscript9!InterpreterThunkEmitter::Close+0x30 (FPO: [0,0,4])
04e6c1f0 660f7d1a 7ab22291 04f3cf98 04f3a8b8 jscript9!Js::ScriptContext::InternalClose+0x76 (FPO: [Non-Fpo])
04e6c21c 660f8d53 00000000 00000000 660f8a3c jscript9!Js::ScriptContext::Close+0x38 (FPO: [Non-Fpo])
04e6c228 660f8a3c 7ab222fd 04e6c278 660f8cc0 jscript9!Js::ScriptContext::MarkForClose+0x3d (FPO: [0,0,4])
04e6c270 660f883f 04e6c2cc 04ea2dfc 07b83ac8 jscript9!ScriptSite::Close+0x147 (FPO: [Non-Fpo])
04e6c298 660f7e0b 7ab2224d 04e6c2cc 660f7de0 jscript9!ScriptEngine::CloseInternal+0xbc (FPO: [Non-Fpo])
04e6c2c0 66b7d47b 04ea2dfc 04e6c2f0 65ffa790 jscript9!ScriptEngine::Close+0x2b (FPO: [Non-Fpo])
04e6c2e8 66b7dd05 07b83ac8 66b7db00 04e6c320 MSHTML!CActiveScriptHolder::Close+0x6b (FPO: [Non-Fpo])
04e6c318 66b7d4f8 08d44fa8 08d44fa8 050adbb8 MSHTML!CJScript9Holder::Close+0x220 (FPO: [Non-Fpo])
04e6c334 67059005 00000000 66ebe337 06b78f68 MSHTML!CScriptCollection::~CScriptCollection+0x3f (FPO: [Non-Fpo])
04e6c34c 6698199a 08d44fa8 04e6c3b8 667fda00 MSHTML!CScriptCollection::SubRelease+0x83631c
04e6c3b0 66981431 06abdbd0 091cef48 06abdbec MSHTML!CMarkup::OnLoadStatusDone+0x52c (FPO: [Non-Fpo])
04e6c3c4 6698078b 00000004 06bd2f98 04e6c824 MSHTML!CMarkup::OnLoadStatus+0xfa (FPO: [Non-Fpo])
04e6c808 6697a322 10000019 04e6c860 667fe541 MSHTML!CProgSink::DoUpdate+0x4c7 (FPO: [Non-Fpo])
04e6c814 667fe541 091cef48 091cef48 06a7acc8 MSHTML!CProgSink::OnMethodCall+0x12 (FPO: [2,0,0])
04e6c860 667fde4a 7aa93778 04e6c92c 00008002 MSHTML!GlobalWndOnMethodCall+0x16d (FPO: [Non-Fpo])
04e6c8b0 77a6c4e7 01300252 00008002 00000000 MSHTML!GlobalWndProc+0x2e5 (FPO: [Non-Fpo])
04e6c8dc 77a6c5e7 667fd020 01300252 00008002 user32!InternalCallWinProc+0x23
What does jscript9!EmitBufferManager::FreeAllocations do exactly?
Well inspecting in IDA, we can see it does one of two things
(1)
push    dword ptr [esi] ; struct CustomHeap::Allocation *
mov     ecx, eax        ; this
call    ?Free@Heap@CustomHeap@@QAE_NPAUAllocation@2@@Z ; CustomHeap::Heap::Free(CustomHeap::Allocation *)
jmp     short loc_10109839
; END OF FUNCTION CHUNK FOR ?FreeAllocations@EmitBufferManager@@AAEX_N@Z
--- OR ---
(2)
push    dword ptr [esi]
mov     ecx, eax        ; this
call    ?Decommit@Heap@CustomHeap@@QAE_NPAUAllocation@2@@Z ; CustomHeap::Heap::Decommit(CustomHeap::Allocation *)
jmp     loc_10109839
; END OF FUNCTION CHUNK FOR ?FreeAllocations@EmitBufferManager@@AAEX_N@Z
Ok.  So, we dont have pageheap information because the fault is occuring inside a custom heap implementation in JSCRIPT9.  That makes some sense.

We now know that we are attemting to access memory that has been freed by CustomHeap::Heap::Free, but where was it allocated?

Logically if it was free'd with jscript9!EmitBufferManager::FreeAllocations, it would be allocated by something like jscript9!EmitBufferManager::


Browsing the symbols we find the releveant funciton NewAllocation and set our breakpoint.

0:015> bp jscript9!EmitBufferManager::NewAllocation
0:015> g
ModLoad: 6c410000 6c44c000 C:\Windows\system32\OLEACC.DLL
ModLoad: 75a00000 75a5f000 C:\Windows\system32\SXS.DLL
ModLoad: 6c470000 6c4fc000 C:\Windows\system32\uiautomationcore.dll
ModLoad: 77ca0000 77ca5000 C:\Windows\system32\PSAPI.DLL
Breakpoint 0 hit
eax=0553bcf8 ebx=07365000 ecx=0614aed0 edx=07365040 esi=00000000 edi=0614aed0
eip=662f1688 esp=0553bca8 ebp=0553bccc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
jscript9!EmitBufferManager::NewAllocation:
662f1688 6a08 push 8

Cool lets go up one level now

0:007> gu
eax=06185240 ebx=07725000 ecx=65fa16df edx=00000018 esi=00000000 edi=0644eed0
eip=65fa1627 esp=0570bfd8 ebp=0570bfec iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
jscript9!EmitBufferManager::AllocateBuffer+0x37:
65fa1627 8bf0 mov esi,eax

Alright so lets check out our return value

0:007> dd @eax
05055240 05055230 00000000 00001000 00000000
05055250 00000000 00000000 00000000 00000000
05055260 00000000 00000000 00000000 00000000
05055270 00000000 00000000 00000000 00000000
05055280 00000000 00000000 00000000 00000000
05055290 00000000 00000000 00000000 00000000
050552a0 00000000 00000000 00000000 00000000
050552b0 00000000 00000000 00000000 00000000

0:007> dd poi(@eax)
05055230 05055218 00000000 07860000 00001000
05055240 05055230 00000000 00001000 00000000
05055250 00000000 00000000 00000000 00000000
05055260 00000000 00000000 00000000 00000000
05055270 00000000 00000000 00000000 00000000
05055280 00000000 00000000 00000000 00000000
05055290 00000000 00000000 00000000 00000000
050552a0 00000000 00000000 00000000 00000000

 

0:007> !heap -p -a @eax

 

0:007> !heap -p -a poi(@eax)

 

0:007> !heap -p -a poi(@eax)+8

 

We can see our suspicious heap value lurking at an offset in there, and predictably there is no awesome user stack trace info from pageheap.  Lets follow it out another level

// Snip //

0:007> p
eax=05055240 ebx=07365000 ecx=07860000 edx=00000018 esi=0614aed0 edi=062eafcc
eip=66393240 esp=0553bce8 ebp=0553bd00 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
jscript9!InterpreterThunkEmitter::NewThunkBlock+0x26:
66393240 8b7df8 mov edi,dword ptr [ebp-8] ss:0023:0553bcf8=07860000

And lets continue the process

0:007> g
(86c.e10): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07860000 ebx=07349d20 ecx=662cc76d edx=06130f84 esi=00000003 edi=0553c464
eip=07860000 esp=0553c28c ebp=0553c2d8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
07860000 ?? ???

So we have seen that we have a buffer allocated in a custom heap implementation with jscript9!EmitBufferManager::NewAllocation that contains executable code, which is then freed by jscript9!EmitBufferManager::FreeAllocations. This memory is then used again in jscript9!NativeCodeGenerator::CheckCodeGenThunk causing our crash in a use-after-free type scenerio.

 

New Call-to-action

Topics: Vulnerabilities