Skip to content

L2 bomblab


CS107 Guide to x86-64

CS107 GDB and Debugging



Mark Higgins – Medium

r2 usage is a bit of a pain, but it's a great tool for debugging.

Q & A:


x86 Assembly/GNU assembly syntax - Wikibooks, open books for an open world

  • b = byte (8 bit).
  • s = single (32-bit floating point).
  • w = word (16 bit).
  • l = long (32 bit integer or 64-bit floating point).
  • q = quad (64 bit).
  • t = ten bytes (80-bit floating point).


Check out CSAPP textbook Chapter 3.10.3 Figure 3.39 for more details.

gdb <program>
r # Run your program (give command-line arguments here)
info bre
info reg
ni # stay in the main
si # step into the function
break <function/address>
x/<x/s/d> # shows you the contents of a memory address e.g. x/2g 0x400
p/<format> # shows you the value stored in a named variable e.g. p/x ($rsp+8)

Introduction - The Official Radare2 Book

Basic Commands - The Official Radare2 Book

r2 <program>
aaa # disassemble all
afl # List all functions
pdf @ main~phase # print disassemble function (pdf)
s sym.phase_5 # seek to the address of phase_5
v # into visual mode
c # toggle the cursor on/off

Phase 1

Similar to activity 3 in recitation03-bomblab

break phase_1
Dump of assembler code for function phase_1:
=> 0x0000000000400ee0 <+0>:     sub    $0x8,%rsp
   0x0000000000400ee4 <+4>:     mov    $0x402400,%esi
   0x0000000000400ee9 <+9>:     callq  0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   %eax,%eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
   0x0000000000400ef2 <+18>:    callq  0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    $0x8,%rsp
   0x0000000000400efb <+27>:    retq
End of assembler dump.

After disassembling, we can see that for callq strings_not_equal, it is using %esi as its argument.

(gdb) x/s 0x402400
0x402400:       "Border relations with Canada have never been better."

Phase 2

It starts from <phase_2+18> and loops between <phase_2+27> and <phase_2+52>. The key is <+14>: cmpl $0x1,(%rsp) and <+30>: add %eax,%eax.

Phase 3

   0x0000000000400f51 <+14>:    mov    $0x4025cf,%esi
(gdb) x/s 0x4025cf
0x4025cf:       "%d %d"

The input format is two decimal numbers separated by a space.

<+9>:     lea    0x8(%rsp),%rdx`
<+39>:    cmpl   $0x7,0x8(%rsp)
<+44>:    ja     0x400fad <phase_3+106>

4 bytes of the first number is compared to 0x7, pay attention to operand order for cmp, which is different in linux and windows.

(gdb) x/2wd $rsp+0x8
0x7fffffffe548: 7     321

exam test inputs: 7 321

<+50>:    jmpq   *0x402470(,%rax,8)
(gdb) x 0x402470 + 32
0x402490:       0x00400f91

go to dereferenced content in address 0x00400f91

   0x0000000000400f91 <+78>:    mov    $0x185,%eax
   0x0000000000400f96 <+83>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400fbe <+123>:   cmp    0xc(%rsp),%eax
   0x0000000000400fc2 <+127>:   je     0x400fc9 <phase_3+134>

(gdb) p $rsp
$72 = (void *) 0x7fffffffe540
(gdb) x/d 0x7fffffffe540+0xc
0x7fffffffe54c: 123
(gdb) p/d 0x185
$73 = 389

Phase 4

Look over phase_4 function and we can find:

   0x000000000040101a <+14>:    mov    $0x4025cf,%esi
(gdb) x/s 0x4025cf
0x4025cf:       "%d %d"
   0x0000000000401051 <+69>:    cmpl   $0x0,0xc(%rsp)
   0x0000000000401056 <+74>:    je     0x40105d <phase_4+81>
   0x0000000000401058 <+76>:    callq  0x40143a <explode_bomb>
(gdb) x/wd $rsp+0x8
0x7fffffffe548: 10
(gdb) x/wd $rsp+0xc
0x7fffffffe54c: 123

second number should be 0, here I tested with 10 123.

   0x000000000040102e <+34>:    cmpl   $0xe,0x8(%rsp)
   0x0000000000401033 <+39>:    jbe    0x40103a <phase_4+46>
(gdb) x/d $rsp+0x8
0x7fffffffe548: 10

the first number should be less than or equal to 0xe=14

   0x0000000000401048 <+60>:    callq  0x400fce <func4>
   0x000000000040104d <+65>:    test   %eax,%eax
   0x000000000040104f <+67>:    jne    0x401058 <phase_4+76>
   0x0000000000401051 <+69>:    cmpl   $0x0,0xc(%rsp)
   0x0000000000401056 <+74>:    je     0x40105d <phase_4+81>
   0x0000000000401058 <+76>:    callq  0x40143a <explode_bomb>

the second number should be 0 func4 is called and the result is compared to 0x0, if it is not 0x0, it will call explode_bomb. Then we disassemble func4

   0x0000000000400fe2 <+20>:    cmp    %edi,%ecx
   0x0000000000400fe4 <+22>:    jle    0x400ff2 <func4+36>
   0x0000000000400ff2 <+36>:    mov    $0x0,%eax
   0x0000000000400ff7 <+41>:    cmp    %edi,%ecx
   0x0000000000400ff9 <+43>:    jge    0x401007 <func4+57>

to let func4 return 0x0, the code at <+36>, we can find that the input x must be 7 <= x <= 7. So the first argument is 7.

Phase 5

CMU Bomb Lab with Radare2 — Phase 5 | by Mark Higgins | Medium

I recommend using Radare2, although it has a steep learning curve - Migration from ida, GDB or WinDBG - The Official Radare2 Book

Phase 6

Really tricky that idk if it's worth the effort to defuse it.

<+93> all numbers should be unique
<+121> for each number x, we replace it with 7-x
<+183> copy values into a new stack based on input (six numbers)
<+257> values in the stack (linked list) should be sorted

The key is to understand the linked list structure:

   0x0000000000401183 <+143>:   mov    $0x6032d0,%edx
(gdb) x/24wd 0x6032d0
0x6032d0 <node1>:       332     1       6304480 0
0x6032e0 <node2>:       168     2       6304496 0
0x6032f0 <node3>:       924     3       6304512 0
0x603300 <node4>:       691     4       6304528 0
0x603310 <node5>:       477     5       6304544 0
0x603320 <node6>:       443     6       0       0

Then all we need to do is to sort the values in the nodes, in this case, 332 168 924 691 477 443 to 924 691 477 443 332 168. So, the node order is 3 4 5 6 1 2 and we replace each number x with 7-x: 4 3 2 1 6 5.

Last update: 2023-11-21