Description
Part 1: A Simple Attack [40%]
The first two questions, refer to the file copy.c in the provided code.
Question 1: Build a Simple, Vulnerable Program [0%]
Using copy.c as a guide, write a simple SM213 assembly-language program that copies a nullterminated array of integers (use Snippets 8 or 9 from Assignment 6 as a guide). Call this
program copy.s.
In copy.c, which is reproduced below, the input array is stored in a global variable named src
and the destination array is in a local variable (i.e., stored on the stack). Your assembly code
must do the same.
# copy.c
int src[2] = {1,0};
void copy() {
int dst[2];
int i = 0;
while (src[i] != 0) {
dst[i] = src[i];
i++;
}
dst[i]=0;
}
int main () {
copy();
}
As in copy.c, you will need two procedures: one that copies the array and one that initializes
the stack pointer and calls the copy procedure. Ensure that copy saves r6 (the return address)
on the stack in its prologue and restores it from the stack in its epilogue, as shown in class.
Note that this code contains a buffer-overflow bug. That is intentional. Be sure your assembly
code has this bug so that you will be able to attack it in Question 2. Another thing you’ll want to
do is to keep the value of i in a register in the body of the loop. If you were to read/write it
from/to the stack on every iteration, you’ll find that the buffer overflow will overwrite the value
of i and thus change the way the attack string is written to the stack.
Question 2: Mount an Attack on that Program [40%]
Modify your copy.s to devise a buffer-overflow attack on this program. The attack should set
the value of every register to -1 and then halt.
You are stuck with a similar set of constraints that a real attacker confronts. You may not
modify the program you have just written in any way other than to change its input (i.e.,
src). Change src to make it bigger and to contain virus program and other values as needed so
that copy executes the virus program when it returns, instead of actually returning to main.
You must specify the attack string (the value of src) using a sequence of .long directives.
Recall that each .long specifies the value of 4 bytes of memory. The string will contain the
virus program as machine instructions, which are either 2 bytes or 6 bytes. You will thus need to
compact multiple instructions into a single .long and possibly also split a 6-byte instruction
across two .long’s.
Remember that the only change you are permitted to make to the program you wrote for
Question 1 is to specify a different value for src.
Run your attack in the simulator to be sure that it works.
Part 2: Launching a Shell [60%]
You are now ready to launch a more dangerous exploit: to get an innocent program to launch a
shell that you can use to run arbitrary programs on the infected machine.
The code file contains a directory called examples. Inside this directory, you will find several
programs that use system calls, in both C and SM213 assembly form. The C files can be
compiled and run on the student servers, and the SM213 programs can be run in the simulator.
Run each example in the simulator and see how the system calls interact with the registers and
memory. There is nothing to hand in for this part.
Note that all system calls return a value in r0, which for read and write is the number of
bytes read or written respectively, and for exec is the status of the executed program (0 for
success). All system calls return -1 if they fail (e.g. user canceled input).
Question 3: Develop your “Shellcode” [20%]
Your first task as an Evil Hacker™ is to develop your very own shellcode. Shellcode is binary
code that, when executed by a CPU, uses a system call to launch an interactive shell, giving an
attacker free rein over the system. Thus, the ultimate goal of an attacker is to inject their
shellcode into a program and get it to run. The Morris worm code shown in class is an example
of shellcode for the VAX platform.
On UNIX systems, like the Linux student servers, the shell program is named /bin/sh.
Therefore, you will develop a piece of code that will execute this code on demand.
Shellcode, when executing, cannot make any assumptions about the environment (e.g. it cannot
rely on any data already in memory besides itself). This makes developing shellcode challenging
sometimes. Follow the following steps to produce your very own shellcode.
1. Write a piece of assembly code that uses system call sys $2 (exec) to launch /bin/sh.
Refer to the examples to see how the system call works. Don’t use .pos in your code, and
don’t load or use any absolute addresses – your shellcode must work no matter what address
it is loaded at. Test your shellcode in the simulator to make sure it works.
2. Convert your assembly code into hexadecimal machine code by following the instruction
formats for each instruction. For example, you would translate the instruction mov r1, r2
as 6012.
3. The provided assembly program q3test.s reads input using the read system call (sys $0),
then executes it as code. You can play with this in the simulator, inputting your hexadecimal
machine code by checking the “Hex Input” checkbox.
4. Once you’re satisfied with your shellcode, try it against the CLI simulator. Save your
hexadecimal machine code in a plain text file called shellcode.hex, use xxd to convert
the hex into binary, and send it into the simulator’s input as follows:
xxd -r -p shellcode.hex | java -jar SimpleMachine213.jar -i cli q1test.s
If your shellcode worked, this should print “<<>>”,
indicating that your shellcode would have successfully launched a shell.
If you succeeded in Step 4, submit your original assembly code as shellcode.s and your
hexadecimal machine code as shellcode.hex for this part of the assignment.
Question 4: Exploit the Buffer Overflow [40%]
Now, it’s time to hack a real program. In the code handout, q4vuln.s is a program that uses the
read system call to read some data. It contains a vulnerability.
1. [10%] Reverse-engineer this program into C, and submit it as q4vuln.c. Use the examples
as a guide for how to reverse the system calls into C.
2. [10%] Now, you need to take control over this program’s return address using a stack smash
attack. Conveniently, there’s a function called proof that, when called, prints out a secret
message. To prove that you have control over the return address, write a string that will cause
the program to jump to proof when it tries to return from the main function.
Write the string in hexadecimal, then convert it to binary when feeding it to the program, like
this:
xxd -r -p q4vuln.hex | java -jar SimpleMachine213.jar -i cli q4vuln.s
Submit your hexadecimal-encoded attack string as q4proof.hex.
3. [20%] Finally, combine your shellcode with your controlled return address. Embed your
shellcode inside the attack string, and set the return address to point into it – noting that the
address of the stack is fixed and known. The simulator can help you figure out the right
addresses to use. If you’re successful, the simulator should show the same <<>> output as before when running q4vuln.s with your input. Submit
your new, final attack string as q4exploit.hex.
BONUS: Launch a Remote Attack [+10%]
The vulnerable program q4vuln.s is actually running on a Linux server on the Internet (in an
AWS datacentre), ready to be exploited by all of you. Your goal is to get a real, functioning
remote shell on this server. The simulator is run in a special mode
(SIMPLE_MACHINE_ALLOW_EXEC=1 java -jar …) that causes exec system calls to be routed
to the real OS – so if you can get a shell on this machine, you will actually gain control of a real
system!
The server address is 35.166.142.125, port 1337. To connect, you may use the nc command:
nc 35.166.142.125 1337
Similar to using the simulator directly, you can pipe data into the connection like so (the cat
keeps the connection open so that you can type commands that are sent to the infected program).
(xxd -r -p q4exploit.hex; cat) | nc 35.166.142.125 1337
The bonus has two parts:
1. Take control over the program’s return address, as in Step 2 above. The server will print a
different secret message from the secret message in the provided q4vuln.s; submit the
server’s secret message in secret.txt.
2. Send over your shellcode exploit to obtain a shell on the server. In order to take full
advantage of the remote shell that opens after your exploit runs, you will need to get a little
creative. After you get a functioning remote shell, you will have an opportunity to capture a
flag from the server, stealing a little piece of secret data from it, by running the special
program ./getflag. Run it, figure out how to use it, and obtain your flag. Submit the flag
you got in flag.txt.
What to Hand In
Use the handin program.
The assignment directory is ~/cs-213/a7, it should contain the following plain-text files.
1. PARTNER.txt containing your partner’s CWL login id. Your partner should not submit
anything.
2. Question 1 and 2: copy.s.
3. Question 3: shellcode.s and shellcode.machine.
4. Question 4: q4vuln.c, q4proof.hex, and q2exploit.hex.
5. BONUS: secret.txt and flag.txt.