# 计算机系统基础:lab 3

# Buf Bomb

# 3.1 实验概述

实验目的:介绍加深对 IA-32 函数调用规则和栈帧结构的理解

实验环境:Linux

实验语言:c

# 3.2 实验内容

本实验的主要内容是对一个可执行程序 “bufbomb” 实施一系列缓冲区溢出攻击,也就是设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为,例如将给定的字节序列插入到其本不应出现的内存位置等。本实验需要熟练运用 gdb、objdump、gcc 等工具完成。实验中需要对目标可执行程序 BUFBOMB 分别完成 5 个难度递增的缓冲区溢出攻击。

# 3.2.1 阶段 1 smoke

1. 任务描述:构造攻击字符串作为输入,造成缓冲区溢出,使 getbuf () 返回时不返回到 test 函数,而是转向执行 smoke 函数

2. 实验设计:分析栈帧结构,使得输入的字符串覆盖 getbuf () 函数的返回地址信息

3. 实验过程:

首先观察到 getbuf 函数中为字符串开辟的空间为 0x28 即 40 字节,由于保存 ebp 占 4 字节,所以返回地址在字符串偏移的 44 字节至 48 字节。只需要将前 44 字节随便填充,最后四字节填充 smoke 函数的入口地址即可。

img

img

在程序反汇编后的文件中查找 smoke 函数,入口地址 0x08048c90。由于是小端存储,最后四字节为 908c0408。

img

4. 实验结果:

img

img

# 3.2.2 阶段 2 Fizz

1. 任务描述:需要利用字符串将 cookie 的值传入作为参数调用 Fizz 函数

2. 实验设计:与 Smoke 类似,只需要在返回地址后面继续覆盖,将参数位置覆盖为 cookie 即可,注意观察堆栈结构

3. 实验过程:

观察图所示的堆栈结构,并结合汇编代码,函数中将 ebp+8 的值与存放 cookie 的寄存器 eax 比较,getbuf 的栈帧返回地址为 ebp+4,因此参数的位置在旧 ebp+8+4 处。将原来的 44-48 字节改为 Fizz 函数入口地址,48-52 字节任意,52-56 字节改为 cookie 值即可。

img

4. 实验结果:答案如图所示,测试通过。

img

img

# 3.2.3 阶段 3 Bang

1. 任务描述:需要在运行时将全局变量的值修改为 cookie 值并调用 Bang 函数

2. 实验设计:由于是在程序运行中修改,需要自定义一段代码修改全局变量并让程序执行,执行后还能返回到 Bang 函数

3. 实验过程:

观察汇编代码如图所示,需要将地址 0x0804c218 处的全局变量改为 cookie 值才能通过。

img

编写攻击代码,将 cookie 值赋值给地址 0x804c218 处,这里用了寄存器当做中间变量。然后将 Bang 函数的入口地址 0x08048d05 压入栈中返回,这样在程序执行完攻击代码后就会跳转到 Bang 函数了。

img

那么如何让程序执行上述攻击代码呢?只需要使用指令 gcc -m32 -c 3.s(假设攻击代码文件名为 3.s)将其转换为机器码,结果如图所示。

然后使用 gdb 调试获取 getbuf 开辟的字符串空间的首地址,即运行到 lea 指令时 eax 的值,结果为 0x556836b8。

img

img

因此攻击字符串构造为攻击代码的机器码,然后填充任意值至 44 字节,44-48 字节使用字符串缓冲区入口地址 0x556836b8 填充。

4. 实验结果:

img

img

# 3.2.4 阶段 4 Boom

1. 任务描述:实现无感攻击,在 getbuf 返回后能回到原来要跳转的 test 函数继续执行,还原对栈帧的破坏

2. 实验设计:与破解 Bang 过程类似,但是需要获取旧的 ebp 和返回地址,构造的攻击代码中恢复栈帧

3. 实验过程:

在 test 函数中查找调用 getbuf 后正确的返回地址,应该为 0x08048e81。

img

然后考虑还原栈帧,需要知道调用 getbuf 之前的旧 ebp 的值,在 call 指令执行前设置断点并查看 ebp 的值,为 0x55683710。

img

接下来就很容易能编写攻击代码了。先篡改 eax 的值为 cookie,作为返回值给 test 函数,然后恢复 ebp,再将正确地址压入堆栈返回。这样在攻击代码执行后就能返回到 getbuf 调用后的语句继续执行。

img

将其转换为机器码:

img

虽然攻击字符串会覆盖原来的返回地址的 ebp,但是执行攻击代码时会将它们恢复,其余与 Bang 类似。

4. 实验结果:

img

img

# 3.2.5 阶段 5 Nitro

1. 任务描述:与 Boom 一样实现无感攻击,但改为调用 testn 函数和 getbufn 函数,跳转地址是动态变化的,需要通过 5 次攻击测试

2. 实验设计:

(1)通过 ebp 和 esp 约束关系找到正确的旧 ebp 的值

(2)多次运行程序,找出字符串存储位置可能的范围

(3)将攻击字符串设置得足够大,使得入口地址能落在攻击字符串的某处

(4)可用 nop 的 ASCII 码 90 大量填充字符串以保证执行最后的攻击代码

3. 实验过程:

首先确定 ebp 与 esp 的约束关系,如图所示,ebp=esp+0x28。

img

getbufn 中有一条 leave 指令恢复 esp,因此根据 esp 即可推断出 ebp。

编写攻击代码如下。先将 cookie 值赋值给 eax,作为 getbufn 的返回值,然后通过 esp 计算出 ebp,最后将调用 getbufn 后的返回地址压入堆栈并返回。

img

将其转换为机器码:

img

观察字符串缓冲区构造,开辟的空间为 0x208 即 520 字节。加上返回地址 4 字节,攻击字符串共需要填充 524 字节。

img

接下来要确定攻击代码的入口地址了,反复调试运行程序,在 getbufn 的 lea 指令地址 0x0804920d 处查看字符串缓冲区地址 eax 的值。某次查看的结果如图所示,得到入口地址 0x556834d8。但是由于每次入口不确定,于是利用 500 多字节的缓冲区猜测入口地址,使用大量 nop 填充,保证入口地址落在 nop 内,最后执行攻击代码即可。

img

多次运行后得到的入口地址结果如下表所示:

0x556834d8 0x55683458 0x556834c8 0x55683498 0x55683478

取其中最大的地址 0x556834d8 就可以保证不会落在攻击字符串 nop 之外。因此最终构造的攻击字符串最后是攻击代码机器码和最大入口地址,其余用 nop 填充。

4. 实验结果:

img

img

完结撒花~~

更新于