(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
An attacker would need to get a target user to open a specially crafted web-page. As far as can be determined, disabling JavaScript should prevent an attacker from triggering the vulnerable code path.
After adding two elements with specific style properties during the onload
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:
MSHTML!CPtsTextParaclient:: 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::
MSHTML!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+eax*2
and 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 ecx
.
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!