哈工大 计算机系统 实验四


所有实验文件可见github 计算机系统实验整理

实验报告

实 验(四)

题 目 Buflab/AttackLab
缓冲器漏洞攻击 
专 业 计算学部
学   号
班   级
学 生
指 导 教 师
实 验 地 点
实 验 日 期

计算机科学与技术学院

目 录

第1章 实验基本信息 - 3 -
1.1 实验目的 - 3 -
1.2 实验环境与工具 - 3 -
1.2.1 硬件环境 - 3 -
1.2.2 软件环境 - 3 -
1.2.3 开发工具 - 3 -
1.3 实验预习 - 3 -
第2章 实验预习 - 4 -
2.1 请按照入栈顺序,写出C语言32位环境下的栈帧结构(5分) - 4 -
2.2请按照入栈顺序,写出C语言62位环境下的栈帧结构(5分) - 4 -
2.3请简述缓冲区溢出的原理及危害(5分) - 5 -
2.4请简述缓冲器溢出漏洞的攻击方法(5分) - 5 -
2.5请简述缓冲器溢出漏洞的防范方法(5分) - 6 -
第3章 各阶段漏洞攻击原理与方法 - 7 -
3.1 SMOKE阶段1的攻击与分析 - 7 -
3.2 FIZZ的攻击与分析 - 7 -
3.3 BANG的攻击与分析 - 9 -
3.4 BOOM的攻击与分析 - 11 -
3.5 NITRO的攻击与分析 - 12 -
第4章 总结 - 15 -
4.1 请总结本次实验的收获 - 15 -
4.2 请给出对本次实验内容的建议 - 15 -
参考文献 - 16 -

第1章 实验基本信息

1.1 实验目的
理解C语言函数的汇编级实现及缓冲器溢出原理
掌握栈帧结构与缓冲器溢出漏洞的攻击设计方法
进一步熟练使用Linux下的调试工具完成机器语言的跟踪调试
1.2 实验环境与工具
1.2.1 硬件环境
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
1.2.2 软件环境
Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位;
1.2.3 开发工具
Visual Studio 2010 64位以上;GDB/OBJDUMP;DDD/EDB等
1.3 实验预习
上实验课前,必须认真预习实验指导书(PPT或PDF)
了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习与实验有关的理论知识。
请按照入栈顺序,写出C语言32位环境下的栈帧结构
请按照入栈顺序,写出C语言64位环境下的栈帧结构
请简述缓冲区溢出的原理及危害
请简述缓冲器溢出漏洞的攻击方法
请简述缓冲器溢出漏洞的防范方法

第2章 实验预习

2.1 请按照入栈顺序,写出C语言32位环境下的栈帧结构(5分)
在这里插入图片描述

2.2请按照入栈顺序,写出C语言64位环境下的栈帧结构(5分)
在这里插入图片描述

2.3请简述缓冲区溢出的原理及危害(5分)
原理:可以通过向程序的缓冲区写超出其可接受长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或覆盖原本的结束指令使其指向某一个攻击代码使程序转而执行攻击指令,以达到攻击的目的。
危害:危害可能有如下两点1、程序崩溃,导致拒绝正常执行程序2、跳转并且执行一段恶意代码,可能对程序进行破坏甚至导致更严重的后果。时

2.4请简述缓冲器溢出漏洞的攻击方法(5分)
通常,输入给程序一个字符串,这个字符串包含一些可执行代码的字节编码,称为攻击代码,另外,还有一些字节会用一个指向攻击代码的指针覆盖返回地址。那么,原本希望的执行ret指令的效果就是跳转到攻击代码。在一种攻击形式中,攻击代码会使用系统调用启动一个shell程序,给攻击者提供一组操作系统函数。在另一种攻击形式中,攻击代码会执行一些未授权的任务,修复对栈的破坏,然后第二次执行ret指令,(表面上)正常返回到调用者。

2.5请简述缓冲器溢出漏洞的防范方法(5分)
1.栈随机化
栈随机化的思想使得栈的位置在程序每次运行时都有变化。因此,即使许多机器都运行相同的代码,它们的栈地址都是不同的。实现的方式是:程序开始时,在栈上分配一段0~n字节之间的随机大小的空间。
2.栈破坏检测
栈破坏检测的思想是在栈中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀值,也称哨兵值,是在程序每次运行时随机产生的。在回复寄存器状态和从函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作改变了。如果是的,那么程序异常终止。
3.限制可执行代码区域
这个方法是消除攻击者向系统插入可执行代码的能力。一种方法是限制某些特定内存区域能够存放可执行代码。在典型的程序中,只有保护编译器产生的代码的那部分内存才可以是可执行的。其他部分可以被限制为只允许读和写。

第3章 各阶段漏洞攻击原理与方法
每阶段25分,文本10分,分析15分,总分不超过75分
3.1 Smoke阶段1的攻击与分析
文本如下: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 bb 8b 04 08
分析过程:
在这里插入图片描述

通过对这一段getbuf函数的反汇编代码的阅读可以发现getbuf的buf缓冲区的大小为0x28+4(44个字节),我们的目标是getbuf结束的时候不正常执行结束命令,而转向执行smoke函数,那么也就是说我们需要输入一个48个字节的攻击字符串,其中前44个字节可以是任意字符起到的作用是填充getbuf开辟的空间,而接下来4个字节就是smoke函数的地址(注意要使用小端方式输入),本代码中smoke的地址为08048bbb,因此可以推出攻击文本如上述展示。
在这里插入图片描述

