Bomblab

本文最后更新于:2023年4月20日 晚上

计算机系统第三次实验 Bomb lab

本实验用到的环境、命令如下:

  • Ubuntu 20.04
  • objdump
  • GDB(~peda插件版)

Phase 1

  • 将 bomb 这个 elf 文件使用 file bomb查看其基本信息,得知它是一个 64 bit 程序,放入 Ubuntu 20.04 中进行后续操作;

  • chmod 777 bomb为其赋予权限;

  • 使用 objdump -d bomb获取其反汇编代码如下(节选 部分)

1
2
3
4
5
6
7
8
9
10
11
12
00000000000015e7 <phase_1>:
15e7: f3 0f 1e fa endbr64
15eb: 48 83 ec 08 sub $0x8,%rsp
15ef: 48 8d 35 5a 1b 00 00 lea 0x1b5a(%rip),%rsi # 3150 <_IO_stdin_used+0x150>
15f6: e8 f4 04 00 00 callq 1aef <strings_not_equal>
15fb: 85 c0 test %eax,%eax
15fd: 75 05 jne 1604 <phase_1+0x1d>
15ff: 48 83 c4 08 add $0x8,%rsp
1603: c3 retq
1604: e8 fa 05 00 00 callq 1c03 <explode_bomb>
1609: eb f4 jmp 15ff <phase_1+0x18>

分析如下:

  • 注意不要运行炸弹函数<explode_bomb>

  • 那么需要执行 1603 处的代码;

  • 注意到,15fd 处的跳转若触发,则程序跳转至 1604 处,会失败;

  • 那么 eax 需要为 0,这样 15fb 行跳转不会触发;

  • 需要strings_not_equal函数返回值为 0 ;

  • 上述函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    1aef:	f3 0f 1e fa          	endbr64 
    1af3: 41 54 push %r12
    1af5: 55 push %rbp
    1af6: 53 push %rbx
    1af7: 48 89 fb mov %rdi,%rbx
    1afa: 48 89 f5 mov %rsi,%rbp
    1afd: e8 cc ff ff ff callq 1ace <string_length>
    1b02: 41 89 c4 mov %eax,%r12d
    1b05: 48 89 ef mov %rbp,%rdi
    1b08: e8 c1 ff ff ff callq 1ace <string_length>
    1b0d: 89 c2 mov %eax,%edx
    1b0f: b8 01 00 00 00 mov $0x1,%eax
    1b14: 41 39 d4 cmp %edx,%r12d
    1b17: 75 31 jne 1b4a <strings_not_equal+0x5b>
    1b19: 0f b6 13 movzbl (%rbx),%edx
    1b1c: 84 d2 test %dl,%dl
    1b1e: 74 1e je 1b3e <strings_not_equal+0x4f>
    1b20: b8 00 00 00 00 mov $0x0,%eax
    1b25: 38 54 05 00 cmp %dl,0x0(%rbp,%rax,1)
    1b29: 75 1a jne 1b45 <strings_not_equal+0x56>
    1b2b: 48 83 c0 01 add $0x1,%rax
    1b2f: 0f b6 14 03 movzbl (%rbx,%rax,1),%edx
    1b33: 84 d2 test %dl,%dl
    1b35: 75 ee jne 1b25 <strings_not_equal+0x36>
    1b37: b8 00 00 00 00 mov $0x0,%eax
    1b3c: eb 0c jmp 1b4a <strings_not_equal+0x5b>
    1b3e: b8 00 00 00 00 mov $0x0,%eax
    1b43: eb 05 jmp 1b4a <strings_not_equal+0x5b>
    1b45: b8 01 00 00 00 mov $0x1,%eax
    1b4a: 5b pop %rbx
    1b4b: 5d pop %rbp
    1b4c: 41 5c pop %r12
    1b4e: c3 retq
  • GDB 动态调试中,找到字符串I am not part of the problem. I am a Republican.

  • 传入上述字符串即可通关 phase_1。

Phase 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
000000000000160b <phase_2>:
160b: f3 0f 1e fa endbr64
160f: 55 push %rbp
1610: 53 push %rbx
1611: 48 83 ec 28 sub $0x28,%rsp
1615: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
161c: 00 00
161e: 48 89 44 24 18 mov %rax,0x18(%rsp)
1623: 31 c0 xor %eax,%eax
1625: 48 89 e6 mov %rsp,%rsi
1628: e8 02 06 00 00 callq 1c2f <read_six_numbers>
162d: 83 3c 24 01 cmpl $0x1,(%rsp)
1631: 75 0a jne 163d <phase_2+0x32>
1633: 48 89 e3 mov %rsp,%rbx
1636: 48 8d 6c 24 14 lea 0x14(%rsp),%rbp
163b: eb 10 jmp 164d <phase_2+0x42>
163d: e8 c1 05 00 00 callq 1c03 <explode_bomb>
1642: eb ef jmp 1633 <phase_2+0x28>
1644: 48 83 c3 04 add $0x4,%rbx
1648: 48 39 eb cmp %rbp,%rbx
164b: 74 10 je 165d <phase_2+0x52>
164d: 8b 03 mov (%rbx),%eax
164f: 01 c0 add %eax,%eax
1651: 39 43 04 cmp %eax,0x4(%rbx)
1654: 74 ee je 1644 <phase_2+0x39>
1656: e8 a8 05 00 00 callq 1c03 <explode_bomb>
165b: eb e7 jmp 1644 <phase_2+0x39>
165d: 48 8b 44 24 18 mov 0x18(%rsp),%rax
1662: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
1669: 00 00
166b: 75 07 jne 1674 <phase_2+0x69>
166d: 48 83 c4 28 add $0x28,%rsp
1671: 5b pop %rbx
1672: 5d pop %rbp
1673: c3 retq
1674: e8 d7 fb ff ff callq 1250 <__stack_chk_fail@plt>
  • 关键行 165b ,其无条件跳转回 1644 ,且需注意 1654,eax 必须与 0x4(%rbx)相等,否则触发引爆函数;

  • 由 162d ,1631 得知,第一个传入的数必须是 1;

  • 注意 164f ,eax 值乘2,然后与内存中的一个值比较,这个值是上一次循环中的 eax;

  • 至此,可以看出是一个 2 的幂次的循环。

  • payload = 1 2 4 8 16 32;

  • 成功解决 phase2;

Phase 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
0000000000001679 <phase_3>:
1679: f3 0f 1e fa endbr64
167d: 48 83 ec 18 sub $0x18,%rsp
1681: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1688: 00 00
168a: 48 89 44 24 08 mov %rax,0x8(%rsp)
168f: 31 c0 xor %eax,%eax
1691: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
1696: 48 89 e2 mov %rsp,%rdx
1699: 48 8d 35 8f 1c 00 00 lea 0x1c8f(%rip),%rsi # 332f <array.0+0x14f>
16a0: e8 5b fc ff ff callq 1300 <__isoc99_sscanf@plt>
16a5: 83 f8 01 cmp $0x1,%eax
16a8: 7e 1a jle 16c4 <phase_3+0x4b>
16aa: 83 3c 24 07 cmpl $0x7,(%rsp)
16ae: 77 65 ja 1715 <phase_3+0x9c>
16b0: 8b 04 24 mov (%rsp),%eax
16b3: 48 8d 15 06 1b 00 00 lea 0x1b06(%rip),%rdx # 31c0 <_IO_stdin_used+0x1c0>
16ba: 48 63 04 82 movslq (%rdx,%rax,4),%rax
16be: 48 01 d0 add %rdx,%rax
16c1: 3e ff e0 notrack jmpq *%rax
16c4: e8 3a 05 00 00 callq 1c03 <explode_bomb>
16c9: eb df jmp 16aa <phase_3+0x31>
16cb: b8 4c 01 00 00 mov $0x14c,%eax
16d0: 39 44 24 04 cmp %eax,0x4(%rsp)
16d4: 75 52 jne 1728 <phase_3+0xaf>
16d6: 48 8b 44 24 08 mov 0x8(%rsp),%rax
16db: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
16e2: 00 00
16e4: 75 49 jne 172f <phase_3+0xb6>
16e6: 48 83 c4 18 add $0x18,%rsp
16ea: c3 retq
16eb: b8 89 02 00 00 mov $0x289,%eax
16f0: eb de jmp 16d0 <phase_3+0x57>
16f2: b8 f6 00 00 00 mov $0xf6,%eax
16f7: eb d7 jmp 16d0 <phase_3+0x57>
16f9: b8 ae 01 00 00 mov $0x1ae,%eax
16fe: eb d0 jmp 16d0 <phase_3+0x57>
1700: b8 f1 02 00 00 mov $0x2f1,%eax
1705: eb c9 jmp 16d0 <phase_3+0x57>
1707: b8 17 01 00 00 mov $0x117,%eax
170c: eb c2 jmp 16d0 <phase_3+0x57>
170e: b8 2a 02 00 00 mov $0x22a,%eax
1713: eb bb jmp 16d0 <phase_3+0x57>
1715: e8 e9 04 00 00 callq 1c03 <explode_bomb>
171a: b8 00 00 00 00 mov $0x0,%eax
171f: eb af jmp 16d0 <phase_3+0x57>
1721: b8 24 01 00 00 mov $0x124,%eax
1726: eb a8 jmp 16d0 <phase_3+0x57>
1728: e8 d6 04 00 00 callq 1c03 <explode_bomb>
172d: eb a7 jmp 16d6 <phase_3+0x5d>
172f: e8 1c fb ff ff callq 1250 <__stack_chk_fail@plt>

  • 注意前面几行,sscanf 调用之前,设置了四个参数,可以看出是传入两个数;

  • 且第一个数要小于 7 ,否则触发引爆函数;

  • 随后跳转到 rax 指向的位置执行;

  • 进入 gdb 进行动态调试,跟踪一下进入 rax 指向空间后的堆栈情况;

1
2
3
4
5
6
7
8
9
10
11
12
13
[-------------------------------------code-------------------------------------]
0x5555555556c1 <phase_3+72>: notrack jmp rax
0x5555555556c4 <phase_3+75>: call 0x555555555c03 <explode_bomb>
0x5555555556c9 <phase_3+80>: jmp 0x5555555556aa <phase_3+49>
=> 0x5555555556cb <phase_3+82>: mov eax,0x14c
0x5555555556d0 <phase_3+87>: cmp DWORD PTR [rsp+0x4],eax
0x5555555556d4 <phase_3+91>: jne 0x555555555728 <phase_3+175>
0x5555555556d6 <phase_3+93>: mov rax,QWORD PTR [rsp+0x8]
0x5555555556db <phase_3+98>: sub rax,QWORD PTR fs:0x28
//这是执行代码情况


随后将 eax(值为0x14c)与传入的第二个参数对比,可见第二个参数需要为 0x14c
  • payload = 1 334;

  • 成功解决phase_3;

Phase 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
0000000000001734 <func4>:
1734: f3 0f 1e fa endbr64
1738: 53 push %rbx
1739: 89 d0 mov %edx,%eax
173b: 29 f0 sub %esi,%eax
173d: 89 c3 mov %eax,%ebx
173f: c1 eb 1f shr $0x1f,%ebx
1742: 01 c3 add %eax,%ebx
1744: d1 fb sar %ebx
1746: 01 f3 add %esi,%ebx
1748: 39 fb cmp %edi,%ebx
174a: 7f 06 jg 1752 <func4+0x1e>
174c: 7c 10 jl 175e <func4+0x2a>
174e: 89 d8 mov %ebx,%eax
1750: 5b pop %rbx
1751: c3 retq
1752: 8d 53 ff lea -0x1(%rbx),%edx
1755: e8 da ff ff ff callq 1734 <func4>
175a: 01 c3 add %eax,%ebx
175c: eb f0 jmp 174e <func4+0x1a>
175e: 8d 73 01 lea 0x1(%rbx),%esi
1761: e8 ce ff ff ff callq 1734 <func4>
1766: 01 c3 add %eax,%ebx
1768: eb e4 jmp 174e <func4+0x1a>

000000000000176a <phase_4>:
176a: f3 0f 1e fa endbr64
176e: 48 83 ec 18 sub $0x18,%rsp
1772: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1779: 00 00
177b: 48 89 44 24 08 mov %rax,0x8(%rsp)
1780: 31 c0 xor %eax,%eax
1782: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
1787: 48 89 e2 mov %rsp,%rdx
178a: 48 8d 35 9e 1b 00 00 lea 0x1b9e(%rip),%rsi # 332f <array.0+0x14f>
1791: e8 6a fb ff ff callq 1300 <__isoc99_sscanf@plt>
1796: 83 f8 02 cmp $0x2,%eax
1799: 75 06 jne 17a1 <phase_4+0x37>
179b: 83 3c 24 0e cmpl $0xe,(%rsp)
179f: 76 05 jbe 17a6 <phase_4+0x3c>
17a1: e8 5d 04 00 00 callq 1c03 <explode_bomb>
17a6: ba 0e 00 00 00 mov $0xe,%edx
17ab: be 00 00 00 00 mov $0x0,%esi
17b0: 8b 3c 24 mov (%rsp),%edi
17b3: e8 7c ff ff ff callq 1734 <func4>
17b8: 83 f8 2d cmp $0x2d,%eax
17bb: 75 07 jne 17c4 <phase_4+0x5a>
17bd: 83 7c 24 04 2d cmpl $0x2d,0x4(%rsp)
17c2: 74 05 je 17c9 <phase_4+0x5f>
17c4: e8 3a 04 00 00 callq 1c03 <explode_bomb>
17c9: 48 8b 44 24 08 mov 0x8(%rsp),%rax
17ce: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
17d5: 00 00
17d7: 75 05 jne 17de <phase_4+0x74>
17d9: 48 83 c4 18 add $0x18,%rsp
17dd: c3 retq
17de: e8 6d fa ff ff callq 1250 <__stack_chk_fail@plt>

  • 读入两个数,其中第一个数要小于等于14;
  • 17b8和17bd可看出,func4 返回值和 第二个数均应为 45;
  • 于是一共就有14种可能(1 45、2 45、…… 、 14 45);
  • 分析 func4 可发现其是一个递归函数,当传入参数为 14 时,返回值为 45;
  • payload = 14 45;
  • 第四题解决。

Phase 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
00000000000017e3 <phase_5>:
17e3: f3 0f 1e fa endbr64
17e7: 48 83 ec 18 sub $0x18,%rsp
17eb: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
17f2: 00 00
17f4: 48 89 44 24 08 mov %rax,0x8(%rsp)
17f9: 31 c0 xor %eax,%eax
17fb: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
1800: 48 89 e2 mov %rsp,%rdx
1803: 48 8d 35 25 1b 00 00 lea 0x1b25(%rip),%rsi # 332f <array.0+0x14f>
180a: e8 f1 fa ff ff callq 1300 <__isoc99_sscanf@plt>
180f: 83 f8 01 cmp $0x1,%eax
1812: 7e 5a jle 186e <phase_5+0x8b>
1814: 8b 04 24 mov (%rsp),%eax
1817: 83 e0 0f and $0xf,%eax
181a: 89 04 24 mov %eax,(%rsp)
181d: 83 f8 0f cmp $0xf,%eax
1820: 74 32 je 1854 <phase_5+0x71>
1822: b9 00 00 00 00 mov $0x0,%ecx
1827: ba 00 00 00 00 mov $0x0,%edx
182c: 48 8d 35 ad 19 00 00 lea 0x19ad(%rip),%rsi # 31e0 <array.0>
1833: 83 c2 01 add $0x1,%edx
1836: 48 98 cltq
1838: 8b 04 86 mov (%rsi,%rax,4),%eax
183b: 01 c1 add %eax,%ecx
183d: 83 f8 0f cmp $0xf,%eax
1840: 75 f1 jne 1833 <phase_5+0x50>
1842: c7 04 24 0f 00 00 00 movl $0xf,(%rsp)
1849: 83 fa 0f cmp $0xf,%edx
184c: 75 06 jne 1854 <phase_5+0x71>
184e: 39 4c 24 04 cmp %ecx,0x4(%rsp)
1852: 74 05 je 1859 <phase_5+0x76>
1854: e8 aa 03 00 00 callq 1c03 <explode_bomb>
1859: 48 8b 44 24 08 mov 0x8(%rsp),%rax
185e: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
1865: 00 00
1867: 75 0c jne 1875 <phase_5+0x92>
1869: 48 83 c4 18 add $0x18,%rsp
186d: c3 retq
186e: e8 90 03 00 00 callq 1c03 <explode_bomb>
1873: eb 9f jmp 1814 <phase_5+0x31>
1875: e8 d6 f9 ff ff callq 1250 <__stack_chk_fail@plt>

  • 第五题仍然读入两个数,称之为第一个数、第二个数;
  • 由181a~1820可看出,第一个数不能为15;
  • 1833~1840这块代码可以看成:ecx不断地加上array中的不同的数,这个数,是上一个取出的数对应的数组中相应偏移量*4的数。当去取出的数为0xf时,结束,且此时取的次数应该为15,否则触发引爆函数;
1
2
3
4
5
6
gdb-peda$ x/60 0x5555555571e0
0x5555555571e0 <array.0>: 0x000000020000000a 0x000000070000000e
0x5555555571f0 <array.0+16>: 0x0000000c00000008 0x0000000b0000000f
0x555555557200 <array.0+32>: 0x0000000400000000 0x0000000d00000001
0x555555557210 <array.0+48>: 0x0000000900000003 0x0000000500000006

  • 以上是数组中的数,4字节为一个数(int)
  • 经过计算,payload = 5 115;即从5号元素开始取,最后取15次,取出数的和正好是115。

第五题解决完毕。

Phase_6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
000000000000187a <phase_6>:
187a: f3 0f 1e fa endbr64
187e: 41 56 push %r14
1880: 41 55 push %r13
1882: 41 54 push %r12
1884: 55 push %rbp
1885: 53 push %rbx
1886: 48 83 ec 60 sub $0x60,%rsp
188a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
1891: 00 00
1893: 48 89 44 24 58 mov %rax,0x58(%rsp)
1898: 31 c0 xor %eax,%eax
189a: 49 89 e5 mov %rsp,%r13
189d: 4c 89 ee mov %r13,%rsi
18a0: e8 8a 03 00 00 callq 1c2f <read_six_numbers>
18a5: 41 be 01 00 00 00 mov $0x1,%r14d
18ab: 49 89 e4 mov %rsp,%r12
18ae: eb 28 jmp 18d8 <phase_6+0x5e>
18b0: e8 4e 03 00 00 callq 1c03 <explode_bomb>
18b5: eb 30 jmp 18e7 <phase_6+0x6d>
18b7: 48 83 c3 01 add $0x1,%rbx
18bb: 83 fb 05 cmp $0x5,%ebx
18be: 7f 10 jg 18d0 <phase_6+0x56>
18c0: 41 8b 04 9c mov (%r12,%rbx,4),%eax
18c4: 39 45 00 cmp %eax,0x0(%rbp)
18c7: 75 ee jne 18b7 <phase_6+0x3d>
18c9: e8 35 03 00 00 callq 1c03 <explode_bomb>
18ce: eb e7 jmp 18b7 <phase_6+0x3d>
18d0: 49 83 c6 01 add $0x1,%r14
18d4: 49 83 c5 04 add $0x4,%r13
18d8: 4c 89 ed mov %r13,%rbp
18db: 41 8b 45 00 mov 0x0(%r13),%eax
18df: 83 e8 01 sub $0x1,%eax
18e2: 83 f8 05 cmp $0x5,%eax
18e5: 77 c9 ja 18b0 <phase_6+0x36>
18e7: 41 83 fe 05 cmp $0x5,%r14d
18eb: 7f 05 jg 18f2 <phase_6+0x78>
18ed: 4c 89 f3 mov %r14,%rbx
18f0: eb ce jmp 18c0 <phase_6+0x46> #分界线一
18f2: be 00 00 00 00 mov $0x0,%esi
18f7: 8b 0c b4 mov (%rsp,%rsi,4),%ecx
18fa: b8 01 00 00 00 mov $0x1,%eax
18ff: 48 8d 15 0a 39 00 00 lea 0x390a(%rip),%rdx # 5210 <node1>
1906: 83 f9 01 cmp $0x1,%ecx
1909: 7e 0b jle 1916 <phase_6+0x9c>
190b: 48 8b 52 08 mov 0x8(%rdx),%rdx
190f: 83 c0 01 add $0x1,%eax
1912: 39 c8 cmp %ecx,%eax
1914: 75 f5 jne 190b <phase_6+0x91>
1916: 48 89 54 f4 20 mov %rdx,0x20(%rsp,%rsi,8)
191b: 48 83 c6 01 add $0x1,%rsi
191f: 48 83 fe 06 cmp $0x6,%rsi
1923: 75 d2 jne 18f7 <phase_6+0x7d>
1925: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
192a: 48 8b 44 24 28 mov 0x28(%rsp),%rax
192f: 48 89 43 08 mov %rax,0x8(%rbx)
1933: 48 8b 54 24 30 mov 0x30(%rsp),%rdx
1938: 48 89 50 08 mov %rdx,0x8(%rax)
193c: 48 8b 44 24 38 mov 0x38(%rsp),%rax
1941: 48 89 42 08 mov %rax,0x8(%rdx)
1945: 48 8b 54 24 40 mov 0x40(%rsp),%rdx
194a: 48 89 50 08 mov %rdx,0x8(%rax)
194e: 48 8b 44 24 48 mov 0x48(%rsp),%rax
1953: 48 89 42 08 mov %rax,0x8(%rdx)
1957: 48 c7 40 08 00 00 00 movq $0x0,0x8(%rax)
195e: 00
195f: bd 05 00 00 00 mov $0x5,%ebp
1964: eb 09 jmp 196f <phase_6+0xf5>
1966: 48 8b 5b 08 mov 0x8(%rbx),%rbx
196a: 83 ed 01 sub $0x1,%ebp
196d: 74 11 je 1980 <phase_6+0x106>
196f: 48 8b 43 08 mov 0x8(%rbx),%rax
1973: 8b 00 mov (%rax),%eax
1975: 39 03 cmp %eax,(%rbx)
1977: 7e ed jle 1966 <phase_6+0xec>
1979: e8 85 02 00 00 callq 1c03 <explode_bomb>
197e: eb e6 jmp 1966 <phase_6+0xec>
1980: 48 8b 44 24 58 mov 0x58(%rsp),%rax
1985: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
198c: 00 00
198e: 75 0d jne 199d <phase_6+0x123>
1990: 48 83 c4 60 add $0x60,%rsp
1994: 5b pop %rbx
1995: 5d pop %rbp
1996: 41 5c pop %r12
1998: 41 5d pop %r13
199a: 41 5e pop %r14
199c: c3 retq
199d: e8 ae f8 ff ff callq 1250 <__stack_chk_fail@plt>

  • 这个题比较复杂

  • 首先,18a0可看出,其读入6个数;

  • 18f0以上,使用一系列的判断,最终效果是,输入的六个数均小于等于6大于等于1,且各不相同。

  • 18f0之下的部分,就是按顺序将 node1 这个链表对应的数及地址逐个读入,读入的具体位次,是由输入的6个数决定的,如 1 就读入一次,也就是读入 node1 内存放的数据

  • 知道了node1~node6中存放数据大小关系后,由小到大排序,输入即可通关

  • payload = 2 4 1 5 6 3

  • 本题结束

