CMU Bomb Lab with Radare2 — Phase 5

Mark Higgins
5 min readJul 13, 2019

Ok, I lied about cheating through everything in this challenge. We will 100% do Phase 5 properly since it focuses on basic reverse engineering. As you may have heard, r2 is great at RE.

If you missed the other posts in this series, here they are:

Start off as we always do. Load the binary, analyze it, print sym.phase_5. At a glance it’s another mess, but if you break it up into parts, the solution is easily scriptable in 10–15 lines of Python.

|     0x0040107a       e89c020000        call sym.string_length
| 0x0040107f 83f806 cmp eax, 6 ; r12
| ,=< 0x00401082 744e je 0x4010d2
| | 0x00401084 e8b1030000 call sym.explode_bomb

Our solution is 6 chars. No problem.

| .. — ->  0x0040108b  0fb60c03      movzx ecx, byte [rbx + rax]
| ::|| 0x0040108f 880c24 mov byte [rsp], cl
| ::|| 0x00401092 488b1424 mov rdx, qword [rsp]
| ::|| 0x00401096 83e20f and edx, 0xf
| ::|| 0x00401099 0fb692b02440. movzx edx, byte [rdx + obj.array.3449]
| ::|| 0x004010a0 88540410 mov byte [rsp + rax + 0x10], dl
| ::|| 0x004010a4 4883c001 add rax, 1
| ::|| ; r12
| ::|| 0x004010a8 4883f806 cmp rax, 6
| `====< 0x004010ac 75dd jne 0x40108b

Let’s look at the key parts.

  1. 0x0040108b — rbx and rax are being used to index through
  2. 0x00401096 — a binary & is applied to edx
  3. 0x00401099 — rdx is used as an index for an array?
  4. 0x004010a8 — Check to see if we’re done

We’re getting dangerously close to doing math, so let’s start debugging and placing breakpoints to figure out what’s going on. I bet you were wondering when we’d talk breakpoints. Well here we go.

Break points

Breakpoints are set in Debug mode from the r2 command line with db [address]. If you do not specify a function or address, db will place a breakpoint at the cursor. You can also set breakpoints in Visual and Graph with F2. Resume/Continue code execution with the dc — (D)ebug (C)ontinue Execution. Obviously that’s a handy command when you’re working with breakpoints and you’ll be using it often.

Visual and Graph mode let you toggle a cursor, which allows you to move around and run commands without having to seek or specify and address. Press the c key to toggle the cursor on/off.

It’s worth mentioning r2 has a Visual mode designed for debugging. Not only does it show you the stack and registers, you can use the cursor c and TAB to select different panes, and p to change the pane’s content.

Don’t forget your cursor works between r2 panes. Use TAB to change pane, then p to change the content

Let’s recap that for those with ADD:

db [address]               # Set breakpoint at specified address
F2 # Set a breakpoint at cursor
dc # Continue code execution
c # Toggle cursor in Visual/Graph mode
TAB # Switch panes in Visual/Graph mode
p # Change print mode in Visual/Graph mode

Add abcdef as your Phase 5 solution in answers.txt, load the binary in r2’s Debug mode, run analysis, thendcu sym.phase_5. Now switch to Visual mode with v, cycle the print mode with p until you see the disassembled function, toggle your cursor with c, then finally move down to the movzx edx, byte [rdx + obj.array.3449] and press F2 to place a breakpoint. Press dc to continue until the breakpoint.

It looks like rdx is being used to select a single character in the object array. Use ps @ obj.array.3449 to print the array

So essentially, our input has a binary &applied to it, and the result is used as an index to select a character from an array. Something like:

array = “maduiersnfotvbyl”
final = ""
for letter in user_input:
index = letter & 0xF
final += array[index]

sym.phase_5 calls a few functions after the loop. Notice that sym.strings_not_equal takes two arguments, our string, and flyers. Disassemble sym.strings_not_equal to see that the two strings are compared, and the function returns 0 if they match.

The goal is to find a password which, after having a binary & applied, indexes with the array to matchflyers. All you really need is to iterate over the target password and brute force for valid characters

#!/usr/bin/env python2
import string
array = "maduiersnfotvbyl"
final = ""
for c in "flyers":
for w in string.ascii_lowercase:
index = ord(w) & 0xF
lookup = array[index]
if lookup == c:
final += w
break
print("Phase 5 password: " + final)

Two more levels to go. By now you’re starting to get a feel for how r2 works and the ideas behind the design. It doesn’t reinvent the wheel, but it’s still an incredibly robust framework that can easily compete with commercial and government tools.

Next: CMU Bomb Lab with Radare2 — Phase 6

Links

Unorganized Random Tips for r2

MalwareTech’s (the guy who stopped WannaCry) Binary Challenges

--

--