Due: Tuesday, September 30 at 23:59.
The goal of this assignment is to gain hands-on experience with the effect of buffer overflows and other memory-safety bugs.
All work in this project must be done in the QEMU virtual machine provided on the course website; see below for information about this environment.
You are given, in the targets
directory, the source code for five exploitable programs, target1
, …, target5
. These programs are to be compiled and installed, setuid root, in the /tmp
directory of your VM. Your goal is to write five exploit programs sploit1
, …, sploit5
, each of which will execute the corresponding target with input that exploits that target's bug, giving a root shell on the VM.
We have provided skeletons for these exploits programs in the sploits
directory, as sploit1.c
, …, sploit5.c
. Our own solutions, incidentally, are very short: fewer than 50 lines each. So while understanding and exploiting the bugs will not be easy, you will not need to write a lot of code.
You may work on this project in collaboration with a single partner as described on the main page.
You must not discuss the project with anyone other than your partner and course staff. You may use online resources for general reference, but not to search for solutions to specific questions posed in this project.
You (and we, for grading) will test your exploit programs within a QEMU ARM virtual machine. This virtual machine emulates an ARM processor.
There are two options for running this virtual machine.
You can install QEMU on your computer.
You can run QEMU from inside the sandbox virtual machine from project 0.
In either case, you will need to download and decompress qemu-arm.tar.bz2. The ARM VM can be started by running the start-arm.sh
inside the qemu-arm
directory. You can log in to the user account using the username/password armuser/armuser. In addition to giving you “console” access to the emulated ARM machine, the start-arm.sh script forwards local port 2200 to port 22 (the ssh port) in the VM. Thus, from a Linux or OS X machine, you can ssh to the ARM VM using
$ ssh -larmuser -p 2200 localhost
You can put the following lines in your local machine's $HOME/.ssh/config
to provide easy ssh access:
Host = armguest HostName = localhost Port = 2200 User = armuser
You can then use the following to log in.
$ ssh armguest
If you are running the QEMU VM inside the VirtualBox VM, then the following line in your $HOME/.ssh/config
works.
Host = sandbox HostName = localhost Port = 2222 User = user Host = armguest ProxyCommand = ssh -q sandbox localhost 2200
The VM has Ubuntu installed as well as a number of useful utilities such as vim, ssh, and wget, and several hex editors such as dhex
.
Once you have the QEMU VM installed, launch it, log in, and download and decompress the assignment tarball.
$ wget https://www.cs.jhu.edu/~s/teaching/cs460/2014-fall/project1.tar.gz $ tar zxf project1.tar.gz
The targets
directory in the assignment tarball contains the source code for the targets along with a Makefile
specifying how they are to be built. To compile the targets and install them setuid root in /tmp
, use the commands make
and make install
.
target5
is fairly complicated. It reads commands for manipulating strings from the file specified as its argument. Due to the way target5
is compiled, the glibc malloc
/free
/realloc
functions are not used. Instead, the replacement functions in smalloc.c
are called. It is easiest to set a breakpoint in smalloc
/sfree
/srealloc
rather than trying to step into calls to malloc
.
The sploits
directory in the assignment tarball contains skeleton source for the exploits which you are to write, along with a Makefile
for building them. Also included is shellcode.h
, which contains shellcode for you to use.
Your exploits should assume that the compiled target programs are installed in /tmp
— /tmp/target1
, …, /tmp/target5
.
Along with each exploit skeleton file, there is an empty text file that you should fill with an explanation of the bug in the corresponding target and how your exploit takes advantage of it. You will submit this explanation along with your exploit.
You are to write exploits, one per target. Each exploit, when run in the virtual machine with its target installed setuid-root in /tmp
, should yield a root shell (/bin/sh
).
Read Aleph One's “Smashing the Stack for Fun and Profit,” carefully! Also, read the “suggested reading” listed in the project README
. You will want to have a good understanding of what happens to the stack, program counter, and relevant registers before and after a function call. Read scut's “Exploiting Format String Vulnerabilities.” It will be helpful to have a solid understanding of the basic buffer overflow exploits before reading the more advanced exploit papers.
The gdb
debugger is your best friend in this assignment as you'll want to understand what's going on in the target program's memory space. Specifically, note the disassemble
and stepi
commands. You may find the x
command useful to examine memory (and the different ways you can print the contents such as /a
or /i
after x
). The info register
command is helpful for printing out the contents of registers.
A useful way to run gdb
is to use the -e
and -s
command line flags; for example, the command gdb -e ./sploit3 -s /tmp/target3
tells gdb
to execute sploit3
and use the symbols from target3
which allows you to trace execution in the target in exactly the way it is executed by the exploit. By contrast, executing just gdb /tmp/target3
will trace the target in the way it is executed by the shell, so the memory layout will be different. (Avoiding a segfault while using this requires careful timing in setting breakpoints. See the assignment README
for the details.)
One of the projects is very constrained in what arguments can be passed to it and you may have trouble running code on the heap (i.e., memory allocated by malloc
). Try placing the shellcode somewhere else.
Make sure that your exploits work within the provided virtual machine.
Start early! Theoretical knowledge of exploits does not readily translate into the ability to write working exploits. The first target is relatively simple to exploit, but the difficulty ramps up from there.
Aleph One gives code that calculates addresses on the target's stack based on addresses on the exploit's stack. Addresses on the exploit's stack can be changed based on how the exploit is executed (working directory, arguments, environment, etc.); in our testing, we do not guarantee to execute your exploits the same way bash
does.
You must, therefore, hard-code target stack locations in your exploits. You should not use a function such as get_sp
in the exploits you hand in.
You will need to submit the source code for your exploits, along with any files (Makefile, shellcode.h) necessary for building them. Make sure that all of your exploits compile with a single make
command!
In addition, along with each exploit, you should include a text file (sploit1.txt, sploit2.txt, and so on). In this text file, explain how your exploit works: what the bug is in the corresponding target, how you exploit it, and where the various constants in your exploit come from.
Finally, you must include a file called ID
which contains the names of all partners (or just your own if you worked by yourself).
Create a single tarball containing your sploits directory and turn that in on blackboard. The easiest way to do that is
$ cd project1/sploits $ make clean $ cd .. $ tar zcf sploits.tar.gz sploits