Monday, August 29, 2011

Targeted Heap Spraying – 0x0c0c0c0c is a Thing of the Past

Traditionally, heap spraying has relied upon spraying with 0x0C0C0C0C followed by shellcode which serves as both an address in the heap and a series of nops. This however is not extremely reliable. You have to be lucky enough to not land on a heap header or somewhere in your shellcode. Additionally, the latest version of EMET now prevents the execution of address 0x0C0C0C0C or any other arbitrary address specified in the registry. While this is a futile attempt to prevent heap spraying, it will require another method to reliably execute shellcode in the heap. Rather, there is a method that allows you to reliably allocate shellcode that is both in a predictable location and memory page-aligned (64K-aligned).

It turns out that allocations in Javascript of at least 512K are allocated using VirtualAlloc, which returns addresses that are page aligned (i.e. in the form of 0xXXXX0000). I credit Alexander Sotirov with this discovery as I learned this technique from him. There are many ways to place shellcode in the heap but string allocations are the tried and true heap allocation primitive in javascript. The format of a javascript string on the heap is as follows:

[string length - 4 bytes][Unicode encoded string][\x00\x00]

The following diagram illustrates a string’s layout in memory:

Therefore, any javascript string will be 6 bytes long plus the length of the Unicode encoded string. Also, heap chunks allocated with VirtualAlloc are 0x20 bytes in length. As a result, shellcode allocated through VirtualAlloc will always reside at offset 0x24. Also, because each allocation results in a 64K-aligned address, we can make a series of string allocations that equal exactly 64K. That way, the start of our shellcode will always be located at an address of the form (0xXXXX0024).

The following javascript code takes advantage of these concepts by allocating an array of sixteen 64K strings (i.e. 1 megabyte).Note the sixteenth allocation accounts for the size of the heap header and string length so that exactly one megabyte gets allocated. The resultant array is then allocated one hundred times resulting in an allocation of exactly 100MB.

You can clearly see the string length at offset 0x20 – 000fffda which is the length of the string minus the null terminator.

Another way to analyze your heap allocations is through the fragmentation view of VMmap – one of many incredibly useful tools in the Sysinternals suite. The following image shows an allocation of 1000MB. Within the fragmentation view you can zoom in and click on individual allocations and confirm that each heap allocation (in orange) begins at an address in the form of 0xXXXX0000.

So why is this technique so useful? This method of heap spraying is perfect when exploiting use-after-free vulnerabilities where an attacker can craft fake objects and vtable structures. A fake vtable pointer can then point to an address in the heap range – 0x11F50024 just as an example. Thus, there is no need to rely upon nops and no need to worry about EMET’s arbitrary prevention of executing 0x0C0C0C0C-style addresses. For all intents and purposes, you’ve completely bypassed ASLR protections.

13 comments:

Thanks for the writeup. Does heaplib have a different header? IIRC heapLib uses HeapAlloc instead of VirtualAlloc, and the start of each chunk begins at offset 0x48 (including the length field), which is different than the 0x20 offset like you described.

There will be a different header depending upon whether HeapAlloc decides to use the backend allocator - FreeList or VirtualAlloc or the frontend allocator - lookaside list (XP) or low fragmentation heap (Vista/Win 7). This decision comes down to the size of the allocation, the availability of free blocks, etc. If the requested allocation is >= 512 KB, HeapAlloc will essentially bypass the backend allocator and call VirtualAlloc directly. You can confirm all of this in a debugger.

Heaplib doesn't use a certain library function over another. It has no way of doing that directly. Instead, like in my post, it declares strings in Javascript which get allocated in the default process heap. Again, the details of how the strings get allocated on the back end depends upon the size of the string. Alexander Sotirov mentions this in his Heap Feng Shui talk.

Actually, this technique is not reliable (or I've missed something). The 1MB blocs will always be correctly allocated at addresses in the form of 0xXXXX0000, but by running the script you provide, I've seen that the first part of those addresses is not always the same.

This technique doesn't guarantee where the first heap chunk will actually land. What it will ensure is that a contiguous block of shellcode will be allocated at addresses of the form 0xXXXX0000 as can be seen in the output you provided. The starting address of the first heap chuck depends on the memory usage of your browser at that snapshot in time. The key is to determine the right balance in terms of how much you spray and deciding on a landing spot somewhere in-between. In the output you provided, the most reliable address would be somewhere in the middle of the overlap of your addresses. So in your case, a page on or around 0x091D0000 would probably be a happy medium. Let me know if that doesn't make sense.

This technique only attempts to tackle ASLR. However, if you can leverage a vulnerability that can get your shellcode into the stack via a stack pivot, you have a reliable location where a rop chain can be stored. There is no panacea to exploitation these days with all the exploit mitigation techniques. This is merely an arrow in the quiver.

Because I'm accounting for the padding for the last page of memory. The 38 accounts for the header and null padding at the end of the string. If that wasn't there, a portion of the string (38 bytes) would run into the next memory page and cause a misalignment when new block are allocated in the heap spray.