Buffer overflow attack

Last revision (mm/dd/yy): //

Description
Buffer overflow errors are characterized by the overwriting of these memory fragments of the proccess, which should have never been modified intentionally or unintentionally. Overwriting values of the IP (Instruction Pointer), BP (Base Pointer) and other registers causes exceptions, segmentation faults, and other errors to occur. Usually these errors end execution of the application in an unexpected way. Buffer overflow errors occur when we operate on buffers of char type.

BO (common name for this kind of errors) is simply a stack or heap overflow. We don't distinguish beetwen these two in this article to avoid reader's confusion. Details about using stack and heap overflow techniques can be found in the separate articles.

Below examples are written in C language under GNU/Linux system on x86 architecture.

Example 1
#include  int main(int argc, char **argv) { char buf[8]; // buffer for eight characters gets(buf); // read from stdio (sensitive function!) printf("%s\n", buf); // print out data stored in buf return 0; // 0 as return value } This very simple application reads from the standard input an array of the characters and copies it into the buffer of the char type. The size of this buffer is eight characters. After that the content of the buffer is displayed and application exits.

Program compilation: rezos@spin ~/inzynieria $ gcc bo-simple.c -o bo-simple /tmp/ccECXQAX.o: In function `main': bo-simple.c:(.text+0x17): warning: the `gets' function is dangerous and should not be used. At this stage even compiler suggests us that the used function gets doesn't belong to the safe ones.

Usage example: rezos@spin ~/inzynieria $ ./bo-simple // program start 1234 // we eneter "1234" string from the keyboard 1234 // program prints out the conent of the buffer rezos@spin ~/inzynieria $ ./bo-simple // start 123456789012 // we eneter "123456789012" 123456789012 // content of the buffer "buf" ?!?! Segmentation fault // information about memory segmenatation fault Definitely we manage (un)luckily to execute faulty operation by the program and provoke it to exit abnormally.

Problem analysis:

The program calls a function, which operate on char type buffer and does no checks against overflowing the size assigned to this buffer. As an aftermath it is possible to intentionally or unintentionally store more data in the buffer what will cause an error. The following question arises: The buffer stores only eight characters, so why function printf displayed twelve?. The anserw come off the process memory organisation. Four characters which overflowed the buffer also overwrite the value stored in one of the registers, which was necessary for the correct function return. Memory continuity resulted in printing out the data stored in this memory area.

Example 2
#include  #include 

void doit(void) {         char buf[8];

gets(buf); printf("%s\n", buf); }

int main(void) {         printf("So... The End...\n"); doit; printf("or... maybe not?\n");

return 0; } This example is analogous to the first one. In addition before and after doit function we have two calls to function printf. Compilation:

rezos@dojo-labs ~/owasp/buffer_overflow $ gcc example02.c -o example02 -ggdb /tmp/cccbMjcN.o: In function `doit': /home/rezos/owasp/buffer_overflow/example02.c:8: warning: the `gets' function is dangerous and should not be used.

Usage example: rezos@dojo-labs ~/owasp/buffer_overflow $ ./example02 So... The End... TEST                  // user data on input TEST                 // print out stored user data or... maybe not? Program between two defined printf calls displays content of the buffer, which is filled with data entered by the user. rezos@dojo-labs ~/owasp/buffer_overflow $ ./example02 So... The End... TEST123456789 TEST123456789 Segmentation fault Because of defined size of the buffer (char buf[8]) and filling it with thirteen characters of char type, the buffer was overflowed.

If our binary application is in ELF format, then we are able to use an objdump program to analise it and find necessery information to exploit buffer overflow error.

Below is an output produced by the objdump. From that output we are able to find addresses, where printf is called (0x80483d6 and 0x80483e7). rezos@dojo-labs ~/owasp/buffer_overflow $ objdump -d ./example02

080483be : 80483be:      8d 4c 24 04             lea    0x4(%esp),%ecx 80483c2:      83 e4 f0                and    $0xfffffff0,%esp 80483c5:      ff 71 fc                pushl  0xfffffffc(%ecx) 80483c8:      55                      push   %ebp 80483c9:      89 e5                   mov    %esp,%ebp 80483cb:      51                      push   %ecx 80483cc:      83 ec 04                sub    $0x4,%esp 80483cf:      c7 04 24 bc 84 04 08    movl   $0x80484bc,(%esp) 80483d6:      e8 f5 fe ff ff          call   80482d0  80483db:      e8 c0 ff ff ff          call   80483a0 80483e0:      c7 04 24 cd 84 04 08    movl   $0x80484cd,(%esp) 80483e7:      e8 e4 fe ff ff          call   80482d0  80483ec:      b8 00 00 00 00          mov    $0x0,%eax 80483f1:      83 c4 04                add    $0x4,%esp 80483f4:      59                      pop    %ecx 80483f5:      5d                      pop    %ebp 80483f6:      8d 61 fc                lea    0xfffffffc(%ecx),%esp 80483f9:      c3                      ret 80483fa:      90                      nop 80483fb:      90                      nop If the second call to printf would inform administrator about user logout (e.g. closed session), then we can try to omit this step and finish without call to printf. rezos@dojo-labs ~/owasp/buffer_overflow $ perl -e 'print "A"x12 ."\xf9\x83\x04\x08"' | ./example02 So... The End... AAAAAAAAAAAAu*. Segmentation fault Application finished its execution with segmentation fault but the second call to printf had no place.

A few words of explanation:

perl -e 'print "A"x12 ."\xf9\x83\x04\x08"' - will print out twelve "A" characters and then four characters, which are in fact an address of the instruction we want to execute. Why twelve? 8 // size of buf (char buf[8]) + 4 // four additional bytes for overwriting stack frame pointer 12 Problem analysis:

The issue is the same as in the first example. There is no control over the size of the copied buffer into the previously declared one. In this example we overwrite EIP register with address 0x080483f9, which is in fact call to ret in the last phase of the program execution.

How to use buffer overflow errors in a different way?

Generally explotation of these errors may lead to:
 * application DoS
 * reordering execution of functions
 * code execution (if we are able to inject the shellcode - described in the separate document)

How buffer overflow errors are made?

This kind of errors are very easy to make. For years they were programmer's nightmare. The problem lies in native C functions, which don't care about doing appropriate buffers length checks. Below is the list of such functions and if exists, their safe equivalents:


 * gets -> fgets - read characters
 * strcpy -> strncpy - copy content of the buffer
 * strcat -> strncat - buffers concatation
 * sprintf -> snprintf - fill buffer with data of different types
 * (f)scanf - read from STDIN
 * getwd - return working directory
 * realpath - return absolut (full) path

Related Threat Agents

 * Category:Command Execution
 * Off-by-one

Related Attacks

 * Stack overflow attack
 * Heap overflow attack
 * Format string attack

Related Vulnerabilities

 * Format string
 * Heap overflow

Related Controls

 * Use safe equivalent functions, which check the buffers length, whenever it's possible.

Namely:
 * 1) gets -> fgets
 * 2) strcpy -> strncpy
 * 3) strcat -> strncat
 * 4) sprintf -> snprintf

with safe checks implemented. Time spent on that will benefit in the future. Remember that you have to do it only once.
 * These functions which doesn't have their safe equivalents should be rewritten

check if the memory is overwritten when and where it shouldn't be.
 * Use compilers, which are able to identify unsafe functions, logic errors and