Stack Smashing and Heap Overflow

Objectives:

The purpose of this lab is to learn about stack smashing and heap overflow attacks. You should understand exactly how they work and various approaches to preventing them. In addition, you will gain hands-on experience with the following:

  1. Using a debugger
  2. Analyzing user stack processing during function calls
  3. Understanding assembly code
  4. Using a stack-protecting compiler

You have probably learned about buffer overflows in earlier classes (like CS 324). Feel free to use other textbooks or references you may have. You should have already read the assigned paper that discusses StackGuard, and other approaches to preventing buffer overflow attacks. Here are two classic non-traditional papers that are worth reading:
Smashing The Stack For Fun And Profit
w00w00 on Heap Overflows

For this lab you will need to download the tar file of code. To receive credit for completing this lab, you only need to turn in a written deliverable with your answers to the questions asked throughout the lab. To receive full credit, you must express your answer clearly; consider this an opportunity to demonstrate your writing skills.  No pass-off with the TAs is required.

Part 1: Decoding the Stack

The program that we will be exploiting is "vulnerable.c" in the tar ball. A make file is provided in the tar ball. The program accepts a character string as an input parameter and echoes that value to the screen. The program has a bug. You will need to use a debugger and analyze the program. Both GDB and DDD are available in the labs. If you are not familiar with debuggers, read these quick introductions:
GDB
DDD

Here are some helpful links to browse over to refresh your memory about the structure of processes in memory:
Function Call Conventions
Procedure Stack Frames
Layout of Heap in relation to Stack

Complete the following 3 items:

  1. Type the command "gcc -v" and record what version of GCC you are using. Ex. "gcc version 1.1.2 230434212 (Red Hat Linux 3.3.3-7)"
  2. After compiling vulnerable.c, run the program in a debugger and pass in a short string like "test" as the only parameter. View and analyze the contents of the user stack during the function call to "vulnerable":
    1. What is the value of the stack pointer ($esp) and base pointer ($ebp) at the exact moment that dummy1 is set to 7 in the main routine?
    2. What is the value of the stack pointer and the base pointer at the exact moment that dummy2 is set to 10 in the function "vulnerable"?
    3. Using the two stack pointer ($esp) values as bounds, neatly draw (or type out) the contents of the user stack generated for handling the function call and precisely identify as many items on the stack as possible.
  3. Try running the program once by supplying an input argument string of length five, such as "cs465". Repeatedly run the program and increase the size of the string by one during each invocation (i.e., cs465a, cs465ab, cs465abc, . . .) until the program crashes.
    1. What is the length of the shortest input string that results in a program crash? (number of characters you typed)
    2. On what line of source code did the program crash? (use the debugger)
    3. Explain precisely why the program crashed. Your answer will be graded on detail and clarity.

Part 2: Alter Program Execution Flow

Notice that the "exploited" function in "vulnerable" is never invoked. In this section, you will cause the "exploited" function to be executed using a carefully constructed input string to "vulnerable."

The program "wrap" will help you build a string to overflow the buffer "buf" in the "vulnerable" function in the "vulnerable" program. "wrap" executes "vulnerable" itself so you don't need to copy and paste. Use the debugger to find the following about "vulnerable:"

  1. The distance in bytes from the end of the buffer to the return address on the stack.
  2. The address of the "exploited" function

"wrap" takes the distance in bytes from the end of the buffer to the return address and the address of the exploited function and produces a string that will overflow "buf" and cause the program to execute "exploited."

Once you have successfully caused "vulnerable" to execute "exploited," do the following:

  1. Explain what each section of code in "wrap.c" labeled "Section X," where X is a number, does.
  2. Diagram the string that wrap creates with the data you give it.
  3. Is the ability to just alter program flow a security problem? Why?

Part 3: Heap Overflow: A Simple Example

This part is an introduction to heap overflows. Compile the program "simple_heap_overflow.c" (a make file is provide). Run the program at the command prompt. Open up the file "simple_heap_overflow.c" and think about what is happening. Answer the following questions:

  1. What is a heap overflow?
  2. How does this program demonstrate a heap overflow?
  3. Why doesn't the program crash?

Part 4: Heap Overflow: Getting a Shell

In this part, we will work with the files "vulnerable_heap.c" and "exploit_heap.c". Vulnerable_heap is a program that takes two character strings as arguments. The first gets stored in a buffer and the second is passed to the function "goodfunc" in "vulnerable_heap" as an argument.

See how "vulnerable_heap" works by looking at the source code and by running it. (Ex. "./vulnerable_heap blah test")

"exploit_heap" is a program that takes one argument--an integer. Run the program "exploit_heap" and try passing in different numbers (start with 70 and go up to 100) until you get a shell.

  1. How does the attack work? (i.e. What does the exploit_heap program do and why?)

Part 5: Stack Protection

We have compiled a version of GCC with stack protection using IBM's Propolice (based on StackGuard). To use our version of GCC, copy and paste the following at the command prompt:

PATH=/users/ta/cs465ta/gcc_path/bin:$PATH

Now, type "gcc -v" and check to make sure you are using gcc version 3.4.1. You should see the following:

[user]$ gcc -v
Reading specs from /users/user2/ta/cs465ta/gcc_path/bin/../lib/gcc/i686-pc-linux-gnu/3.4.1/specs
Configured with: ../configure --prefix=/users/ta/cs465ta/gcc_path --enable-stack-protector
Thread model: posix
gcc version 3.4.1

Recompile the vulnerable programs in this lab with the new compiler and run each of the corresponding exploits again (parts 1-4). This doesn't mean to answer all the questions again--just see if each exploit still works. Remember to first type "make clean" to remove all the files previously compiled, before you type "make" to recompile with the new version of GCC.

  1. For each vulnerable program describe what happened with each corresponding exploit.
  2. Describe two ways that Propolice protects the stack (see their website).
  3. If some of the exploits still work, explain why they work even though Propolice is being used.

Conclusion and Pass Off

To pass off the lab:

  1. Turn in answers your answers to all the questions in parts 1-5.
  2. Also, turn in the answers to the additional questions presented below:

Additional Questions:

  1. In parts 4 when you executed shell code, did you really compromise the security of the system you are working on? If not, under what circumstances does a buffer overflow/heap overflow attack result in a security violation?
  2. How many hours did you spend on lab 7?
  3. What did you like about lab 7?
  4. What did you dislike about lab 7?