Introduction
A Mad Programmer got really mad and planted a slew of “binary bombs” on our class machines. A binary bomb is a program that consists of a sequence of phases. Each phase expects you to type a particular string on stdin
. If you type the correct string, then the phase is defused and the bomb proceeds to the next phase. Otherwise, the bomb explodes by printing "BOOM!!!"
and then terminating. The bomb is defused when every phase has been defused.
There are too many bombs for us to deal with, so we are giving each student a bomb to defuse. Your mission is to defuse your bomb before the due date. Good luck, and welcome to the bomb squad!
Your task
- Obtain a “binary bomb” as described below.
- Note that this program will automatically communicate with our server. This is how you will be graded.
- If your bomb “explodes”, it will notify our server. Too many explosions will lose you points.
-
The bomb program will ask you you for a secret input.
-
Defuse the “phases” of the bomb by figuring out (e.g. using a debugger) what the secret input for each “phase” is. (You will not get credit for using the debugger to jump over the code that checks whether input is valid; the bomb must send a correct input to our server.)
- For lab: defuse phase 1.
- You will get full credit for defusing phase 1 with less than 20 explosions.
- There is a small grade penalty for explosions beyond 20.
- For homework: defuse phases 2 and 3.
- You will get full credit for defusing phases 2 and 3 with less than 30 explosions.
- There is a small amount of extra credit for each additional phase defused.
- There is a small grade penalty for explosions beyond 30.
Submission
There is no explicit submission. The bomb will notify your instructor automatically about your progress as you work on it.
Viewing your results
You can see your grade, updated with about a 1-hour delay on the gradebook.
There is scoreboard showing how many explosions and phases defused all bombs have here, which is updated more frequently.
About Collaboration
For phase 1, anything goes. Being a lab, you can work together as much as you want.
For phases 2 and beyond, it is homework so more restrictions apply. You are welcome to discuss with one another the process and tools you use, but please do not look at or describe one another’s code.
Obtaining your bomb
-
Use Linux.
This lab only works on 64-bit Linux machines. The lab machines qualify; see these instructions if you need help accessing them remotely.
-
You can obtain your bomb by pointing your Web browser at:
http://archimedes.cs.virginia.edu:15213/ This will display a binary bomb request form for you to fill in. Enter your computing ID and email address and hit the Submit button. The server will build your bomb and return it to your browser in a
tar
file calledbombk.tar
, wherek
is the unique number of your bomb.Save the
bombk.tar
file to a (protected) directory in which you plan to do your work. Then give the command:tar -xvf bombk.tar
. This will create a directory called./bombk
with the following files:README
: Identifies the bomb and its owners.bomb
: The executable binary bomb.bomb.c
: Source file with the bomb’s main routine and a mad greeting from the Mad Mad Programmer.
If for some reason you request multiple bombs, this is not a problem. Choose one bomb to work on and delete the rest.
Getting a bombs from ssh
If you are trying to do the lab without physical access to the machine being used, try the following:
curl "http://archimedes.cs.virginia.edu:15213/?username=$USER&usermail=$USER@virginia.edu&submit=Submit" > bomb.tar
mv bomb.tar $(head -1 bomb.tar | cut -d'/' -f1).tar
Note, this might fail if the remote machine you run it on is not a lab machine because $USER
might not be set correctly by other machines. Replace $USER
with your computing ID if you are running this command e.g. in cloud9, koding, or codio.
Hints
Basic Strategy
-
The best way is to use your favorite debugger to step through the disassembled binary. Almost no students succeed without using a debugger like gdb or lldb.
-
Try running
objdump -t bomb
. This will show you the symbols in the executable, including the names of all methods. Look for one that looks dangerous, as well as some that looks like interesting methods (perhaps something like “Phase 1”). -
To avoid accidentally detonating the bomb, you will need to learn how to single-step through the assembly code and how to set breakpoints. You will also need to learn how to inspect both the registers and the memory states.
-
It may be helpful to use various utilities for examining the bomb program outside a debugger, as described in “examining the executable” below.
Bomb Usage
-
The bomb ignores blank input lines.
-
If you run your bomb with a command line argument, for example,
linux> ./bomb psol.txt
then it will read the input lines from
psol.txt
until it reaches EOF (end of file), and then switch over tostdin
. This will keep you from having re-type solutions.
Examining the Executable
-
objdump -t
will print out the bomb’s symbol table. The symbol table includes the names of all functions and global variables in the bomb, the names of all the functions the bomb calls, and their addresses. You may learn something by looking at the function names! -
objdump -d
will disassemble all of the code in the bomb. You can also just look at individual functions. Reading the assembler code can tell you how the bomb works.If you prefer to get Intel syntax disassembly from
objdump
, you can useobjdump -M intel -d
. -
strings
is a utility which will display the printable strings in your bomb.
Using GDB
-
Run bomb from a debugger like gdb instead of running it directly. The debugger will allow you to stop the bomb before it detonates.
For example, if I ran
linux> gdb bomb (gdb) b methodName (gdb) run (gdb) kill
this will start
gdb
, set a breakpoint atmethodName
, and run the code. The code will halt before it runsmethodName
; callingkill
will stop the bomb and exit the current debugging session withoutmethodName
running. -
Use “step” and “stepi” to examine this function. “step” runs your code one line of source code at a time. “stepi” runs your code one line of machine instruction at a time. This allows you to run “phase_1()” piece by piece.
-
Use this to step carefully through
phase_1()
to see if you can find the passphrase.linux> gdb bomb (gdb) b lineNumberForPhase1Call (gdb) run
input test passphrase here
(gdb) stepi (gdb) info locals (gdb) info registers
Generally some parameters are local variables and some are stored in registers. You should see your test passphrase here. Note the hex value of your input
(gdb) stepi
keep
stepi
ing until you seestrings_not_equal
method (a suspicious name that might be checking your passphrase)(gdb) info locals (gdb) info registers
Which one holds your passphase? Try “examining” that and others…
-
Some useful
gdb
commands:(gdb) info locals
- prints out the name and value of local variables in scope at your current place in the code.
(gdb) info registers
- prints the values of all registers except floating-point and vector registers
(gdb) x/20bx 0x...
- examine the values of the 20 bytes of memory stored at the specified memory address (0x…). Displays it in hexadecimal bytes.
(gdb) x/20bd 0x...
- examine the values of the 20 bytes of memory stored at the specified memory address (0x…). Displays it in decimal bytes.
(gdb) x/gx 0x...
- examine the value of the 8-byte integer stored at the specified memory address.
(gdb) x/s 0x...
- examines the value stored at the specified memory address. Displays the value as a string.
(gdb) x/s $someRegister
- examines the value at register someRegister. Displays the value as a string (assuming the register contains a pointer).
(gdb) print expr
- evaluates and prints the value of the given expression
call (void) puts (0x...)
- calls the built-in output method
puts
with the givenchar *
(as a memory address). Seeman puts
for more. (gdb) disas methodName
- gives you the to get the machine instruction translation of the method
methodName
. (gdb) disas
- gives you the to get the machine instruction translation of the currently executing method.
(gdb) x/6i 0x...
- try to disassemble 6 instructions in memory starting at the memory address 0x…
(gdb) set disassembly-flavor intel
- switches GDB to Intel syntax disassembly (the syntax you used in 2150; not the syntax we will use for the rest of the course)
(gdb) set disassembly-flavor att
- switches GDB back to AT&T syntax disassembly, the default and the syntax we will use for the rest of the course
(gdb) b *0x...
- set a breakpoint at the specified memory address (0x…).
(gdb) b function_name.
- set a breakpoint at the beginning of the specificed function.
(gdb) nexti
- step forward by one instruction, skipping any called function.
(gdb) kill
- termiante the program immediately
(gdb) help
- brings up gdb’s built-in help menu
The textbook also has a nice summary of useful gdb commands on page 280 (or 255 of the 2nd edition). You can also find sources like http://csapp.cs.cmu.edu/2e/docs/gdbnotes-x86-64.txt that list and describe other useful gdb commands.
On interpreting the disassembly
-
Reviewing the x86-64 calling convention (Figure 3.28 in the textbook or this reference you may remember from 2150) may be helpful.
-
The C standard library function
sscanf
is called__isoc99_sscanf
in the executable. Tryman sscanf
for more information about this library function. -
Pay attention to the names of functions being called.
-
Disassembling a standard library function instead of reading the documentation for the function is probably a waste of time.
-
Some of the things later phases might be using include:
* calls to `scanf` (which is much like a backwards version of `printf`; try `man scanf` for more) * linked data structure traversal * recursion * string literals * `switch` statements