Check out the new USENIX Web site. next up previous
Next: StackGuard: Making the Stack Up: StackGuard: Automatic Adaptive Detection Previous: Introduction

Buffer Overflow Attacks

 

Buffer overflow attacks exploit a lack of bounds checking on the size of input being stored in a buffer array. By writing data past the end of an allocated array, the attacker can make arbitrary changes to program state stored adjacent to the array. By far, the most common data structure to corrupt in this fashion is the stack, called a ``stack smashing attack,'' which we briefly describe here, and is described at length elsewhere [15, 17, 21].

Many C programs have buffer overflow vulnerabilities, both because the C language lacks array bounds checking, and because the culture of C programmers encourages a performance-oriented style that avoids error checking where possible [14, 13]. For instance, many of the standard C library functions such as gets and strcpy do not do bounds checking by default.

   figure38
Figure 1: Stack Smashing Buffer Overflow Attack

The common form of buffer overflow exploitation is to attack buffers allocated on the stack. Stack smashing attacks strive to achieve two mutually dependent goals, illustrated in Figure 1:

Inject Attack Code
The attacker provides an input string that is actually executable, binary code native to the machine being attacked. Typically this code is simple, and does something similar to exec("sh") to produce a root shell.
Change the Return Address
There is a stack frame for a currently active function above the buffer being attacked on the stack. The buffer overflow changes the return address to point to the attack code. When the function returns, instead of jumping back to where it was called from, it jumps to the attack code.

The programs that are attacked using this technique are usually privileged daemons; programs that run under the user-ID of root to perform some service. The injected attack code is usually a short sequence of instructions that spawns a shell, also under the user-ID of root. The effect is to give the attacker a shell with root's privileges.

If the input to the program is provided from a locally running process, then this class of vulnerability may allow any user with a local account to become root. More distressing, if the program input comes from a network connection, this class of vulnerability may allow any user anywhere on the network the ability to become root on the local host. Thus while new instances of this class of attack are not intellectually interesting, they are none the less critical to practical system security.

Engineering such an attack from scratch is non-trivial. Often, the attacks are based on reverse-engineering the attacked program, so as to determine the exact offset from the buffer to the return address in the stack frame, and the offset from the return address to the injected attack code. However, it is possible to soften these exacting requirements [17]:

The cook-book descriptions of stack smashing attacks [15, 17, 21] have made construction of buffer-overflow exploits quite easy. The only remaining work for a would-be attacker to do is to find a poorly protected buffer in a privileged program, and construct an exploit. Hundreds of such exploits have been reported in recent years [4].


next up previous
Next: StackGuard: Making the Stack Up: StackGuard: Automatic Adaptive Detection Previous: Introduction

Crispin Cowan
Tue Dec 9 16:04:30 PST 1997