3.2 Fizz的攻击与分析
文本如下: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 e8 8b 04 08 00 00 00 00 45 c4 0d 32
分析过程:
首先,第一步和3.1的攻击类似,也是需要用一个48字节的输入来把让getbuf结束时不进入test段函数,而是进入fizz函数,那么采用与上述同样的手段,我们发现fizz的地址为08048be8,那么我们可以得到一个输入串,也就是44个字节的任意字符加上fizz地址的小端法输入,这样可以把返回地址定位到fizz函数。
接下来进行进一步分析,可以发现fizz函数的反汇编代码如下图所示:
在这里插入图片描述

观察fizz函数可知,fizz函数中将0x8(%ebp)与0x804e158处的值进行比较,如果相等,则继续往下执行validate,否则向下执行exit(0)。使用gdb查看0x804e158处的值,可以发现这个地址储存的使我们的cookie,如下:
在这里插入图片描述

那么我们就知道我们需要给fizz函数一个初始输入也就是我们的cookie,这个输入是跟在上述分析出来的串的后面的,只需要使0x8(%ebp)处为cookie的值即可,而0x4(%ebp)处的值可以任意,我们将其全部填为0,那么我们就得到了最终的输入串,也就是我们在输入文本中展示的。
在这里插入图片描述

3.3 Bang的攻击与分析
文本如下:c7 05 60 e1 04 08 45 c4 0d 32 68 39 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 e8 3c 68 55
分析过程:
在这里插入图片描述
首先,这个输入串的基础还是和3.1一样,需要的是一个48字节的输入串,而我们需要处理的是把全局变量改成cookie,那么我们需要做的就是把攻击代码存储在buf的开头,在getbuf函数执行结束之后放回buf开头处执行攻击代码,这就是我们的基本思路。
使用gdb,我们可以发现0x804e160中存储的是全局变量,在初试情况下全局变量的值为0,而0x804e158中存储的是按照小端法存储的cookie。如下图所示:

在这里插入图片描述
在这里插入图片描述

接着我们可以确定字符串的首字符的地址,也就是%ebp-0x28,我们可以发现首地址是0x55683ce8。
在这里插入图片描述

接下来我们要开始编辑攻击代码,攻击代码实现的效果就是更改全局变量,接着将bang函数的首地址压入栈中,主要目的是使得全局变量发生更改之后可以调用bang函数,攻击代码的反汇编结果如下:
在这里插入图片描述

最后我们可以得到我们需要的输入字符,开头是我们获得的攻击代码的机器码,接下来是无意义的字符,这两部分加起来一共44个字节,接下来4个字节是字符串的首地址,也就是0x55683ce8(注意是小端法存储)。攻击结果如下:
在这里插入图片描述
3.4 Boom的攻击与分析
文本如下:b8 45 c4 0d 32 68 a7 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 00 30 3d 68 55 e8 3c 68 55
分析过程:
首先分析这一阶段的任务:第一是将cookie作为返回值传送给test函数,第二是恢复栈帧,那这就意味着我们不能再像之前那样使用00 00 00 00覆盖栈帧的值,而是需要恢复在攻击之前的栈帧的值,这就是这一阶段的大概解决思路。
首先我们可以使用gdb发现当运行getbuf的时候栈帧的初始值是0x55683d30如下图所示:
在这里插入图片描述

接着,我们可以得到test函数中在运行getbuf之后的代码的地址0x8048ca7,这是我们运行完getbuf之后需要返回的值,需要加入我们的攻击代码字符串中。
在这里插入图片描述

接下来我们可以开始编写攻击代码的汇编形式并生成其机器码模式,这一段攻击代码的思路是将cookie赋值给%eax,并将test中getbuf下一行代码的地址压入栈,作为getbuf的返回地址。我们需要将这一段机器码插入buf的开头位置,由于buf的开头位置在3.3中已经查询,这里就不再查询,使用上一问结果0x55683ce8。
在这里插入图片描述

从而我们可以获得我们需要的攻击代码的字符串,也就是攻击文本中展示的。攻击结果如下图:
在这里插入图片描述

3.5 Nitro的攻击与分析
文本如下:
在这里插入图片描述

分析过程:
首先分析这一阶段的目的:我们一共需要执行五次getbufn,需要每次都向testn中返回cookie值,主要需要解决的是每一次执行getbufn的过程中它的%ebp的值都是不一样的,这就导致我们的攻击代码的使用位置不确定。
我们发现,尽管%ebp的值是每次都不确定的,但是它和%esp之间是存在数量关系的,也就是%esp+0x18,因此如果我们需要还原被破坏的栈的话我们只需要执行leal 0x18(%esp),%ebp即可,此外,我们需要把cookie值赋给%eax,将其传递给testn函数,那么根据这一分析我们可以得到我们的攻击代码如下:
在这里插入图片描述

根据对于getbufn代码的分析我们容易得知我们这次需要输入的是528个字节的字符,接下来我们需要解决的主要问题是读入的字符串的首字符的地址问题,那么我们可以在getbufn内部打一个断点,主要目的是执行五次,观察每次%eax的值是什么,来确定我们最终可以选择的地址是什么。观察结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们可以选择其中的最高地址0x55683b38作为我们的返回地址,这样可以保证五次执行的过程中每一次都可以执行到攻击代码。则我们现在已经得到的字符串为15个字节的攻击代码和4个字节的首地址,还有509个字节是空缺的,我们使用nop代码来填充,这一代码的机器码为90,从而我们的字符串就是509个字节的nop,15个字节的攻击代码,4个字节的字符串首地址。攻击效果如下:

在这里插入图片描述

第4章 总结
4.1 请总结本次实验的收获
对于栈帧的形式有了更加深刻的认识,同时对于缓冲器漏洞攻击的原理也有了了解,同时对于其危害也有了深刻认识。

4.2 请给出对本次实验内容的建议
可以在ppt上增加更多的教学部分。

注:本章为酌情加分项。

参考文献