In association with heise online

Faking headers

One question remains unsolved: how can attackers inject their code and have it executed? Even in our simplified example, the answer to this question depends on a number of factors. Every operating system sets aside different areas of memory that a program would like to use as a heap. Operating systems also have multiple ways of requesting a block of memory from the kernel, each of which can also potentially be used for an attack.

In our specific example, Windows NT is the operating system, and it reserves a memory block for SimpleHeap via the function LocalAlloc(). It creates SimpleHeap at the next address that can be divided by 0x10000 after the code and the static data of the main program in memory. Among other things, the exact address depends on the compiler's settings when translating the program; these settings influence the size of the main program and hence the next available address. Here, it once again becomes clear why attackers prefer stack-based buffer overflows so much: there are far fewer unknown parameters.

On our test system, the memory area for SimpleHeap is at the address 0x00430020 for a debug build of the program. The 32-byte offset to the value divisible by 0x10000 is management information that is here returned by LocalAlloc().

The pointers myRoot and myHeap thus refer to the address 0x00430020. Since the attack overwrites the SimpleHeap block header for line, we should take a closer look at this memory area just before this fatal copy event takes place. The memory block image that the program allocated first is at the address 0x00430020. The field size correctly indicates the reserved size of zero bytes. The first four bytes (next) refers to the header of the next block (line) at address 0x00430030.

memory layout before copying
Zoom The memory block before the fatal copying process; immediately following the empty block <tt>image</tt> is <tt>line</tt>.

When the program copies the first line of the image file from the buffer line to image, it overwrites the data starting at 0x00430030. hdr->next->used has to have the value 0 so that free blocks will be merged the next time that SimpleHeap_free(line) is called. In addition, hdr->next->prev needs to contain a suitable value for an attack. In other words, attackers have to place what experts call a "fake header" at the address hdr->next. To do so, they first have hdr->next point to an area that they control: the image data at the address 0x00430040.

fake header
The exploit puts its fake header in.

Copying data from the "line" to "image"

The content of the other fields hdr->prev, hdr->size, and hdr->used is not important; these fields are not accessed. But things get interesting again starting at offset 16 of the image data, where hdr->next points to address 0x00430040. The fake header placed there has to indicate an unuse block (hdr->next->used == 0), which means that there must be a value 0 at offset 16+12 of the image data.

The program then executes the critical command:


This write operation uses the value of the prev field in the fake header, which is 0x00430050 the address of the code implanted in the image file. The program calculates the target address hdr->next->next->prev from the value at hdr->next->next plus an offset of 4 for the prev elements. This simple example exploit should overwrite the return address on the stack for the call of SimpleHeap_free(). The debugger locates it at the address 0x0012FD9C. Hence, hdr->next->next has to contain the address 0x0012FD98.

Now, the content of the fake header is set -- and so is the content of the image data:

0x0043040 address of the fake header (hdr->next)
12 bytes, random
0x0012FD98 target address minus 4 (hdr->next->next)
0x00430050 target value (hdr->next->prev)
4 bytes, random (hdr->next->size)
0x00000000 hdr->next->used

When the CPU processes SimpleHeap_free(line), this results in the following SimpleHeap memory layout:

memory after copying
Zoom The buffer overflow has prepared the memory for the fatal call of <tt>SimpleHeap_free ()</tt>.

Merging the free blocks places the desired address on the stack and the return instruction at the end of SimpleHeap_free() uses it as the address to jump to. The CPU then executes the injected code, and the attack has been successful.

The attacker could have overwritten other memory addresses instead of the return address on the stack. Addresses for exception handlers on the stack or in the data segment are especially popular. The resulting exploit is then called an SEH exploit (Structured Exception Handler). In addition, other pointers to functions in the data segment or addresses of functions which the operating system stores for the process context, are also used in practice.

Incidentally, directly changing the program code itself is not advisable as the respective memory areas are generally marked as "read only," and write access would terminate the process.

Print Version | Permalink:
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit

  • July's Community Calendar

The H Open

The H Security

The H Developer

The H Internet Toolkit