• This lab does not feel especially friendly at the beginning, so I started by getting comfortable with gdb.
  • These are just my own notes and solutions. Solving it once by yourself really does deepen your understanding.
  • Start with the first phase if you want to see how the process begins.
  • Good luck.

Bomb Lab Notes

First, disassemble the bomb binary:

1
objdump -d bomb > bomb.asm

Then you can search inside bomb.asm for things like <phase_1>, <phase_2>, and so on.

After that, open the binary with gdb:

1
gdb bomb

Phase 1

The first phase is the easiest one to read. The function loads a string address into a register, calls a helper that compares two strings, and explodes if the return value is not zero.

So the most direct way to solve it is to break near the comparison call and inspect the registers:

1
(gdb) b *0x400ee9

Then run the bomb and type anything for the first input:

1
2
3
4
5
6
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!

llllluo

Breakpoint 1, 0x0000000000400ee9 in phase_1 ()

Now inspect the string argument:

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

That is the answer to phase 1.

You can also check your own input:

1
2
(gdb) x/s $rdi
0x603780 <input_strings>: "llllluo"

Phase 2

This phase calls read_six_numbers, so the first obvious guess is that it expects six integers.

Reading the assembly shows:

  • the first number must be 1
  • each following number must be double the previous one

So the required sequence is:

1
1 2 4 8 16 32

And the bomb responds with:

1
That's number 2.  Keep going!

Phase 3

This phase uses sscanf with a format that reads two integers. The first number is checked to make sure it is at most 7, and then the code jumps through a small jump table. Each case loads a different constant into %eax, and the second input must match that constant.

So the structure is:

1
index value

One valid answer is:

1
0 207

That is enough to pass phase 3.

Phase 4

This phase also reads two integers, and then calls a recursive helper func4.

From the assembly, you can see:

  • the first input must be at most 14
  • the return value of func4(first, 0, 14) must be 0
  • the second input must also be 0

The midpoint logic inside func4 reveals that the only valid first input is 7, so the answer is:

1
7 0

The bomb replies:

1
So you got that one.  Try this one.

Phase 5

This one expects a string of length 6.

The core loop takes each input character, keeps only its low four bits with andl $0x0f, and uses that value as an index into a 16-character lookup table:

1
maduiersnfotvbyl

The transformed result must become:

1
flyers

So what matters is choosing six characters whose low four bits map to:

1
9 15 14 5 6 7

One working example is:

1
9?.567

After that, the bomb says:

1
Good work!  On to the next...

Phase 6

This is the most annoying normal phase.

It starts by reading six integers, then checks:

  • each number must be between 1 and 6
  • no two numbers can be the same

After that, it transforms each input x into 7 - x. Then it uses those transformed positions to walk through a linked list stored in memory and rebuild a new list in that order.

The list in memory looks like this:

1
2
3
4
5
6
7
(gdb) x/24qd 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

The reordered list must be in descending order by node value:

1
924, 691, 477, 443, 332, 168

That corresponds to node indices:

1
3 4 5 6 1 2

But remember that the program internally uses 7 - x, so the actual input must be:

1
4 3 2 1 6 5

And then you get:

1
Congratulations! You've defused the bomb!
  • Done.