Tuesday, May 17, 2005

Defeating Microsoft Windows XP SP2 Heap protection and DEP bypass

Author: Alexander Anisimov

Heap Overflow 
Let`s take a look at this pretty simple example of a vulnerable function:

As we can see here the vulner() function copies data from a string pointed by str to an allocated memory block pointed at by buf, without a bound check. 

A string larger than 127 bytes passed to it will thereby overwrite the data coincidental to this memory block (Which is, actually, a header of the following memory block).
The heap overflow exploitation scenario usually proceeds on like this:
If during the buffer overflow the neighboring block exists, and is free, then the Flink and 
Blink pointers are replaced (Fig. 5). 

At the precise moment of the removal of this free block from the doubly-linked freelist a 
write to an arbitrary memory location happens: 
For example, the Blink pointer could be replaced by the unhandled exception filter address 
(UEF -- UnhandledExceptionFilter), and Flink, accordingly, by the address of the instruction
which will transfer ther execution to the shellcode.

[*] More detailed information about the heap overflows is provided in the “Windows Heap 
Overflows” whitepaper (by David Litchfield, BlackHat 2004).

Fig. 1

In Windows XP SP2 the allocation algorithm was changed -- now before the removal of a 
free block from the freelist, a pointer sanity check is performed with regard to the previous 
and next block addresses (safe unlinking, fig. 2.):

Fig. 2

Then that block gets deleted from the list. 

The memory header block was changed, besides other things (fig. 7.). A new one-bytelarge 'cookie' field was introduced, which holds a unique precomputed token -- undoubtely designed to ensure header consistency. 

This value is calculated from the header address and a pseudorandom number generated 
during the heap creation: 

The consistency of this token is checked only during the allocation of a free memory block 
and only after its deletion from the free list.

If at least one of these checks fails the heap is considered destroyed and an exception 

The first weak spot -- the fact that the cookie gets checked at all only during free block allocation and hence there is no checks upon block freeing. However in this situation there is nothing you can do except changing the block size and place it into an arbitrary freelist.

And the second weak spot – the manipulation of the lookaside lists doesn`t assume any 
header sanity checking, there isn`t even a simple cookie check there. 

Which, theoretically, results in possibility to overwrite up to 1016 bytes in an arbitrary 
memory location. 

The exploitation scenario could proceed as follows: 
if, during the overflow the concidental memory block is free and is residing in the lookaside list, then it becomes possible to replace the Flink pointer with an arbitrary value.

Then, if the memory allocation of this block happens, the replaced Flink pointer will be copied into the header of the lookaside list and during the next allocation HeapAlloc() will return this fake pointer.

The prerequisite for successful exploitation is existence of a free block in lookaside list which
neighbors with the buffer we overflow. 

This technique was successfully tested by MaxPatrol team in trying to exploit the heap buffer overflow vulnerability in the Microsoft Windows winhlp32.exe application using the advisory published by the xfocus team: 

The effect of a successful attack: 
  1. Arbitrary memory region write access (smaller or equal to 1016 bytes). 
  2. Arbitrary code execution (appendix A). 
  3. DEP bypass. (DEP is Data Execution Prevention) (appendix B).
Full article: