目录
前言
- 本实验是《深入理解计算机系统》一书中的附带实验。本次实验要求学生们利用一个缓冲区溢出漏洞,来修改一个二进制可执行文件的运行时行为。
- 掌握缓冲区溢出攻击的原理,加深对IA-32调用约定和堆栈组织的理解,对可执行文件bufb应用一系列缓冲区溢出攻击。
- 本文用于记录之前做实验的一些信息,可能思路有些凌乱,谨慎参考!
实验内容及操作步骤:
一、level 0:Candle
- 让test运行完后,不直接返回退出。而是跳到smoke函数处,继续运行,而当smoke运行完毕后,才退出。
Smoke函数
- 所以先反汇编getbuf函数查看buf数组的首地址,然后反汇编smoke函数查看smoke函数的入口地址
根据这个得到我们输入的序列应该是-0x28(%ebp) ~ 0x8(%ebp)
共48个字节才可以将返回地址覆盖为smoke函数的入口地址0x08048e0a
将所需要输入的序列写入level0.txt
中
- 经验证,正确跳转到了smoke函数处
二、level 1:Sparkler
- 在level 0的基础上,使getbuf函数的返回指向fizz函数,同时将fizz函数的参数置为userid对应的cookie值
Fizz函数
- 根据反汇编查看得到fizz函数的入口地址
0x08048daf
,参数的保存地址
所以level1.txt
构造的序列为
三、level 2:Firecracker
bufbomb在getbuf()函数返回会执行bang()函数。但是在执行bang()函数之前我们需要设计全局变量global_value为我们自己userid的cookie。
- 获取global_value的内存,和bang函数的起始地址
- 生成修改global_value的值和跳转bang函数的二进制代码
gcc -m32 -c level2-code.s
objdump -d level2-code.o > level2-code.txt
使用上面两条指令得到机器码
3. 构造攻击序列
通过gdb调试找到buf数组的首地址
所以,buf的首地址为0x55683828
构造的序列为【步骤2中的代码序列(16字节)+填充序列(28字节)+填充跳转地址(4字节buf起始地址)】
输入指令验证,得到
四、level 3:Dynamite
需要实现的内容:
(1)修改getbuf()返回值为对应cookie,而不是1;
(2)恢复test函数中的%ebp寄存器内容;
(3)返回到接下去test()函数执行位置正常执行
- 通过gdb查看得到test函数正确的ebp内容,以及正常执行下一条指令的地址
可以看出,test函数的ebp值为0x55683d10
,正常返回地址是0x8048e50
- 根据设置getbuf()返回值,重建ebp,返回test()函数的汇编代码获取2进制代码
同上生成二进制代码为
- 构造攻击序列
序列构成如下:
【步骤2中的代码序列(16字节)+填充序列(28字节)+填充跳转地址(4字节buf起始地址)】
经过验证得到
五、level 4:Nitroglycerin
正常的程序运行过程中,具体在栈中的位置是不确定,所以该实验与level3的区别在于,buf等地址在栈中位置是变化的。这里需要用到空操作雪橇(nop sled)技术,通过nop指令构造序列,程序只要执行到任意一个nop指令就会逐渐执行到攻击代码
在level4实验中运用到getbufn()函数、testn()函数,该函数和之前的大体相似,但是会连续执行5次,且buf的缓冲区的长度为520字节。
任务:
(1)确定buf的起始地址范围
(2)获取tesdn函数的正确%ebp指针内容。
(3)确定序列中填充的跳转地址
- 确定buf的起始地址范围
首先可以通过反汇编查看getbufn函数的代码得到buf的首地址位于-0x208(%ebp)
使用gdb,配合使用-n参数初步试探ebp(也可以是ebp-0x208直接试探buf首地址)
buf的初始地址范围为0x556835f8 ~ 0x556836a8
- 通过反汇编查看ebp与esp的关系
生成的二进制代码为:
- 确定序列中填充的跳转地址
因为buf的初始地址不确定,在序列中填充的跳转地址只能根据它的大致范围确定。我们选取buf可能地址中的最大值0x556836a8,这样当buf移动的时候,该地址始终可以命中nop序列。
计算总的攻击序列长度= buf长度为520字节+4空格+填充跳转序列4字节 = 528字节
所以攻击序列如下:【509个nop指令+15字节代码序列+4字节修改返回地址代码序列】
验证结果如下:
需要加上-n参数
实验结果及分析:
可以看出由上一步看出,成功解决问题,详细分析过程如上!