Secret Phase

  • 首先,发现有 secret phase 函数,其在 bomb_defused()内被调用;

  • 进入这个函数后,先判断 num_input_strings == 6 是否成立,再在offset 57F0处读入3个数据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0x7fffffffde7c --> 0x5555922000007fff
RDX: 0x7fffffffde78 --> 0x7ffff7e05490 (<_IO_fgets+144>: mov edx,DWORD PTR [rbp+0x0])
RSI: 0x555555557379 ("%d %d %s")
RDI: 0x5555555597f0 ("14 45 DrEvil")
RBP: 0x1
RSP: 0x7fffffffde70 --> 0x300000006
RIP: 0x555555555dff (<phase_defused+83>: call 0x555555555300 <__isoc99_sscanf@plt>)
R8 : 0x7fffffffde80 --> 0x555555559220 --> 0x2000000ca
R9 : 0x0
R10: 0x7ffff7f44ac0 --> 0x100000000
R11: 0x7ffff7f453c0 --> 0x2000200020002
R12: 0x7fffffffe008 --> 0x7fffffffe369 ("/home/kawa/Desktop/bomb")
R13: 0x555555555489 (<main>: endbr64)
R14: 0x555555558cf0 --> 0x555555555440 (<__do_global_dtors_aux>: endbr64)
R15: 0x7ffff7ffd040 --> 0x7ffff7ffe2e0 --> 0x555555554000 --> 0x10102464c457f
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x555555555dec <phase_defused+64>: lea r8,[rsp+0x10]
0x555555555df1 <phase_defused+69>: lea rsi,[rip+0x1581] # 0x555555557379
0x555555555df8 <phase_defused+76>:
lea rdi,[rip+0x39f1] # 0x5555555597f0 <input_strings+240>
=> 0x555555555dff <phase_defused+83>: call 0x555555555300 <__isoc99_sscanf@plt>
0x555555555e04 <phase_defused+88>: cmp eax,0x3
0x555555555e07 <phase_defused+91>: je 0x555555555e17 <phase_defused+107>
0x555555555e09 <phase_defused+93>: lea rdi,[rip+0x14a8] # 0x5555555572b8
0x555555555e10 <phase_defused+100>: call 0x555555555220 <puts@plt>
Guessed arguments:
arg[0]: 0x5555555597f0 ("14 45 DrEvil")
arg[1]: 0x555555557379 ("%d %d %s")
arg[2]: 0x7fffffffde78 --> 0x7ffff7e05490 (<_IO_fgets+144>: mov edx,DWORD PTR [rbp+0x0])
arg[3]: 0x7fffffffde7c --> 0x5555922000007fff
arg[4]: 0x7fffffffde80 --> 0x555555559220 --> 0x2000000ca


注意RDI,也就是第一个参数的值,可以看出这个是 phase 4 的payload,故在修改 phase 4 payload = 14 45 DrEvil;

即可触发隐藏 phase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
00000000000019e3 <secret_phase>:
19e3: f3 0f 1e fa endbr64
19e7: 53 push %rbx
19e8: e8 87 02 00 00 callq 1c74 <read_line>
19ed: 48 89 c7 mov %rax,%rdi
19f0: ba 0a 00 00 00 mov $0xa,%edx
19f5: be 00 00 00 00 mov $0x0,%esi
19fa: e8 e1 f8 ff ff callq 12e0 <strtol@plt>
19ff: 89 c3 mov %eax,%ebx
1a01: 83 e8 01 sub $0x1,%eax
1a04: 3d e8 03 00 00 cmp $0x3e8,%eax
1a09: 77 26 ja 1a31 <secret_phase+0x4e>
1a0b: 89 de mov %ebx,%esi
1a0d: 48 8d 3d 1c 37 00 00 lea 0x371c(%rip),%rdi # 5130 <n1>
1a14: e8 89 ff ff ff callq 19a2 <fun7>
1a19: 83 f8 02 cmp $0x2,%eax
1a1c: 75 1a jne 1a38 <secret_phase+0x55>
1a1e: 48 8d 3d 63 17 00 00 lea 0x1763(%rip),%rdi # 3188 <_IO_stdin_used+0x188>
1a25: e8 f6 f7 ff ff callq 1220 <puts@plt>
1a2a: e8 7d 03 00 00 callq 1dac <phase_defused>
1a2f: 5b pop %rbx
1a30: c3 retq
1a31: e8 cd 01 00 00 callq 1c03 <explode_bomb>
1a36: eb d3 jmp 1a0b <secret_phase+0x28>
1a38: e8 c6 01 00 00 callq 1c03 <explode_bomb>
1a3d: eb df jmp 1a1e <secret_phase+0x3b>
00000000000019a2 <fun7>:
19a2: f3 0f 1e fa endbr64
19a6: 48 85 ff test %rdi,%rdi
19a9: 74 32 je 19dd <fun7+0x3b>
19ab: 48 83 ec 08 sub $0x8,%rsp
19af: 8b 17 mov (%rdi),%edx
19b1: 39 f2 cmp %esi,%edx
19b3: 7f 0c jg 19c1 <fun7+0x1f>
19b5: b8 00 00 00 00 mov $0x0,%eax
19ba: 75 12 jne 19ce <fun7+0x2c>
19bc: 48 83 c4 08 add $0x8,%rsp
19c0: c3 retq
19c1: 48 8b 7f 08 mov 0x8(%rdi),%rdi
19c5: e8 d8 ff ff ff callq 19a2 <fun7>
19ca: 01 c0 add %eax,%eax
19cc: eb ee jmp 19bc <fun7+0x1a>
19ce: 48 8b 7f 10 mov 0x10(%rdi),%rdi
19d2: e8 cb ff ff ff callq 19a2 <fun7>
19d7: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
19db: eb df jmp 19bc <fun7+0x1a>
19dd: b8 ff ff ff ff mov $0xffffffff,%eax
19e2: c3 retq

  • 先读入一行字符串,然后转换为整型;
  • 注意 1a04 和 1a09,输入转换的整型,要小于等于1001,由此可发现,输入的数据应该是一个数,而不是几个。
  • 随后调用 fun7,且最后返回值必须是2,否则爆炸。
  • 来到fun7 内;
  • fun7 是一个递归函数,需要明确的是,rdi 是 fun7 的第一个参数,大概率是个指针(因为后面引用它时用了括号),esi是第二个参数,这个是我们最开始输入进去的一个数。
  • 在 fun 7 内,esi的值是不改变的,也就是我们输入的值,一直都是参数之一,而另一个参数;
  • 如果当前节点的值大于输入值,当前节点变为当前节点+8;
  • 返回两倍的下一个节点调用fun7的返回值;
  • 不满足大于的话,result 化为0;
  • 若相等,直接返回0;
  • 若当前节点值小于输入值,将result值赋为2倍的下一节点的值+1,且注意,下一节点是当前节点+16;
  • 返回result值

来看看这些节点,以及它们的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

0x555555559130 <n1>: 0x0000000000000024 0x0000555555559150
0x555555559140 <n1+16>: 0x0000555555559170 0x0000000000000000
0x555555559150 <n21>: 0x0000000000000008 0x00005555555591d0
0x555555559160 <n21+16>: 0x0000555555559190 0x0000000000000000
0x555555559170 <n22>: 0x0000000000000032 0x00005555555591b0
0x555555559180 <n22+16>: 0x00005555555591f0 0x0000000000000000
0x555555559190 <n32>: 0x0000000000000016 0x00005555555590b0
0x5555555591a0 <n32+16>: 0x0000555555559070 0x0000000000000000
0x5555555591b0 <n33>: 0x000000000000002d 0x0000555555559010
0x5555555591c0 <n33+16>: 0x00005555555590d0 0x0000000000000000
0x5555555591d0 <n31>: 0x0000000000000006 0x0000555555559030
0x5555555591e0 <n31+16>: 0x0000555555559090 0x0000000000000000
0x5555555591f0 <n34>: 0x000000000000006b 0x0000555555559050
0x555555559200 <n34+16>: 0x00005555555590f0 0x0000000000000000


再想想题目,我们最后需要构造这样的结构:

  • 返回值为2,有一种可能:

    • 通过最外层调用中,输入值小于节点值实现,要求最外层-1次调用返回值为1;
  • 故:倒数第二层调用必须返回值为1;

  • 若某层返回值为1,这说明了什么捏?

  • 说明该层调用的内一层调用,必须走a1 != a2 路线,且要求内层调用返回值为0;

  • 若某层返回值为0,这又说明了什么捏?

  • 一定是第一种调用,也就是a1 > =a2,且内层一直是第一种调用,输入值小于节点值。

  • 综上,输入值应满足:一直小于某些节点值,以及最外一层的节点值,但最内一层,输入值必须等于某一节点值,否则循环不完了。

  • 有以下节点值:0x24, 0, 0x8, 0x32,0x16,0x2d,0x6,0x6b,0x0;

  • 选择0x24尝试:

    • 先是等于,然后直接返回,不行;
  • 选择0x0尝试:

    • 0一直是最小的数,也不可能实现;
  • 选择0x8尝试:

    • 8 < 24 , goto 1, node -> node + 8, 8 > 6, goto 2, node += 16, 16 > 8 , 2d>8,
  • 太多数据,不再尝试。

  • 再次分析,由于最初的节点是0x24,且最初节点必须走第一种跳转,也就是说第一层节点值大于输入值。

  • 然后,节点+8,来到50号的 0x8,这里要求,返回值为1,也就是传入值 >=8,然后最后一层需要相等。这样一来,答案就明朗了,答案就是0x16

  • 测试一下:

1
2
3
4
22
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!

ok

全部通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
kawa@kawa-virtual-machine:~/Desktop$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
I am not part of the problem. I am a Republican.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That's number 2. Keep going!
1 332
Halfway there!
14 45 DrEvil
So you got that one. Try this one.
5 115
Good work! On to the next...
2 4 1 5 6 3
Curses, you've found the secret phase!
But finding it and solving it are quite different...

22
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!

实验至此结束


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!