6,521 views
BlackHatEU2013 – Day2 – Advanced Heap Manipulation in Windows 8
Good afternoon everyone,
The next talk I will be covering today is presented by Zhenhua ‘Eric’ Liu, Senior Security researcher at Fortinet.
Why doing this type of research.
Facts : Exploiting memory corruption vulnerabilities are more difficult today, because of OS security improvements and Sandboxing techniques implemented into various applications. Bypassing sandboxes often rely on techniques to break the integrity of the underlying OS.
The patched Windows 7 kernel includes
- null dereference protection
- kernel pool integrity checks
- non-paged pool NX
- enhanced ASLR
- SMPE/PXN
The Windows 8 User Heap includes measures to decrease determinism.
All of this makes it increasingly more difficult to exploit memory corruption bugs. Even if you find a way to attack application data and gain control over EIP, you’ll have to take multiple hurdles to build a working exploit. Eric also mentions that applications that use custom heap management routines or allocators might be interesting because they might not be protecting the metadata and/or take care of decreasing the level of determinism in their implementation.
With application specific attacks you need to find a way to place “parts” in a specific way, in a specific order, at a specific location in memory, Eric continues. Ideally they would be adjacent so you could overflow from the vulnerable object into the adjacent chunk. It is clear that modern Heap Feng Shui, which defeats randomisation, would be very valuable.
Defragmentation of the heap is key, Eric says. if you can remove the noise, you have a better chance at placing your chunks in the desired order. The problem is that the traditional defragmentation allocation sequences will trigger the LFH. This needs to be avoided because all subsequent allocations may not be placed where you want them to be.
The challenges are: How can we place a desired object just behind the vulnerable buffer ? Can we place something else than an object just behind the vulnerable buffer ?
Concepts & Techniques
Before looking at the solution, Eric covers some heap basics. FreeLists consists of doubly linked lists and is used for fast allocation & free. Chunks are handled in a LIFO manner. FreeLists are still used in both kernel pool and user heap in Windows 8. FreeLists contain metadata and this metadata could still be an interesting target.
There are 3 ways to put something on the FreeLists:
- Direct free
- Split a big chunk when an allocation happens (calculated free lists). The unused fragment after allocation will be put on the Freelists. To know where it can be placed, a “search“ needs to happen
- coalescing when freeing (calculated fre lists)
By making a series of allocations, frees, of specific sizes, you can get larger chunks to split into pieces. When you then reallocate the ones that end up on the FreeLists, you might still be able to control the contents of all chunks. By then playing with frees again, you can create holes in the heap layout, which is perfect to make sure your arbitrary object will be placed where you want it to be placed.
Example : Let’s say your vulnerable buffer is 64bytes and you want to place a Directory object behind it. The approach would be to allocate chunks of 808 bytes from 0x1000 byte pages. Next, allocate chunks of 4d8 bytes, so you would get holes of 320 bytes. By continue to use frees and allocs, you can create the necessary holes in the heap layout of a desired size.
Implementation in the Kernel Pool
In general, requests for allocations will be handled based on the size of the allocation.
The required primitives to use this technique are : We need to be able to allocate a buffer of an arbitrary size, we must be able to free a buffer of an arbitrary size, and do so using User Code. One possible solution is to use an Allocation Proxy and Free Proxy. Allocations could use the routine to create a symbolic link. To Free, you could use ExAllocatePoolWithTag(). When a FreeList search fails, allocations will come from a new page. 0x1000h in the ExAllocaePoolWithTag() function is hard code to make sure allocations are aligned by 0x1000. The search process uses a bitmap. if the search fails, the pool will be extended.
The picking sequence when splitting is interesting too, Eric explains. The first allocation comes from the start of a free empty page. Additional allocations will be taken from the end of the remaining part, effectively leaving a hole in the original chunk, which is perfect for future allocations.
To utilize a Windows object in a kernel exploit, we need to find some kind of function pointer and overwrite it. In Windows 7, the TypeIndex in an object header is a nice target. When you call CloseHandle() on that object, the pointer might get called. In Windows 8, you might be able to use a function pointer in the Timer object. Of course, you need to use the allocation/free primitives, based on FreeLists behaviour, to create the correct heap layout and place your vulnerable buffer + the desired object in the correct order.
The next challenge is to place the buffers at predictable addresses. The common technique in User Land is to use a heap spray.
Implementation in User Heap
In the User Heap, allocations depend on the size again. (Small/Medium/Large). Important values are 0x4000, 0x4000 – 0x7ffff and size > 0x7ffff. When an allocation is done, the LFH will be checked to see if it’s active for that size. If not, the back end allocator will be used. Eric explains that you might be able to attack non-protected metadata (_HEAP_USERDATA_HEADER), as documented by Chris Valasek. There are 2 challenges: If you allocate 18 chunks of a certain size, you’ll activate the LFH (which is what you need to avoid), and guard pages will be used, making overflows painful.
Eric explains that you could achieve defragmentation by using allocations of size 0x4000 – 0x7ffff, using the Back End Allocator and mandatory search. A Free 0x70100 + Allocate of 0x70000, could make a 0x1000 hole (by splitting the chunks). The size of UserBlocks (total size) is fixed. So if you then allocate UserBlocks of _HEAP_BUCKET for the desired size, you can allocate something into that hole.
The most important primitives you need to use this approach are: LFH should not be active yet for the desired sizes, so allocations would be taken from the backend allocator., Ability to allocate buffers of arbitrary size & free buffers of arbitrary size. Of course, after you gained control over EIP by using allocator primitives, you still need to figure out a way to get your shellcode to execute.
Exploit process:
- Figure out the vulnerability
- Heap Feng Shui
- Trigger overflow, modify FirstAllocationOffiset
- Allocate new objects with proper size
- Modify new object content
- Control EIP
Practical Heap determining in IE10.
Eric demonstrates the use of HTML5 and a 2D Canvas object to control the CRT heap (malloc) and cause adjacent allocations at higher addresses. You can then create holes to allocate the vulnerable buffer.
© 2013, Peter Van Eeckhoutte (corelanc0d3r). All rights reserved.