In association with heise online

Shell code

The code that is injected is often called shell code because in the first simple implementations the attacker prompts for input which is supplied via the Shell on the attacked system. How that works is a completely different topic, and we don't have space for it here. But we should mention a couple of generalities.

After a heap overflow, it rarely makes sense to leave the attacked application running. After all, the attacker has just manipulated the internal structure of the primary memory for data, the heap, and generally damaged it. The process would probably immediately produce an access violation and be terminated. Furthermore, the attacker should not be able to use his code on the heap any longer, but he still has API functions that the process is using anyway, and their addresses can be determined with the debugger.

The following shell code outputs a character string via printf() and terminates the processes cleanly:

Back: CALL SimpleHeap.printf
CALL SimpleHeap.exit
End: CALL Back
DB "***Hacked***"

The jump from the label End and the subsequent call to Back places the address of a string ***Hacked*** as a return address on the stack where printf() is waiting for it as an argument. Likewise, the push command moves the return value 0 for exit() onto the stack.

With this, the exploit is ready, and the prepared image file has the following contents:

00: 80 00 00 00 00 00 00 10 40 00 43 00 FF FF FF FF
10: FF FF FF FF FF FF FF FF 98 FD 12 00 50 00 43 00
20: FF FF FF FF 00 00 00 00 EB 0C E8 B9 24 FE FF 6A
30: 00 E8 E2 80 FE FF E8 EF FF FF FF (Insert a filler
40: character string here, terminated with 00)

The call to SimpleHeap.exe with the supposed image file causes the hidden code to be executed.

Exploit demo
Zoom The supposed image data uses a heap overflow in SimpleHeap.exe.

One could compile the program with the option /GS in Microsoft's compiler, which activates buffer overflow protection. This protective mechanism does not prevent the intentional overriding of a single address on the stack and is thus ineffective there. The only thing that could stop such an attack is DEP (data execution prevention).

Reality check

The approach discussed here is in principle also used for genuine exploits. However, the fixed addresses used here for simplicity's sake have one disadvantage: they have to be known in advance, and the exploit will not work if any of them are incorrect. So, the example exploit would fail if LocalAlloc() provides another area of memory for some reason or because special DLLs produce other stack addresses. In those cases, manual work would be required to adapt the addresses. The art of writing reliable exploits is a bit like writing error-free software. The only attack that is truly reliable and will work on any system is one that does not have to know any addresses on the target system.

The increasing number of exploits for weak spots in browsers often use heap overflows. In cases like the recently discovered "Windows Embedded Open Type Font Heap Overflow", creating a stable exploit is a work of art. Weak points that fall in the category known as "memory corruption," such as the recent query interface problem in the Firefox browser, are also vulnerable to such attacks. Usually, they differ in the way that data are copied into memory.

Finally, as a result of this increasing number of heap overflow exploits during the last few years, heap implementations have themselves matured significantly. Many systems now prevent simple exploits by means of additional tests. For example, they check to make sure that the pointers in the heap are consistent before they use them:

if ( this_block->prev-> next == this_block )

This check ensures that the previous block actually refers to the current one.

Other tests check whether a pointer even refers to a heap memory block at all by running through a list of all of the blocks. It is only used if the target of the pointer is found. With current CPUs, such safety measures do not significantly reduce performance.

But none of these measures can completely ensure that no buffer overflow will occur. If an attacker can overwrite a program's management data, the consequences will always be unpleasant. However, heap checks have pleasant side effects: they help reveal inconsistent data structures due to programming errors, and this provides for better, more stable software for customers. (ehe)

Felix "FX" Lindner runs SABRE Labs and specializes in professional security agency services and analysis.

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