20145302张薇 《网络对抗技术》逆向及BOF基础实践
实验内容
- 实践对象:名为20145302的linux可执行文件。
- 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
- 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。但是正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。
- 实践两种方法:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
实验原理
- 缓冲区溢出:计算机程序一般都会使用到一些内存,这些内存或是程序内部使用,或是存放用户的输入数据,这样的内存一般称作缓冲区。溢出是指盛放的东西超出容器容量而溢出来了,在计算机程序中,就是数据使用到了被分配内存空间之外的内存空间。而缓冲区溢出,简单的说就是计算机对接收的输入数据没有进行有效的检测(理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据。
实践1、手工修改可执行文件
-
先运行一下此文件,应该实现的是foo函数的功能:
-
将此文件进行反汇编:
- 第一列表示内存中的地址,第二列是机器指令的十六进制代码,第三列是反汇编后的汇编指令。
- 在main函数中我们发现有一条call指令调用了地址为8048491的foo函数
- 为了使函数不运行foo函数,二是运行getshell函数,我们想要把main函数的call指令后的地址改为getshell函数的地址。
- call指令的机器代码为“e8 d7 ffffff”,为了调用为getshell的地址,我们需要将“e8 d7 ffffff”改为“getshell-80484ba”对应的补码,即“e8 c3 ffffff”。
-
开始手动修改可执行文件
-
利用vi进入文件:
-
此时文件界面显示的是ASCⅡ码形式,我们输入命令
:%!xxd
,将显示模式切换为16进制模式 -
由于数据太多,我们使用查找功能,输入“/e8 d7”,查找我们所需修改的内容:
-
利用vi的修改功能,点击
i
键进入插入模式,并将d7修改为c3:
-
使用命令
:%!xxd -r
将16进制转换为原格式,随后再用:wq
命令存盘退出vi。(这一步很重要,否则无法成功运行)
-
验证运行是否修改成功:
-
再次使用反汇编指令观察机器代码的改变:
实践2、通过构造输入参数,造成BOF攻击,改变程序执行流
-
反汇编查看文件汇编代码
-
我们发现foo函数只为该文件留了38字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址
-
进入gdb模式用r来运行,再使用
info r
来查看寄存器中的值。在此使用测试数字:1111111122222222333333334444444455555555.(我们完全可以使用其他数字来进行测试,只要自己易于区分即可)
-
我们观察到eip的值为"0x35353535 0x35353535",而十六进制的35换算成ASCⅡ码是5,由此得知溢出部分是在5这一部分发生的,为了进一步详细确认地址发生覆盖的位置,我们将测试数字更变为:1111111122222222333333334444444412345678
-
观察得知:eip的值更变为“0x34333231 0x34333231”,换算成ASCⅡ码即为1234。意味着字符串1111111122222222333333334444444412345678中1234那四个位置上的数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码
-
由此,我们将这4个位置上的数替换为getShell的内存地址,就可以让文件运行getShell
-
确认字节序:
-
输入我们构造的字符串来进行攻击,验证攻击成功:
Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。
使用输出重定向“>”将perl生成的字符串存储到文件input中。
实践问题
- 为何进入vi后,在16进制模式下修改后直接保存退出会导致文件无法运行?