Context
In this post, I will cover a dynamic solution for the second phase of the CMU Binary Bomb, which is a lot of fun and teaches you how some C basics, such as switch statements, recursion, linked lists, end up as assembly.
Phase 2 of the Bomb
Although this phase can easily be done by hand, or symbolic execution, the solution I will be presenting can be easily adapted for more complex tasks.
We’ll start by loading the binary in radare2, in debug mode.
$ r2 -Ad bomb
We’ll continue until sym.phase_2
[0xf76fbd00]> dcu sym.phase_2
I’ll not spoil the solution for phase_1
, even though it’s fairly easy to get to it.
If we look at the code of phase_2
, we’ll notice that it reads six numbers and then compares them with some values in a loop.
╒ (fcn) sym.phase_2 79
│ ; var int local_28h @ ebp-0x28
│ ; var int local_18h @ ebp-0x18
│ ; arg int arg_1h @ ebp+0x1
│ ; arg int arg_8h @ ebp+0x8
│ ; CALL XREF from 0x08048a7e (sym.main)
│ 0x08048b48 55 push ebp
│ 0x08048b49 89e5 mov ebp, esp
│ 0x08048b4b 83ec20 sub esp, 0x20
│ 0x08048b4e 56 push esi
│ 0x08048b4f 53 push ebx
│ 0x08048b50 8b5508 mov edx, dword [ebp + arg_8h] ; [0x8:4]=-1 ; 8
│ 0x08048b53 83c4f8 add esp, -8
│ 0x08048b56 8d45e8 lea eax, [ebp - local_18h]
│ 0x08048b59 50 push eax
│ 0x08048b5a 52 push edx
│ 0x08048b5b e878040000 call sym.read_six_numbers
│ 0x08048b60 83c410 add esp, 0x10
│ 0x08048b63 837de801 cmp dword [ebp - local_18h], 1 ; [0x1:4]=-1 ; 1
│ ┌─< 0x08048b67 7405 je 0x8048b6e
│ │ 0x08048b69 e88e090000 call sym.explode_bomb
│ └─> 0x08048b6e bb01000000 mov ebx, 1
│ 0x08048b73 8d75e8 lea esi, [ebp - local_18h]
│ ┌─> 0x08048b76 8d4301 lea eax, [ebx + 1] ; 0x1 ; 1
│ │ 0x08048b79 0faf449efc imul eax, dword [esi + ebx*4 - 4]
│ │ 0x08048b7e 39049e cmp dword [esi + ebx*4], eax ; [0x13:4]=-1 ; 19
│ ┌──< 0x08048b81 7405 je 0x8048b88
│ ││ 0x08048b83 e874090000 call sym.explode_bomb
│ └──> 0x08048b88 43 inc ebx
│ │ 0x08048b89 83fb05 cmp ebx, 5 ; 5
│ └─< 0x08048b8c 7ee8 jle 0x8048b76
│ 0x08048b8e 8d65d8 lea esp, [ebp - local_28h]
│ 0x08048b91 5b pop ebx
│ 0x08048b92 5e pop esi
│ 0x08048b93 89ec mov esp, ebp
│ 0x08048b95 5d pop ebp
╘ 0x08048b96 c3 ret
We’re going to make this phase solve itself, because we’re too lazy smart to do any manual work (or any work, for that matter).
Go Solve Yourself
We’re going to set two breakpoints. One at the cmp
instruction within the loop, at 0x8048b7e
, and one right after the loop, at 0x8048b8e
.
[0x08048b48]> db 0x8048b7e
[0x08048b48]> db 0x8048b8e
[0x08048b48]> db
0x08048b7e - 0x08048b7f 1 --x sw break enabled cmd="" name="0x8048b7e" module=""
0x08048b8e - 0x08048b8f 1 --x sw break enabled cmd="" name="0x8048b8e" module=""
Now comes the fun part. In radare2, you can add commands to be executed whenever a breakpoint is hit via dbc
. We’ll force our values, which reside at esi + ebx*4
to always be equal to the value in eax
.
[0x08048b48]> "dbc 0x8048b7e .dr*;*(esi+ebx*4)=`dr eax`"
[0x08048b48]> "dbc 0x8048b8e pf dddddd @ esi"
[0x08048b48]> db
0x08048b7e - 0x08048b7f 1 --x sw break enabled cmd=".dr*;*(esi+ebx*4)=`dr eax`" name="0x8048b7e" module=""
0x08048b8e - 0x08048b8f 1 --x sw break enabled cmd="pf dddddd @ esi" name="0x8048b8e" module=""
The first dbc
statement adds two commands to be executed whenever the breakpoint at cmp
is hit. .dr*
executes dr*
as radare2 commands, to force “sync” the registers when the breakpoint is hit.
*(esi+ebx*4)=`dr eax`
writes at esi + ebx*4
(our input) the value of eax
(the desired value). Thus, the comparison will always be true until the loop ends.
The second dbc
statement prints the resulting esi
at the end of the loop, which will be the valid input for defusing this phase of the bomb.
There is one last element that is out of place: execution will still break inside the loop at every iteration. We want our commands to be executed at that point, but without breaking. We can set this breakpoint to be a tracepoint instead.
[0x08048b48]> dbte 0x8048b7e
[0x08048b48]> db
0x08048b7e - 0x08048b7f 1 --x sw trace enabled cmd=".dr*;*(esi+ebx*4)=`dr eax`" name="0x8048b7e" module=""
0x08048b8e - 0x08048b8f 1 --x sw break enabled cmd="pf dddddd @ esi" name="0x8048b8e" module=""
Now we should be set. Just dc
and enjoy.
[0x08048b4b]> dc
hit tracepoit at: 8048b7e
fs+regs
fs-
hit breakpoint at: 8048b81
hit tracepoit at: 8048b7e
fs+regs
fs-
hit breakpoint at: 8048b81
hit tracepoit at: 8048b7e
fs+regs
fs-
hit breakpoint at: 8048b81
hit tracepoit at: 8048b7e
fs+regs
fs-
hit breakpoint at: 8048b81
hit tracepoit at: 8048b7e
fs+regs
fs-
hit breakpoint at: 8048b81
hit breakpoint at: 8048b8e
0xff9aa630 = 1
0xff9aa634 = 2
0xff9aa638 = 6
0xff9aa63c = 24
0xff9aa640 = 120
0xff9aa644 = 720
We’re done with this phase. Those are the defusal numbers.
Hope you’ve enjoyed reading. Have fun with the bomb!