Monday, July 11, 2011

Buffer Over Flow Attack

If you are reading this post then you definitely have some idea about computer programming and process, A computer program executes various processes and goes on balancing equations for which it has been created.

In the new era of programming we generally see that companies recruit only those programmers which are efficient in programming. Now a days its not a scenario that only the objective of your program is fulfilled. The Code Efficiency is also taken into account. Where Code Efficiency is determined on a series of situations (depending upon the objective of your program).

Buffer overflow attack is an example of exploiting the vulnerability of an inefficient programming. So we see a lot of inefficient programmers who are responsible for the server crashes.

To introduce buffer overflow to a newbie i would say that its a condition when a process or a program attempts to store data beyond the fixed-length temporary memory better known as buffer.

It is generally accepted that the best solution to buffer overflow attacks is to fix the defective programs. However, fixing defective program requires an indepth knowledge of programming.

A buffer is a contiguous allocated chunk of memory, such as an array or a pointer in C. In C and C++, there are no automatic bounds checking on the buffer, which means a user can write past a buffer.

For example:

int main () {
int buffer[10];
buffer[20] = 10;
}

The above C program is a valid program, and every compiler can compile it without any errors. However, the program attempts to write beyond the allocated memory for the buffer, which might result in unexpected behavior. Over the years, some bright people have used only this concept to create havoc in the computer industry. Before we understand how they did it, let’s first see what a process looks like in memory.

A process is a program in execution. An executable program on a disk contains a set of binary instructions to be executed by the processor; some read-only data, such as printf format strings; global and static data that lasts throughout the program execution; and a brk pointer that keeps track of the malloced memory. Function local variables are automatic variables created on the stack whenever functions execute, and they are cleaned up as the function terminates.( you can read about the “process” in depth from WIKI I am not going too much in detail about this)

In memory layout of a Linux process.

A process starts with the program’s code and data. Code and data consists of the program’s instructions and the initialized and uninitialized static and global data, respectively. After that is the run-time heap (created using malloc/calloc), and then at the top is the users stack. This stack is used whenever a function call is made.



image credits to Linux Journal)

Another Example to Illustrate this.

void function (char *str) {
char buffer[16];
strcpy (buffer, str);
}
int main () {
char *str = “Hi My name is saurabh tiwari”; // length of str = 29 bytes
function (str);
}

This program is guaranteed to cause unexpected behavior, because a string (str) of 29 bytes has been copied to a location (buffer) that has been allocated for only 16 bytes. The extra bytes run past the buffer and overwrites the space allocated for the FP(FP is functions return address), return address and so on. This, in turn, corrupts the process stack. The function used to copy the string is strcpy, which completes no checking of bounds. Using strncpy would have prevented this corruption of the stack. However, this classic example shows that a buffer overflow can overwrite a function’s return address, which in turn can alter the program’s execution path. Recall that a function’s return address is the address of the next instruction in memory, which is executed immediately after the function returns.

How to implement the above example – (source- Sandeep Grover)

Because we know it is easy to overwrite a function’s return address, an intelligent hacker might want to spawn a shell (with root permissions) by jumping the execution path to such code. But, what if there is no such code in the program to be exploited? The answer is to place the code we are trying to execute in the buffer’s overflowing area. We then overwrite the return address so it points back to the buffer and executes the intended code. Such code can be inserted into the program using environment variables or program input parameters.

I will be covering the shell program on the implementation of Buffer overflow attack in my next post.

Till then happy hacking.

No comments: