实验4 缓冲区溢出攻击实验.docx
《实验4 缓冲区溢出攻击实验.docx》由会员分享,可在线阅读,更多相关《实验4 缓冲区溢出攻击实验.docx(14页珍藏版)》请在冰点文库上搜索。
![实验4 缓冲区溢出攻击实验.docx](https://file1.bingdoc.com/fileroot1/2023-6/21/b54d3f8d-6497-47e0-9b9a-89bb79cd90bd/b54d3f8d-6497-47e0-9b9a-89bb79cd90bd1.gif)
实验4缓冲区溢出攻击实验
深圳大学实验报告
课程名称:
计算机系统
(2)
实验项目名称:
缓冲区溢出攻击实验
学院:
计算机与软件学院
专业:
计算机科学与技术
指导教师:
罗秋明
报告人:
实验时间:
2016年5月8日
实验报告提交时间:
2016年5月22日
教务处制
一、实验目标:
1.理解程序函数调用中参数传递机制;
2.掌握缓冲区溢出攻击方法;
3.进一步熟练掌握GDB调试工具和objdump反汇编工具。
二、实验环境:
1.计算机(IntelCPU)
2.Linux64位操作系统(CentOs)
3.GDB调试工具
4.objdump反汇编工具
三、实验内容
本实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。
我们仅给黑客(同学)提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。
程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲区内容,否则无法通过管卡!
要求同学查看各关卡的要求,运用GDB调试工具和objdump反汇编工具,通过分析汇编代码和相应的栈帧结构,通过缓冲区溢出办法在执行了getbuf()函数返回时作攻击,使之返回到各关卡要求的指定函数中。
第一关只需要返回到指定函数,第二关不仅返回到指定函数还需要为该指定函数准备好参数,最后一关要求在返回到指定函数之前执行一段汇编代码完成全局变量的修改。
实验代码bufbomb和相关工具(sendstring/makecookie)的更详细内容请参考“实验四缓冲区溢出攻击实验.pptx”。
本实验要求解决关卡1、2、3,给出实验思路,通过截图把实验过程和结果写在实验报告上。
四、实验步骤和结果
步骤1返回到smoke()
1.1解题思路
首先弄清楚getbuf()的栈帧结构,知道存放字符数组buf地址的单元和存放getbuf()返回地址的单元之间相差多少个字节。
假设两者之间相差x个字节。
然后找到smoke()函数的入口地址。
该值为4个字节。
再构造exploit.txt,前x个字节随意填,然后再填入4个字节的smoke()地址,注意是小端方式存储。
这样操作完成,就可以得到预期结果了。
1.2解题过程
首先进入GDB对bufbomb进行调试,先在调用getbuf()处设置断点,然后运行。
注:
此时的输入文件exploit_raw.txt文件中是随便填的,并不影响我调用smoke(),因为我会在gdb中使用set指令直接修改getbuf()的返回地址。
此时查看运行程序的调用栈帧结构,如下所示:
上图说明当getbuf()执行完后,会返回到test()函数中(返回到地址0x08048db2,我们要修改存放这个值的地址单元,改为smoke的入口地址值)。
分别进入getbuf和test的帧中,查看esp的值,如下所示,它们两个之间的差值就是getbuf的帧大小,为0x30。
查看getbuf()的汇编代码,可以知道函数getbuf()的帧(大小为0x30)的具体分配:
返回地址4个字节,将%ebp压栈占去4个字节,然后esp减去0x28。
接着看方框2中的两条指令可知,是在为调用Gets()函数构造参数,它将ebp偏移-0x18处的地址作为Gets的参数,用作字符数组的buf地址。
具体的结构如下所示:
由getbuf的栈帧结构可得如下表格:
输入的字符数量
被破坏的状态
0-11
无
12-23
分配后但未使用的空间
24-27
保存的%ebp旧值
28-31
Getbuf的返回地址
32+
调用者test()的状态
在还没有执行Gets()时查看getbuf()的帧结构里面存的值,如下所示:
黑色方框是gets()函数读取字符串所存放的地方,大小为12个字节,蓝色方框则是getbuf()的返回地址。
使用objdump查看函数smoke()的入口地址,如下所示:
由于我是随便填的exploit_raw.txt(但是肯定字符小于12个),肯定不会破坏缓冲区,getbuf执行完了只会返回调用它的函数test中。
但是我使用set指令将getbuf()的返回地址改成了smoke()的入口地址:
然后继续执行程序,getbuf()执行完就跳到smoke()函数中了,如下图所示:
执行正确!
现在已经知道了getbuf()具体的栈帧结构,就可以构造exploit.txt了
可以知道,至少要输入32个字符(即32个字节)才能把getbuf()的返回地址覆盖掉。
如下图所示:
其中前28个字节无所谓,可以随便填,但最后4个字节一定要是smoke()的开始地址0x08048eb0。
由于是采用小端方式存储,所以改地址要写成如下形式(低字节在前)。
再将exploit.txt转成exploit_raw.txt。
1.3最终结果截图
程序成功地跳到了smoke()函数中:
步骤2返回到fizz()并准备相应参数
2.1解题思路
分析fizz()函数,得到它需要一个参数,为‘huanggang’的cookie值。
根据步骤1分析得到的getbuf栈帧结构,可以得到fizz()地址和cookie参数放在栈帧中的具体位置。
再获取fizz()函数的入口地址和‘huanggang’的cookie值,用于构造exploit.txt。
就可以运行了。
2.2解题过程
Fizz()函数的汇编转为C语言大致如下:
即在调用fizz()函数之前,先要构造一个参数cookie,分析栈帧结构,如下所示。
Cookie参数存在存放fizz()入口地址的单元的上方。
所以我们构造exploit.txt时,需要36个字节,其中前28个随便填,第29到32个字节填fizz函数的入口地址值,第33到36字节填‘huanggang’生成的cookie值。
分别找出fizz()地址值和cookie值,如下所示:
接着构造exploit.txt,如下所示:
再将exploit.txt转成exploit_raw.txt。
2.3最终结果截图
成功跳转到fizz()函数中。
步骤3返回到bang()且修改global_value
3.1解题思路
写一段将cookie值赋给global_value,并进入bang()函数的汇编指令,将其汇编再反汇编得到指令的二进制代码。
再将得到的二进制代码通过Gets()函数存到数组buf的缓冲区中,与此同时,修改getbuf()的返回地址为buf的地址(即插入代码的入口)。
Gets()得到的字符串包含注入代码,注入代码的入口,以及一些填充用的字符。
3.2解题过程
先找出bang()函数的地址值、变量global_value和cookie的地址:
使用gdb进行调试,当运行到getbuf()里面,并将Gets()执行完后,使用set命令将函数getbuf()的返回地址值改为bang()的入口地址,并使用set命令将global_value的值设为cookie值。
如下所示:
然后运行,函数跳转到bang()中,并且执行正确。
如下图所示:
程序运行情况已经了解,接下来就需要构建exploit.txt了。
使用自己注入的代码完成上面的set指令。
编写如下汇编代码,功能:
将cookie值赋给global_value,然后进入函数bang()中。
mov0x0804ad4,%eax//把cookie值放到临时寄存器中
mov%eax,0x0804a1c4//把临时寄存器中的值赋给global_value。
push$0x08048e10//把bang()函数的入口地址压栈。
ret//跳转到注入代码的首地址(即buf数组地址)
使用gcc将其编译成机器码,再使用objdump进行反汇编,操作如下:
注意:
在使用gcc编译时加入-m32来要求生成32位机器码,再反汇编。
这样就得到了注入指令的机器码。
注入代码有16个字节,我们需要覆盖到buf地址开始后的32个字节,才能修改getbuf()的返回地址。
所以前16个字节为注入代码,中间12个字节为填充字节,随便填,最后4个字节填注入代码的入口地址,即数组buf的地址。
构造的exploit.txt文件如下:
Linux内存地址有随机化机制,如果随机化机制打开,那么每次运行程序,getbuf()函数中的字符数组buf地址无法确定(注入代码开始地址无法确定),这样的话,注入代码就无法正确写入跳转地址。
所以需要先关闭Linux内存地址随机化机制,才能完成实验。
可以通过设置kernel.randomize_va_space内核参数来设置内存地址随机化的行为。
3.3最终结果截图
成功将global_value值设置为cookie值:
五、实验总结与体会
通过本次实验,加深了对函数调用时堆栈情况的了解,
在步骤3中,开始怎么做也不对。
然后查询资料,发现Linux有内存地址随机化机制,因此在运行时,buf数组的首地址是不一样的,即注入代码首地址不能确定。
关闭内存地址随机化机制后,再来运行程序,就成功了。
说明有时你是做对了,只是环境没配置好,得出了错误的结果。
在编写程序时,一定要注意缓冲区的保护。
指导教师批阅意见:
成绩评定:
指导教师签字:
李炎然
2016年4月21日
备注: