Explioit and Patch
Objectives
In this project, you will gain experience recognizing TOCTOU race conditions, integer-based vulnerabilities, and buffer overflows. You will also get your first taste of exploiting vulnerabilities. Finally, you will practice writing patches for the vulnerabilities you identify.
Requirements
In this project you will be looking for vulnerabilities in seven simple programs, exploiting those vulnerabilities, and writing patches to fix those vulnerabilities. These vulnerabilities will cover the types of vulnerabilities discussed in class:
- TOCTOU race conditions
- Integer-based vulnerabilities
- Buffer overflows
To start, download and unzip the handout.
This directory has seven binaries you will need to exploit, labeled
problem{1-7}
. For this project, I have turned off various protections to allow
exploits to work. For example, the binaries will not use a stack canary or ASLR.
Along with the binaries, I have also provided a problem#.c
file. This is the
file is very similar to the file from which the binary was compiled. However,
this file has had any secret information removed.
If you wish to compile the code files, use make binaries
. This will build
binaries in the ./out/
directory to avoid erasing the binaries in the
workspace directory. Do not compile any other way as this may result in deleting
the binaries in the workspace directory, which are necessary to complete the
project.
Open a Dev Container
Type F1
to open the command pallette. Run the following command:
Dev Containers: Open Folder in Container
. You need to run this assignment in a
container since we are exploiting vulnerabilities and have turned off various
protections.
Identifying Vulnerabilities
Each program has a single vulnerability you will need to identify. This
vulnerability will result in the execution of the void flag()
function, which
would otherwise not be called. You should identify this vulnerability by looking
at the source code for the program. You do not need to and should not
examine the binary itself. This will waste your time and cause the project to
take much longer than intended.
Exploiting the Vulnerability
Next, you will need to determine what input you need to provide to the program
to exploit the program’s vulnerability. On a successful exploit, the flag will
be printed out by the program. Flags are in the format flag{366-fL4G-H3r3}
.
Remember, you can pipe input to the program from a file using
./program << program.input
. This can be helpful as you are fine tuning your
exploit so you don’t have to hand enter strings. Alternatively, you can use this
command:
You can then substitute what you need for hello
.
Problem 5 is different than the others, in that you do not provide the program input over standard input, but instead exploit it using a bash script. This script should run the problem binary, conduct the steps necessary to exploit it, and allow the flag to be printed out. In particular, you may this helpful:
This will get the process ID of the process most recently put into the
background. You may also find sleep
, kill
, and touch
helpful.
Patching the vulnerability
Finally, you will write a patch to correct the vulnerability. You will do so by
editing the problem#.c
file for each problem. In most cases, these patches
will be very simple and will involve modifying one or two lines. Make sure that
your patch doesn’t create new vulnerabilities. Note, a valid patch fixes the
vulnerability and nothing else. It does not just remove the call to
void flag()
or removes any intended functionality.
To compile and check that your code is correct, you can use make all
. To
generate a diff file for your patch (how patches are applied) use the
make diff
command. You can then find your diffs in ./diff/
.
Critical Sections and Mutexes
In one of the problems you will encounter errors due to a race condition between multiple threads. These types of problems occur because you can’t predict the speed with which threads will execute and therefore when a shared resource will be accessed. The section of code that accesses a shared variable (and thus may be vulnerable to a race condition) is called a critical section.
To fix a multi-threaded race condition, you need to ensure that only one thread is in the critical section at a time. One way to do this is to use a mutex or lock. In Python, this looks like:
In C#, you can use
this library.
You can lock a mutex with WaitOne()
and unlock it with ReleaseMutex()
.
Writeup
I have provided a submission.md
file that you will use to writeup your
results. This is the file you will submit and be graded on.
For each problem, this file has a place for you to list the following information:
- The flag
- The steps necessary to exploit the binary. (May be a single line.)
- A patch that fixes the exploit. (Generated using
make diff
.) - An explanation of what the vulnerability was and how the patch fixes it. (Keep this explanation short and to the point.)
The README.md
file in the handout gives an example of how the report should
look.
Grading Rubric
For each problem, you can receive 40 points:
- 10 points for correctly extracting the flag from the binary
- 10 points for listing the steps needed to execute your exploit
- 10 points for providing a correct patch
- 10 points for explaining what the vulnerability is and how you patched it
As there are seven problems, this means that there are a total of 280 points for this project.
Handout
Submission
Submit your submission.md
file on Canvas.