20242405 2026-2027-1 《网络与系统攻防技术》实验1实验报告
20242405 2026-2027-1 《网络与系统攻防技术》实验1实验报告
1. 基础知识\
在本次实验中,可执行文件pwn1遵循Linux下的ELF格式,其结构包含ELF头、程序头表、节头表以及.text(代码)、.data(已初始化数据)、.bss(未初始化数据)等核心节区;程序运行时的栈帧结构由EBP(栈底指针)、ESP(栈顶指针)和EIP(指令指针,指向下一条待执行指令)协同维护,函数通过push
ebp、mov
ebp,esp建立新帧并用leave和ret恢复;由于x86架构采用小端序存储,数据的低位字节存放在低地址、高位字节存放在高地址;call指令(机器码e8)的操作数采用相对寻址,计算公式为"目标地址
= 下一条指令地址 + 偏移量",偏移量以补码形式小端序存储。
2.实验内容\
(1)手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
- (2)利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
- (3)注入一个自己制作的shellcode并运行这段shellcode。\
3.实验过程
-
任务一:
-
首先反汇编查看地址
-
{width="5.764583333333333in"
height="3.4493055555555556in"} -
{width="5.739583333333333in"
height="2.8333333333333335in"}
截图显示,getShell 函数的起始地址:0804847d,main 函数中调用 foo
的指令地址:80484b5,call 指令的机器码:e8 d7 ff ff ff,call
指令的下一条指令地址(即执行时 EIP 的值):80484ba。
call 指令的计算公式:偏移量 = 目标地址 - 下一条指令的地址
目标地址(getShell)= 0x0804847d
下一条指令地址 = 0x080484ba
计算:0x0804847d - 0x080484ba = -0x3d
结论:将原机器猫(e8 d7 ff ff ff)中的d7改为c3
进入vi进行更改:
{width="5.375in"
height="4.308333333333334in"}
-
反汇编查看:
-
{width="5.416666666666667in"
height="4.25in"} -
运行结果:
-
{width="5.466666666666667in"
height="0.875in"} -
成功的进入了shell
-
任务二
-
首先GDB 调试确定偏移量
-
{width="5.395833333333333in"
height="4.4375in"} -
截图显示,第 29~32 个字符覆盖了保存的 EBP,第 33~36
个字符覆盖了函数的返回地址(EIP)。所以缓冲区填充需要 32个字节(28字节
buf + 4字节 EBP),第 33~36 个字节就是要覆盖的返回地址位置。 -
构造payload,并进行注入攻击。
-
{width="5.333333333333333in"
height="2.5in"} -
成功拿到了shell。
-
任务三
-
首先关闭防御机制,为pwn1设置堆栈可执行,并关闭ASLR
-
再构造初始攻击载荷
-
{width="5.7659722222222225in"
height="1.9236111111111112in"} -
在一个终端进行攻击,另一个终端寻找地址
-
{width="5.141666666666667in"
height="0.6083333333333333in"} -
![C:/Users/syl/Desktop/新建文件夹/新建 DOCX 文档/图片 10.png图片
10]()
-
找到ret指令的地址,并设置断点
-
{width="5.7659722222222225in"
height="1.1416666666666666in"} -
找到了Shellcode 在内存中的真实起始地址是 0xffffd350。
-
生成最终的payload并进行攻击
-
{width="4.733333333333333in"
height="1.0583333333333333in"} -
{width="4.716666666666667in"
height="1.8583333333333334in"} -
成功拿到了shell\
4.问题及解决方案\
- 问题1:在任务二中,最初使用"32字节填充 +
4字节返回地址"构造Payload,导致程序反复报错崩溃。
-
- 问题1解决方案:调整Payload结构为"28字节A填充 + 4字节有效EBP地址 +
6个ret指令地址+ getShell地址"。保留有效EBP避免了 leave
阶段崩溃,且通过多个 ret
指令弹栈消耗掉多余字节,解决16字节栈对齐问题,最终成功获取Shell。
- 问题2:注入攻击成功后,终端光标卡住闪烁,但并未如预期般弹出 # 或
$ 提示符,让人误以为攻击失败。
- 问题2解决方案:实验通过管道 (cat input; cat) | ./pwn1
将Payload输入程序。Shell启动后,其标准输入是一个非交互式的管道,因此它默认不显示命令提示符。但此时Shell已经成功获取,不需要等待提示符。直接在卡住的光标处盲打输入命令(如
whoami、ls)并回车,Shell能够正常执行命令并回显结果,以此验证攻击成功。 -
- 问题3:在任务三第一次构造Payload时,采用了"nop + shellcode +
retaddr"的布局,程序在Shellcode执行过程中崩溃。
- 问题3解决方案:更改Payload布局为"anything + retaddr + nops +
shellcode"(RNS模式),即将Shellcode放置在返回地址之后的高地址区域,使栈顶向上增长时不再与代码区重叠。重新注入后成功获取Shell。
- 问题4:为了调试Shellcode地址,在另一终端运行 (cat inputshellcode;
cat) | ./pwn1,但执行 ps -ef | grep pwn1
却找不到该进程,导致无法用GDB attach调试。
- 问题4解决方案:该调试Payload末尾包含了 \x0a(回车符),导致 gets
函数读取后程序不再阻塞等待输入,直接执行到 ret
指令并跳转到占位地址,程序瞬间发生段错误(Segmentation
fault)并退出,因此 ps 查不到进程。 因此重新生成一个去掉 \x0a
的调试Payload(如 inputshellcode_debug)。运行后 gets
会因等待输入而阻塞,程序保持挂起状态,此时再使用 ps
即可成功找到进程号,并顺利在GDB中进行 attach 和内存地址定位。\
5.学习感悟、思考等\
(1)AI的辅助十分强大,几乎所有问题都可以通过询问Ai得到解决
- (2)每一步都需要进行验证,否则很可能出现命令没有运行成功,接下来的实验出现问题。

{width="5.764583333333333in"
{width="5.739583333333333in"
{width="5.416666666666667in"
{width="5.466666666666667in"
{width="5.395833333333333in"
{width="5.333333333333333in"
{width="5.7659722222222225in"
{width="5.141666666666667in"
{width="5.7659722222222225in"
{width="4.733333333333333in"
{width="4.716666666666667in"
浙公网安备 33010602011771号