20145319 逆向与Bof实验
1 实验内容
- 本次实验以可执行文件pwn1为例,将对pwn1进行反汇编的基础上进行功能上的解读,并进行缓冲区溢出攻击
- 可执行文件pwn1的正常流程是主函数调用foo函数完成字符串的录入和对录入字符串的重复输出,我们首先通过修改文件pwn1使其跳过foo函数转而执行getshell函数
- 利用其对于缓冲区溢出漏洞进行攻击,通过调整输入字符串来覆盖原有返回地址,使程序执行我们想要其执行的函数getshell
2 实验步骤
- 首先对于目标文件进行反汇编处理,输入命令
objdump -d mypwn | more
可以看到结果如下
- 忽略掉其中与功能无关的部分,将整个反汇编代码浏览一遍,我们可以发现这个代码主要分成三部分,主函数,以及两个
子函数foo
和子函数getShell
- 首先从主函数的汇编代码来看,这个函数的功能十分简单,其中
call 8048491
就是调用函数foo,之后程序结束
- 之后我们来看看
函数foo
的汇编代码部分,该函数实现了字符串的录入功能,其中汇编代码sub $0x38,%esp
就是为字符串所预留出的寄存器空间,但是在不对缓冲区进行保护的情况下,我们就可以通过录入过长的字符串,而覆盖掉本在堆栈中的返回地址,从而达到我们想要实现的目的,实现缓冲区溢出攻击
- 之后开始修改可执行文件中的机器码,让其可以按照我们想要的结果来运行,首先我们可以将主函数中
call指令
中的地址修改为getShell代码段地址,来看看getShell函数功能,用vim编辑器十六进制打开,并找到我们想修改的部分(详见所附操作指令)
- 之后我们开始尝试进行缓冲区溢出攻击,来使程序达成同样的效果
- 输入一串长字符串,直到程序反馈寄存器错误
- 由反馈的结果来看eip中的地址已经变成了0x39393939即被四个9所覆盖,我们就需要调节我们所录入的字符串,并且观察到底是字符串中的哪几位覆盖住了返回地址即可
- 由上一步我们可以基本可以确定覆盖住返回地址的四位字符正是字符串中的3456四位
- 之后我们需要将字符串中的3456四位修改成getshell的内存地址0804847d,由上几步我们大致可以确定在计算机内部的字节顺序,注意修改字节顺序后我们只需将其新的字符串键入即可
- 因为键盘上无法直接键入
\x7d
等十六进制数,因此我们先将其重定向至文件input中,之后通过管道将input文件中的内容作为输入来运行程序
3 shellcode注入
- 我们可以通过写c语言程序或者直接写汇编程序两种方式来获得我们的shellcode,这里我们采用第二种方式
- 首先编写shellcode的汇编代码
- 之后通过反汇编得到其机器码组成,将其中的机器码摘出来就是我们需要使用的部分了
- 首先做好准备工作,为了防止此类攻击,如今的计算机操作系统已经增加了许多保护措施,例如保护堆栈,使堆栈不可执行,又例如每一次生成代码的堆栈地址随机,来使得我们无法通过多次尝试来搜寻准确的返回地址,所以我们在准备阶段我们将这些保护功能都关闭(如果
execstack
显示command not found
可以尝试apt-get install prelink
)
- 构造注入字符串一般有两种策略,一是
retaddr+nop+shellcode
二是nop+shellcode+retaddr
我们先把retaddr用数字5319来代替
- 之后我们将文件执行挂在后台,打开另一个终端查看当前进程的进程号对其进行跟踪
- 使用断点调试,观察注入的shellcode的地址所在
- 观察可以看出shellcode的地址应该就是0xffffd330之后的一段区间,所以将返回地址修改成这段区间中的数值即可,修改后写入即可看到最后注入成功
4 其他
- vim相关
-
%!xxd
将文件显示变为十六进制模式
-
%!xxd -r
将十六机制模式转回原格式
- 在命令行模式下输入
/
即为查找,例如搜寻我们想要找到的e8 d7
段,只需输入/e8 d7
- 将文件转成十六进制模式下修改后要转回原格式才进行保存
- 其他
-
Perl
是一门解释型语言,不需要预编译,可以在命令行上直接使用