This lecture is a continuation of the previous one and describes the Buffer Overflow Attacks in detail. It also mentions the Goals and the 2 Tricks which could be useful in making this attack successful. Certain things to keep in mind during this attack.
BUFFER OVERFLOW ATTACK
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.
Many C programs have buffer overflow vulnerabilities, both because the C language lacks array bounds checking (reason being the use of Pointers, Typecasting, ………), and because the culture of C programmers encourages a performance-oriented style that avoids error checking where possible. For instance, many of the standard C library functions such as gets and strcpy do not do bounds checking by default. We will use the same "gets" example program given in the last lecture.
char *gets(char *s); (transfer ends on EOF or newline)
"gets" doesn’t know how big the array is. It will keep on transferring. Buffer will grow up. After exceeding the array the attacker will be entering the characters past the upper bound of the buffer.
GOALS TO ACHIEVE
The common form of buffer overflow exploitation is to attack buffers allocated on the stack. The attacker strives to achieve two mutually dependent goals.
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.
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. Note that at frame boundaries we have return addresses and we don’t know where this boundary is.
int main (int argc, char **argv, char **envp), we don’t know how many characters are there in envp.
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.
TRICKS TO ACHIEVE THE GOALS
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 :
a). The location of the return address can be approximated by simply repeating the desired return address several times in the approximate region of the return address.
b). The offset to the attack code can be approximated by prepending the attack code with an arbitrary number of NOP instructions. The overwritten return address need only jump into the middle of the field of NOPs to hit the target.
THINGS TO KEEP IN MIND
The attacker needs to view the program from 2 points:
a). What are the main intentions ?
b) How the machine level coding is going to look like ? (The attacker wants to avoid the newline(\n), as "gets" will return).
A lot of literature on such attacks 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.