Project 2: Software Vulnerabilities
Due: 04/06/2025 (Sun) 11:59pm
Introduction
In this project, you will perform a series of software vulnerability exploits. You will explore unsafe and insecure programming techniques and evaluate the efficacy of operating system defenses against them.
Getting started
If you have not finished setting up your project environment, please follow the instructions in Project Setup to set it up first.
We expect you will work on this project remotely in the project server through SSH.
[host] $ ssh NetID@csa-chk22b.utdallas.edu
Once you are successfully logged in,
fetch the source code of Project 2 in the project server.
To do that,
use Git to commit changes you've made since handing in Project 1 (if any),
fetch the latest version of the course repository, and then create a
local branch called project2
based on
our project2 branch origin/project2
:
$ cd ~/infosec
$ git pull
Already up-to-date.
$ git add -A
$ git commit -am 'changes to project1 after handin'
Created commit 734fab7: changes to lab1 after handin
3 files changed, 28 insertions(+), 7 deletions(-)
$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote:
To ssh://s3lab.utdallas.edu:2224/cxk200010/infosec.git
88682b1..494dc56 lab1 -> lab1
$ git checkout -b project2 origin/project2
Branch project2 set up to track remote branch refs/remotes/origin/project2.
Switched to a new branch "project2"
$ git clean -dfx
$
The git checkout -b
command shown above actually does two things: it
first creates a local branch project2
that is based on the
origin/project2
branch provided by the course staff, and second, it
changes the contents of your project directory to reflect the files
stored on the project2
branch.
Git allows switching between existing
branches using git checkout branch-name
(change branch-name
to the branch name you want to switch to), though you should commit any
outstanding changes on one branch before switching to a different one.
The git clean -dfx
command deletes all unsaved files from
the project1
branch (e.g., *.class
files), which you do not need
for this project.
You will now need to bring your student.info
file
from the project1
branch
into the project2
branch, as follows:
$ git checkout --patch project1 student.info
$ git commit -am "Bring student.info from project1"
Project 2 includes two directories: targets and exploits.
In the targets directory,
you will find the source files of target programs
(target1.c
, target2.c
, target3.c
, and target4.c
).
These programs are written in C and contain hidden
software vulnerabilities that you need to identify and exploit.
Please do not modify the source code of the target programs.
The source code of your exploits
needs to be placed in the exploits directory.
You need to access a virtual machine (VM) that is set up to run
the targets and your exploits, namely attackme
.
This VM has the tools (e.g., gcc
and gdb
) that
we expect you to use to examine the target programs and write
the exploits.
We do not provide full-featured hacking and code analysis
tools, such as Ghidra and IDA in this VM.
You will not gain your knowledge/techniques to
identify and exploit the software vulnerabilities
if you use these automated tools,
which is against the main goal of this project.
If you need legitimate tools and the VM does not have the tools
installed, you can request the CS 6324 staff to install them,
subject to the instructor's approval.
You can access the VM through SSH from inside the project server:
$ ssh attackme
[attackme] $
The VM shares your home directory (~/
) with the project server.
Any changes in your home directory including project files
in the infosec directory will be synchronized between the VM
and project server automatically.
To compile the source code of the target programs, run the following commands.
[attackme] $ cd ~/infosec/targets
[attackme] $ make
gcc -ggdb -Wall target1.c -o target1
gcc -ggdb -Wall target2.c -o target2
gcc -ggdb -Wall target3.c -o target3
gcc -ggdb -Wall target4.c -o target4
target4.c: In function 'main':
target4.c:12: warning: unused variable 'a'
target4.c:12: warning: unused variable 'b'
target4.c:12: warning: unused variable 'c'
target4.c:12: warning: unused variable 'd'
Hand-in procedure
You will turn in your project by pushing your progress to the repository and tag the final version of the project.
When you are ready to hand in your project code and report,
please place the report in a file called report-project2.pdf
in the top level of your directory before handing in your work.
After that,
add your report to the Git repository with
git add report-project2.pdf
and git commit
.
If you have obtained help of any kind while working on this project,
make sure to write the names or URLs of your sources in
references-project2.txt
in the top level of your directory,
and add it to the repository with git add references-project2.txt
and git commit
.
You need to update Makefile
in the exploits
directory.
This Makefile
will be used by the CS 6324 staff to
run and grade your exploits.
Your exploits can be written in any programming/scripting
language that the VM supports
(e.g., Bash, C, Perl, and Python).
For example, you can create a shell script for your exploit1
and
add the following command into Makefile
to run it:
exploit1:
@echo "# exploit1: Add your commands to run the exploit below"
./exploit1.sh
Or, you can add the following commands into Makefile
for us to run your exploit1
written C:
exploit1:
@echo "# exploit1: Add your commands to run the exploit below"
gcc exploit1.c -o exploit1
./exploit1
When the CS 6324 staff runs the following command in the VM,
your Makefile
should allow running your exploit1
:
$ make exploit1
Failure to follow these rules will not give you any credit.
Note
Tip
If you write an exploit in C,
you should use a function like execve
to launch the
target, but not a function like system
.
When using execve
, pass in NULL
for the environmental variables
so that it will be consistent and repeatable from run to run.
Make sure your exploits run successfully in the VM
since that is where we will grade them.
Run the following commands to check if your exploits run
successfully in the attackme
VM.
[attackme] $ cd ~/infosec/exploits
[attackme] $ make
After checking your exploits run successfully in the VM, add the new exploit files and any other new files you have created into the Git repository, commit, and push. For example,
[attackme] $ git add exploit1.sh exploit2.c
[attackme] $ git commit -am 'project2 complete'
[attackme] $ git push
Tag your final commit as project2-final
and
push the tag to the repository to submit your progress.
We only grade the commit with this tag.
[attackme] $ git tag project2-final
[attackme] $ git push
[attackme] $ git push origin --tags
# if you want to change the final tag,
[attackme] $ git tag -d project2-final # this will delete the local tag
Deleted tag 'project2-final' (was 75411c7)
[attackme] $ git push origin :refs/tags/project2-final # this will delete the remote tag
To ssh://s3lab.utdallas.edu:2224/cxk200010/infosec.git
- [deleted] project2-final
Simple Command Line Buffer Overflow (20 pts)
target1
is a program that takes a directory as input,
and tells the user how to use the command
ls
to list the contents of the directory.
You will login as a normal user, and your goal is to pass
an argument to the program so it will start a shell
by exploiting a buffer overflow vulnerability.
Suppose that this program is setuid root, then it would be possible to start a "root" shell. Although the target program does not actually have the setuid bit set or owned by root (to avoid potential security issues), please assume that it is setuid root.
Note
You are required to exploit a buffer overflow vulnerability to start a shell. For example, passing "/bin/bash" as a command line argument to the target program to open a shell (without exploiting the vulnerability) will not give you any credit.
In the
exploits
directory, write an exploit program (e.g.,exploit1.c
orexploit1.sh
) that passes an attack string to the target and performs the attack. UpdateMakefile
to (compile and) run your exploit.make exploit1
should run your exploit successfully.Identify the exact vulnerability in the program that you exploited (i.e. function name and line number). Explain why it is a vulnerability.
Explain your attack strategy. That is, explain how you determined the correct input to pass and what commands are executed.
Buffer Overflow to Rewrite a Return (20 pts)
The attack
target2
is a program that takes a customer's name as the input,
and prints a coupon.
Assume that each customer can only execute the program once,
so he/she can only get one coupon.
Your goal is to pass some argument to the program so it will
repeatedly print coupons.
In other words, the argument will make the program execute the
function coupon
repeatedly.
Note
To get full credit, the function coupon has to execute an infinite number of times. If it only executes twice, then you will get half the points.
In the
exploits
directory, write an exploit program (e.g.,exploit2.c
orexploit2.sh
) that passes the attack string to the target and performs the attack. UpdateMakefile
to (compile and) run your exploit.make exploit2
should run your exploit successfully.Identify the specific bug/vulnerability that made your attack possible (i.e. function name and line number). Explain why it is a vulnerability.
Describe your attack strategy. That is, describe the memory addresses involved in your attack, and explain how the attack made the program print an unlimited number of coupons.
The defense
The project server that hosts the attackme
VM
has an updated operating system with some stack defenses activated.
Repeat the attack on
target2
outside the VM. Did the attack work? Comment on your results (i.e. explain why).Propose two different operating system and/or compiler/programming language defenses that can be used to prevent this attack from working. Discuss the advantages, disadvantages, and feasibility of the proposed defenses.
Return to LibC (20 pts)
The attack
target3
is a program that scans several network packets and
checks if the traffic (concatenation of the packets) matches
any virus signatures.
Suppose target3
is setuid root.
You will login as a normal user, and the goal is to pass
argument(s) to the program to start a root shell
by exploiting a return-to-libc vulnerability.
You need to assume that the stack is not executable. Therefore, you cannot change the return address to the shellcode in the stack.
Draw the layout of the stack frame corresponding to the function
is_virus
directly after the local variables are initialized. For each element on the stack, provide its size.In the
exploits
directory, write an exploit program (e.g.,exploit3.c
orexploit3.sh
) that performs the attack. UpdateMakefile
to (compile and) run your exploit.make exploit3
should run your exploit successfully.Identify the specific bug in the program and vulnerability that made your attack possible (i.e. function name and line number). Explain why it is a vulnerability.
Describe your attack strategy. That is, explain what memory addresses you used and how you figured out those addresses.
The defense
Try repeating the above attack on the project server outside the VM. The attack should become more difficult now.
Are you able to get the attack to work? If so, explain your method. Otherwise, explain what prevented you from completing the attack.
What specific mechanism(s) make the attack more difficult?
Format String Attacks (40 pts)
target4
has a format-string vulnerability;
your task is to develop
a scheme to exploit this vulnerability.
The target program asks the user to provide an input,
which will be saved in a buffer called user_input
.
The program then prints out the buffer using printf
.
Unfortunately, there is a format-string vulnerability in the way
the printf
is called on the user inputs.
We want to exploit this vulnerability and
see how much damage we can achieve.
The program has two secret values stored in its memory, and you are interested in these values. However, the secret values are unknown to you, nor can you find them from reading the binary code.
Note
For the sake of simplicity, we hardcode the secrets using constants 0x44 and 0x55, but you can pretend that you don't have the source code or the secrets.
Although you do not know the secret values, in practice, it is not so difficult to find out their memory addresses (the range or the exact value). The values are at consecutive memory addresses because in many operating systems, memory addresses remain unchanged any time you run the program.
Draw the layout of the stack frame corresponding to the main function directly after the local variables are initialized. For each element on the stack, provide its size.
Provide the specific inputs (i.e. both the integer and the string) that you need in order to crash the program. Write the inputs in
exploit4.txt
at line 1 in the form ofint string
That is, the integer number, followed by a space, followed by the string. Explain why the program crashes with your inputs.Provide the specific inputs (i.e. both the integer and the string) that you need in order to print the address of the variable
secret[0]
. Write the inputs inexploit4.txt
at line 2 in the form ofint string
. Explain why you think this is the correct address.
Note
Tip You can use GDB to verify that your answer is correct.
Provide the specific inputs (i.e. both the integer and the string) that you need in order to print the value of
secret[0]
. Write the inputs inexploit4.txt
at line 3 in the form ofint string
. Explain your strategy.Based on your knowledge of how arrays are stored on the heap, calculate the address of
secret[1]
. Write the inputs inexploit4.txt
at line 4 in the form ofint string
. Explain your strategy.Provide the specific inputs (i.e. both the integer and the string) that you need in order to print the value of
secret[1]
. Write the inputs inexploit4.txt
at line 5 in the form ofint string
. Explain your strategy.Provide the specific inputs (i.e. both the integer and the string) that you need in order to modify the values of both
secret[0]
andsecret[1]
. Write the inputs inexploit4.txt
at line 6 in the form ofint string
. Explain your strategy.Does Address Space Layout Randomization (ASLR) make this attack more difficult? Explain.
What other operating system defenses can be used to prevent this attack? Explain.
Failure to follow the format rules on exploit4.txt
will not give you any credit.
Makefile
in the exploits
directory has commands
to print out the content of exploit4.txt
when make exploit4
is executed.
Please do not change that part.
Using GDB
GDB is the best way to understand how a target program executes internally when certain inputs given at run-time in this project. You can also identify the memory addresses of variables and buffers to exploit, and print out the content of the stack memory, including the return address of a function call. See the GDB manual for a full guide to GDB commands. Here are some particularly useful commands for this project.
- Ctrl-c
Halt the machine and break in to GDB at the current instruction.
- c (or continue)
Continue execution until the next breakpoint or
Ctrl-c
.- si (or stepi)
Execute one machine instruction.
- b function or b file:line (or breakpoint)
Set a breakpoint at the given function or line.
- b *addr (or breakpoint)
Set a breakpoint at the EIP addr.
- set print pretty
Enable pretty-printing of arrays and structs.
- info registers
Print the general purpose registers,
eip
,eflags
, and the segment selectors.- x/Nx addr
Display a hex dump of N words starting at virtual address addr. If N is omitted, it defaults to 1. addr can be any expression.
- x/Ni addr
Display the N assembly instructions starting at addr. Using
$eip
as addr will display the instructions at the current instruction pointer.