(The fix and CVE number for this bug are not known)
A specially crafted web-page can cause Microsoft Internet Explorer 9 to access data before the start of a memory block. An attack that is able to control what is stored before this memory block may be able to disclose information from memory or execute arbitrary code.
Microsoft Internet Explorer 9
After adding two elements with specific style properties during the
event handler, MSIE refreshes the layout, at which point the "content" style
causes it to update a counter, which triggers a call to
CPtsTextParaclient::, in which the exception happens on x86:
CountApes: mov edi,edi push ebp mov ebp,esp sub esp,8 push ebx mov ebx,dword ptr [eax+20h] push esi lea ecx,[eax+24h] push edi mov dword ptr [ebp-8],ecx mov dword ptr [ebp-4],0 test ebx,ebx je MSHTML!CPtsTextParaclient:: CountApes+0x1b7 cmp ebx,dword ptr [ebp-8] je MSHTML!CPtsTextParaclient:: CountApes+0x1b3 mov eax,dword ptr [ebx] ds:0023:dcbabbbb=????????
I enabled page-heap to make triggering the issue more reliable and get a better idea of what is going on. To understand how, a bit of background on how page heap works is needed. When you enable full page-heap in an application, every heap allocation will be given its own "page". This page contains a data structure that contains information used by page-heap to store information about the allocation, followed by the allocated memory itself and then some optional padding. This structure is stored at the end of the page, with the user allocation aligned as required (hence the optional padding). This memory page is followed by a reserved page, which causes any out-of-bounds access immediately after the allocation to cause an access violation exception. Full details can be found in the Application Verifier documentation on-line.
As the documentation shows, the
0xdcbabbbb value in
ebx that causes the
access violation is used by page-heap as the "Prefix end magic": a marker at
the end of the structure used by page-heap to store information about the
allocation that comes immediately before the actual allocation. From the
assembly we can see that
ebx was read from
eax + 0x20, so it might be
interesting to ask page-heap where that points to:
1:020> !heap -p -a @eax address 0b00efb4 found in _DPH_HEAP_ROOT @ 51000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) af126e8: b00efd8 24 - b00e000 2000 71908e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 77c15ede ntdll!RtlDebugAllocateHeap+0x00000030 77bda40a ntdll!RtlpAllocateHeap+0x000000c4 77ba5ae0 ntdll!RtlAllocateHeap+0x0000023a 683928a3 MSHTML!CGeneratedTreeNode::
InitBeginPos+0x00000016 683926b4 MSHTML!CGeneratedContent:: InsertOneNode+0x00000044 6839264d MSHTML!CGeneratedContent:: CreateNode+0x000000b8 68392be1 MSHTML!CGeneratedContent:: CreateContent+0x000000d6 68392b0b MSHTML!CGeneratedContent:: ApplyContentExpressionCore+0x00000109 681a397c MSHTML!CElement:: ComputeFormatsVirtual+0x000021c9 682e9421 MSHTML!CElement:: ComputeFormats+0x000000f1 <<<snip>>>
This tells us that
eax points to 0x0b00efb4, which is 0x24 bytes before the
user allocated memory at 0xb00efd8. So
eax + 0x20 must point 4 bytes before
it and tada: this is where page-heap stores the "Prefix end magic".
It seems that this method is called to operate on an object using a pointer at an offset before the actually allocated memory. This does not make much sense until you've analyzed a lot of MSIE bugs: it's quite common in MSIE for an object to "contain" another object in memory, and for MSIE to add offsets to pointers to find a contained object, or to subtract offsets to find the container of such a contained object. It looks like this is the case here as well.
Looking at the caller, CPtsTextParaclient::
GetNumberApeCorners+0x103 mov ecx,dword ptr [esi+0Ch] mov eax,dword ptr [ecx] and eax,1 lea edx,[ebp+0Ch] lea eax,[eax+eax*2] push edx lea eax,[ecx+eax*8-24h] call MSHTML!CPtsTextParaclient:: CountApes
This code uses a pointer to a memory structure (
esi) to find pointer to a
second structure (
ecx). It reads a flag in
eax and multiplies it by 0x18
(3 x 8:
eax*8), then subtracts 0x24. It then adds this to
ecx to produce the
eax value seen during the crash. Since the flag can be
either 0 or 1, the result in
eax can be either
ecx - 0x24 or
Obviously, in this case it is the former.
It appear that the code is using the flag to determine if
ecx is a
"stand-alone" object or a "contained" object. The bug is that either the code
is using this flag incorrectly (the flag is correct, but does not indicate the
object is a "contained" object) or the flag has been set incorrectly (the code
is correct, but the flag should not have been set as the object is not
"contained" in another object).
Using Heap Feng-Shui, it may be possible to allocated a heap block
immediately before the one used in the bug and control its content in order to
control the data the code is operating on. Unfortunately, at the time I did not
look at what the code did with the data if the access violation could be
prevented, so it's not possible for me to say exactly what an attacker might do
with this vulnerability. But one can speculate that this might allow an
attacker to have the code use some secret value (e.
I did not investigate the crash on x64, but I can only imagine the code is the same, but the offsets are different.
This report was generated using a predecessor of BugId, a Python script created to detect, analyze and id application bugs. Don't waste time manually analyzing issues and writing reports but try BugId out yourself today! You'll get even better reports than this one with the current version.id: MSHTML.
dll!CPtsTextParaclient:: CountApes Arbitrary~BBB AVR(3CE28B51) description: Security: Attempt to read from unallocated arbitrary memory (@0xDCBABBBB) in MSHTML. dll!CPtsTextParaclient:: CountApes note: Based on this information, this is expected to be a security issue!