Lab: Stack-Based Buffer Overflows
In this lab, you will be learning about buffer overflows in the stack, a common vulnerability in programs that allows you to run arbitrary code. This lab will require some programming in C, some knowledge of assembly, and a touch of debugging tools.
Late submissions will result in a 10% penalty per day (e.g., 2.5 days late result in 25% penalty)
1. Background
Stack-based buffer overflows have been around for a long time and all indications are that these and similar attacks will continue to be a problem in the near future. Aleph One wrote the definitive paper on using this technique to exploit programs, Smashing The Stack For Fun And Profit, and Paul Makowsky expanded on the protections that are now standard to allow Smashing the stack in 2011. You should read these papers carefully. They will walk you through every aspect of overflowing the buffer, creating a shellcode, current protections implemented in modern operating systems, and ultimately exploiting a vulnerable program. It is very long and full of technical detail -- make sure to set aside plenty of time to work through it.
Several strategies have been created to counter these types of bugs in programs. The version of Linux installed on your machine employs two different kernel-based stack protection mechanisms, and one hardware-flag. One kernel protection randomizes stack addresses to make it difficult to predict locations of shellcode. The other places random canary values on the stack to protect stored addresses. The hardware flag used (NX bit) sets memory regions as non-executable, triggering a signal and the termination of the program. You need to disable all of these mechanisms or else it will be difficult to exploit overflows on your system.
To disable stack protection, you will need to write a value in a special system file (as root or running a script with sudo). We have provided scripts that do this called
disable-stack-protection
and enable-stack-protection.
located inside the zip file referenced below. You should read these scripts to see how to enable and disable stack randomization. Note that if your system is ever rebooted, the
stack protections will be re-enabled by default.
To disable the placing of canary values in your executables, you need to use a gcc version that does not place canary values, or disable the functionality with the -fno-stack-protector
option. Again, we have automated this task during the compilation of the code you will be exploiting. Read the Makefile
shipped with the zip file below to see how to disable canary values.
2. Instructions
Log on to your linux machine, and obtain the files needed for this lab:
wget http://strawman/lab1/lab1.zip
and unzip them withunzip lab1.zip
-
You will find a directory
lab1/
which contains three files. The Makefile contains instructions to compile the C programsuppercase.c
andlowercase.c
. To compile the programs, simply typemake
inside thelab1/
directory. Make sure you don't compile the programs directly with gcc, as that will use gcc version 4 which inserts canary values by default. Examine both programs and discuss within your team what possible security issues exist with them. -
Now, focus on
uppercase.c
. This program takes a string in onargv[1]
and prints out the same string with all ASCII lowercase characters changed to uppercase. Think about what would happen if a user provided a string longer than 512 bytes. Now, try it out. Run the program with a first argument that is much longer than 512 bytes. -
Use
gdb
to run the program again with the same, very long, first argument (hint:set args AAAAAAA...
). When you run the program and it finishes, record the%eip
address reported when it segfaults. Compare this value to your string's ASCII hexadecimal representation (hint: man ascii). Now, repeatedly shorten/lengthen your string and re-runuppercase
ingdb
to determine the length of the shortest string needed to control%eip
. -
Set a breakpoint at
main()
and runuppercase
again with your shortest (but%eip
-controlling)argv[1]
. Once the breakpoint is reached, find the address ofuppercase
'sargv[1]
(hint: print&argv[1]
). -
Write a new program in C which exploits this stack-based buffer overflow to execute a shell. Your exploit should embed a shellcode in the
argv[1]
buffer ofuppercase
and then overwrite the stack frame return address so that execution continues within that buffer whenmain()
returns. Note: sincebuf
will get modified beforemain()
returns, you won't be able to jump into that buffer.
The shellcode you need to use is:
char scode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89" "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff" "\xff\xff/bin/sh";
-
Once you have a working exploit which executes a shell, make
uppercase
a setuid root program by runningchmod u+s uppercase
as root. Now, run your exploit again as a non-root user. Once your shellcode runs, use theid(1)
command to determine what user the shell is executed as. If everything works correctly, you'll have elevated privileges to root through this overflow. -
Now take a look at
lowercase.c
. Notice what happens toargv[1]
before it is copied intobuf
. If you try to exploit this overflow by placing your shellcode inargv[1]
, why won't it work? Think about other locations your shellcode could be stored instead ofargv[1]
. -
Write a new exploit for
lowercase
which does not embed the shellcode inbuf
orargv[1]
. Instead, just repeatedly fillargv[1]
with the address where your shellcode resides. There's at least two places inlowercase
's address space where you can stuff your shellcode.
Report
For this lab, your team must submit a report with the following information:
-
Submit all exploits with every line commented to demonstrate you understand how the exploits work.
-
Submit a diagram of the stack for
uppercase
which includes the stack frames formain()
andstrcpy()
and all local variables formain()
. Also, include the location ofmain()
's return address and how it gets overwritten by an overflownbuf
. Finally, includeargv[1]
in the diagram as well, relative to the stack frames. Exact offsets aren't that important here, but relative locations are. -
How would you modify
uppercase.c
andlowercase.c
to make them safe from buffer overflow attacks? Submit an answer to this question in the form a code diff of each program in the unified format. See the man page fordiff(1)
. Verify that your changes fixed the problem by running your exploits on the patched programs. -
If
buf
were instead allocated viamalloc(3)
in these vulnerable programs, would the same techniques for exploitation work? Why or why not? -
What is different about executing a setuid program versus a non-setuid program? What are the dangers of setuid programs? Why are setuid programs sometimes necessary?
-
Find an advisory for a remote overflow vulnerability published within the last year on the web which has an associated, published exploit. The exploit must be in the form of source code, and should be designed to execute code on the remote system (you do not need to test this). In what scenarios can the vulnerability you found be exploited? Include links and references to an advisory on the vulnerability, the exploit itself, and any related information you find.
Grading
Your grade for this lab will be composed of:
25% - The source code of the exploits with appropriate comments.
25% - The stack diagram.
20% - The fixes for the vulnerabilities in both programs.
30% - The rest of the questions.