**郑重声明:**本文所涉安全技术仅限用于合法研究与学习目的,严禁任何形式的非法利用。因不当使用所导致的一切法律与经济责任,本人概不负责。任何形式的转载均须明确标注原文出处,且不得用于商业目的。
🔋 点赞 | 能量注入 ❤️ 关注 | 信号锁定 🔔 收藏 | 数据归档 ⭐️ 评论| 保持连接💬
🌌 立即前往 👉 🚀
▶ 信息收集
▶ 漏洞检测
▶ 初始立足点 ➢ 查找漏洞的公共利用 ➢ 缓冲区溢出攻击原理🔥🔥🔥
▶ 权限提升
▶ 横向移动
▶ 报告/分析
▶ 教训/修复
目录
[1.1 缓冲区溢出漏洞](#1.1 缓冲区溢出漏洞)
[1.1.3 缓冲区溢出攻击原理](#1.1.3 缓冲区溢出攻击原理)
[1.1.3.1 缓冲区溢出概述](#1.1.3.1 缓冲区溢出概述)
[1.1.3.2 缓冲区溢出的核心攻击目标](#1.1.3.2 缓冲区溢出的核心攻击目标)
[1.1.3.3 攻击原理:篡改"回家地址"](#1.1.3.3 攻击原理:篡改“回家地址”)
[1.1.3.4 缓冲区溢出攻击图例](#1.1.3.4 缓冲区溢出攻击图例)
[1.1.3.5 攻击原理演变](#1.1.3.5 攻击原理演变)
[1.1.3.6 典型攻击场景:JMP ESP技术](#1.1.3.6 典型攻击场景:JMP ESP技术)
[1.1.3.7 安全启示](#1.1.3.7 安全启示)
[1.1.4 缓冲区溢出攻击流程详解](#1.1.4 缓冲区溢出攻击流程详解)
[1.1.4.1 触发溢出](#1.1.4.1 触发溢出)
[1.1.4.2 覆盖返回地址(控制EIP)](#1.1.4.2 覆盖返回地址(控制EIP))
[1.1.4.3 注入Payload与NOP滑块](#1.1.4.3 注入Payload与NOP滑块)
[1.1.4.4 选择返回地址指令](#1.1.4.4 选择返回地址指令)
[1.1.4.5 攻击修改与调整注意事项](#1.1.4.5 攻击修改与调整注意事项)
[1.1.4.6 具体攻击过程示意](#1.1.4.6 具体攻击过程示意)
[欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论](#欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论)
1.修改漏洞利用脚本
1.1 缓冲区溢出漏洞
内存损坏漏洞利用(如缓冲区溢出 )是相对复杂且难以修改的。这类漏洞利用的修改通常涉及:
🔍 理解高级缓冲区溢出理论
⚙️ 交叉编译二进制文件
🛠️ 修改和更新内存损坏漏洞
本文以缓冲区溢出漏洞作为示例。
1.1.3 缓冲区溢出攻击原理
1.1.3.1 缓冲区溢出概述
本节通过一个简单的C语言示例,直观地演示栈缓冲区溢出的发生过程、原理及其被攻击利用的关键步骤。
💻 漏洞代码示例
以下是关于**strcpy函数(** 用于字符串复制的函数**)**及其引发的典型缓冲区溢出漏洞的总结:
| 方面 | 关键说明 |
|---|---|
| 函数作用 | 将源字符串 (第二个参数)完整复制 到目标缓冲区(第一个参数)。 |
| 根本问题 | 不执行任何边界检查 ,完全无视目标缓冲区的实际容量。 |
| 危险本质 | 若源字符串长度 > 目标缓冲区大小(64字节),则发生 "缓冲区溢出"。 |
| 直接后果 | 超出的字符会覆盖相邻内存区域,破坏栈上的关键数据(如函数返回地址)。 |
| 潜在风险 | 可导致程序崩溃 、行为异常 ,或被精心构造的攻击数据利用,以劫持程序执行流程。 |
| 安全建议 | 避免使用 strcpy;改用安全函数(如 strncpy、snprintf)或始终手动验证输入长度。 |
结论 :
strcpy是 C 语言中一个典型的不安全函数 ,其设计缺陷使它成为栈缓冲区溢出漏洞的常见源头。
1.1.3.2 缓冲区溢出的核心攻击目标
📍 EIP/RIP:程序执行的"导航仪"
| 寄存器 | 架构 | 作用 | 类比 |
|---|---|---|---|
| EIP (Extended Instruction Pointer) | x86 (32位) | 存储下一条要执行的指令的内存地址 | 像汽车导航的当前光标,始终指向下一步要走的路 |
| RIP (Return Instruction Pointer) | x86-64 (64位) | 同上,64位版本 | 同上,64位系统中的"导航光标" |
关键机制:
-
函数调用时,
call指令将返回地址 (函数执行完后应返回的位置)压入栈中。 -
函数结束时,
ret指令从栈中弹出该地址 ,并加载到EIP/RIP中。 -
CPU严格按EIP/RIP指向的地址取下一条指令执行。
简单说:EIP/RIP是CPU的"眼睛",它看向哪里,程序就执行到哪里。
🔄 ret指令:函数返回的"传送门"
ret指令的执行过程:
1. 从当前ESP指向的栈顶 → 弹出4/8字节数据(这就是返回地址)
2. 将该数据 → 载入EIP/RIP寄存器
3. CPU立即跳转到EIP/RIP指向的新地址开始执行
形象比喻:
栈顶的返回地址是一张写有"回家地址"的纸条
ret指令是出租车司机:他拿起纸条(弹出栈),按照上面的地址(加载到EIP/RIP),把你送过去(跳转执行)
1.1.3.3 攻击原理:篡改"回家地址"
当缓冲区溢出发生时:
正常情况:
栈布局:[局部变量buffer][保存的EBP][返回地址(正确的家)]...
函数返回时:ret取出"正确的家"地址 → 安全返回
被攻击时:
栈布局:[AAAA...恶意代码][被覆盖的EBP][恶意地址(攻击者伪造)]...
函数返回时:ret取出"恶意地址" → 跳转到攻击者指定的地方
攻击者攻击过程:
-
溢出填充 :用输入数据填满
buffer,并继续向后覆盖(向高地址、栈底方向) -
精确覆盖 :用精心计算的恶意地址覆盖原返回地址(要精准覆盖)
-
放置代码 :在
buffer中提前放入恶意机器代码(shellcode) -
触发跳转 :函数执行
ret时,EIP/RIP被改为恶意地址 -
执行控制 :CPU跳转到恶意地址执行(通常指向
buffer中的shellcode)
🧭 EBP与ESP在攻击中的角色
| 寄存器 | 存储内容 | 在攻击中的作用 |
|---|---|---|
| ESP (栈指针) | 当前栈顶地址(如0x7FFFFFFC) |
攻击常利用JMP ESP指令跳转到栈中执行shellcode |
| EBP (基址指针) | 当前栈帧基址(如0x7FFFFFF8) |
被溢出数据覆盖后,可能破坏栈帧链,影响程序稳定性 |
关键内存布局(发生溢出时):
高地址(栈底)
├─────────────────────────┤
│ 参数区域 │
├─────────────────────────┤
│ 返回地址 ← 被覆盖! │ ← 返回地址被覆盖后跳到恶意代码执行地址
├─────────────────────────┤ ← EBP 指向
│ 保存的EBP ← 可能被覆盖 │
├─────────────────────────┤
│ buffer[64] │ ← 从这里开始溢出(向高地址方向)
│ [shellcode] │ ← 攻击代码通常放在这里
├─────────────────────────┤ ← ESP 指向
低地址(栈顶)
1️⃣ 输入超长数据 → 填满buffer并继续写入
2️⃣ 覆盖返回地址 → 改为指向恶意代码的地址
3️⃣ 函数执行ret → 恶意地址载入EIP/RIP
4️⃣ CPU跳转执行 → 执行攻击者预设的shellcode
5️⃣ 获得控制权 → 可能开启shell、提升权限等
1.1.3.4 缓冲区溢出攻击图例
以下是栈在三种不同输入情况下的状态对比,直观展示缓冲区溢出如何发生及其攻击具体过程。
| 状态 | 栈内存图示 (简化) | 用户输入 | 对缓冲区的影响 | 返回地址状态 | 结果 |
|---|---|---|---|---|---|
| ① 初始化 | [ 64字节缓冲区空间 ] [正确返回地址] |
无 | 缓冲区保留空间 | ✅ 正确保存 | 函数正常执行并返回 |
| ② 安全输入 | [32字节数据] [空余32字节] [正确返回地址] |
32个字符 | 仅填充一半缓冲区 | ✅ 未受影响 | 函数正常返回 |
| ③ 溢出攻击 | [64字节全满+16字节溢出] [被覆盖的返回地址] |
80个'A' (0x41) |
超出容量,发生溢出 | ❌ 被覆盖为0x41414141 |
程序崩溃或跳转到非法地址 |
1.1.3.5 攻击原理演变
攻击者不会仅仅让程序崩溃,而是会精心构造攻击数据:
| 攻击阶段 | 操作 | 目标 |
|---|---|---|
| 基础溢出 | 用'A'等字符填充,覆盖返回地址为0x41414141 |
测试漏洞存在,导致程序崩溃 |
| 真实攻击 | 用有效内存地址 替换'A',覆盖返回地址 |
控制程序执行流程 |
| 代码注入 | 在溢出数据中插入shellcode(恶意机器代码) | 执行任意命令,控制目标系统 |
1.1.3.6 典型攻击场景:JMP ESP技术
-
寻找指令 :在系统库中找到一个
JMP ESP指令的地址(这条指令意为"跳转到ESP寄存器指向的位置")。 -
构造载荷 :将返回地址覆盖为**
JMP ESP指令的地址**。 -
放置代码 :在溢出数据中紧随返回地址之后放置shellcode。
-
触发执行:
-
函数返回时,
ret指令将JMP ESP地址载入EIP/RIP -
CPU执行
JMP ESP,跳转到ESP指向的位置 -
此时ESP恰好指向shellcode的起始处
-
CPU开始执行shellcode,攻击者获得系统控制权
-
攻击载荷结构示例:
[ 缓冲区内 ][ shellcode ][ 填充数据 ][ JMP ESP地址 ]
↑ ↑ ↑
缓冲区起始 填满剩余空间 覆盖原返回地址
🛡️ 关键安全认知
-
溢出≠崩溃 :缓冲区溢出不一定会导致立即崩溃,而是为攻击者提供了篡改程序流程的机会。
-
地址是关键:攻击者需要精确计算或猜测内存地址,现代防御技术(如ASLR)通过随机化地址增加攻击难度。
-
shellcode是武器:攻击者注入的恶意代码通常体积小、功能强,可直接在目标系统上执行任意操作。
核心要点:理解栈缓冲区溢出的三种状态,是从理论认知到实际攻击利用的关键一步。攻击者通过将简单的溢出漏洞转化为精准的流程劫持,最终实现对系统的完全控制。
1.1.3.7 安全启示
返回地址是栈缓冲区溢出攻击的"王冠上的宝石" 。保护返回地址不被篡改,是防御此类攻击的第一道防线。现代操作系统通过ASLR(地址随机化) 、栈保护符(Canary) 等技术,正是为了增加攻击者预测和覆盖正确地址的难度。
1.1.4 缓冲区溢出攻击流程详解
🔄 四步攻击流程
1.1.4.1 触发溢出
创建超出缓冲区容量的数据,覆盖相邻内存区域(返回地址、函数指针、局部变量等)。
关键 :提供的数据必须超过缓冲区固定大小,才能产生溢出效果。
1.1.4.2 覆盖返回地址(控制EIP)
精确计算偏移量 ,用恶意地址覆盖栈上的返回地址,从而控制EIP/RIP。
| 操作 | 目标 | 结果 |
|---|---|---|
| 填充缓冲区 | 到达返回地址在栈中的位置 | 建立溢出基础 |
| 计算偏移量 | 确定从缓冲区起始到返回地址的字节距离 | 精准定位 |
| 覆盖地址 | 用攻击者控制的地址替换原返回地址 | 劫持程序流程 |
1.1.4.3 注入Payload与NOP滑块
在缓冲区中插入恶意代码(Payload),前面可添加NOP滑块以提高成功率。
[ NOP滑块 (可选) ][ Shellcode/Payload ][ 填充数据 ][ 恶意返回地址 ]
↑ ↑ ↑ ↑
NOP指令 恶意机器代码 填满剩余空间 覆盖原返回地址
NOP滑块作用:
-
增加容错:即使返回地址计算稍有偏差,只要指向NOP滑块内任意位置,CPU都会"滑行"到Payload
-
简化定位:无需精确命中Payload起始地址
1.1.4.4 选择返回地址指令
选择合适的指令地址作为返回地址,常见的是JMP ESP:
-
寻找指令 :在目标程序或系统库中找到
JMP ESP指令的内存地址 -
覆盖地址:用该地址覆盖原返回地址
-
执行流程:
函数返回 → 执行ret指令 → EIP指向JMP ESP地址 → 执行JMP ESP → 跳转到ESP指向的位置 → ESP通常指向栈上紧随返回地址之后的位置 → 执行攻击者放置在该处的Payload
1.1.4.5 攻击修改与调整注意事项
在修改缓冲区漏洞利用的代码时,主要修改以下内容:
| 注意事项 | 具体操作 | 目的 |
|---|---|---|
| 修改缓冲区元素 | 调整payload中的文件路径、IP地址、端口、URL等 | 适应特定攻击目标 |
| 调整偏移量 | 重新计算缓冲区长度和偏移 | 确保精准覆盖返回地址 |
| 寻找返回地址 | 在本地克隆环境,使用调试器获取JMP ESP等指令的实际内存地址 | 提高攻击可靠性 |
| 修改Payload | 审查公开攻击代码 中的十六进制Payload,或插入自定义Payload | 避免使用潜在恶意代码,确保Payload功能符合需求 |
| 排除坏字符 | 避免在Payload中使用**空字节(\x00)**等可能截断字符串的控制字符 | 防止Payload被提前截断,确保完整性 |
🔍 坏字符示例
| 坏字符 | 十六进制 | 可能影响 |
|---|---|---|
| 空字节 | \x00 |
被解释为字符串终止符,截断Payload |
| 换行符 | \x0A |
可能被解释为输入结束 |
| 回车符 | \x0D |
可能影响某些输入处理 |
| EOF字符 | \x1A |
在某些上下文中表示文件结束 |
🧠 攻击成功的关键要素
-
精确计算:偏移量、缓冲区大小、内存地址
-
环境适配:Payload、返回地址需针对目标环境调整
-
字符过滤:避免使用目标程序可能特殊处理的字符
-
流程控制:确保从溢出到Payload执行的完整链条
核心要点 :缓冲区溢出攻击是精准的工程过程,每一步都需要精心计算和调整。从防御角度看,破坏其中任一环节即可有效防御此类攻击。
1.1.4.6 具体攻击过程示意
假设一个函数的栈布局如下(从高地址到低地址):
高地址 (栈底方向)
┌─────────────────┐
│ 函数参数 │
├─────────────────┤
│ 返回地址 │ ← **攻击目标:覆盖此处!**
├─────────────────┤
│ 保存的EBP │
├─────────────────┤ ← EBP指向这里
│ 局部变量2 │
├─────────────────┤
│ 局部变量1 │
├─────────────────┤
│ buffer[256] │ ← 缓冲区起始(地址如0x0ff8)
低地址 (栈顶方向)
攻击者构造的输入数据就像一个精心设计的恶意包裹,结构如下:
[填充数据][JMP ESP地址][NOP滑块][Payload][剩余填充...]
↑ ↑ ↑ ↑ ↑
填满缓冲区 覆盖返回地址 安全缓冲 恶意代码 填满剩余空间
📦 包裹各部分详解
| 部分 | 大小 | 作用 |
|---|---|---|
| 填充数据 | 精确计算 | 填满缓冲区,直到返回地址之前 |
| JMP ESP地址 | 4/8字节 | 指向JMP ESP指令的内存地址 |
| NOP滑块 | 可变长度(如100字节) | 0x90指令,CPU执行时"滑过" |
| Payload | 精炼代码 | 恶意机器指令(如开启shell) |
| 后续填充 | 按需 | 确保完全覆盖返回地址区域 |
🔄 攻击执行流程
正常流程:
函数调用 → 局部变量入栈 → 执行函数体 → 弹出返回地址 → 安全返回
被攻击流程:
1. 攻击者输入超长数据(如300字节)
2. 数据写入buffer[256]并溢出
3. 覆盖局部变量 → 覆盖保存的EBP → **覆盖返回地址**
4. 函数执行完毕,执行`ret`指令
5. CPU读取**被篡改的返回地址**(JMP ESP地址)
6. 跳转到JMP ESP指令处执行
7. JMP ESP使程序跳转到**ESP指向的位置**
8. 此时ESP恰好指向**NOP滑块或Payload起始处**
9. CPU"滑过"NOP指令,执行Payload
10. **攻击者获得系统控制权**
🎯 关键偏移量计算
攻击成功的核心是精确计算:
-
缓冲区起始地址 :如
0x0ff8 -
返回地址位置 :如
0x10f0 -
偏移量 :
0x10f0 - 0x0ff8 = 248字节攻击数据结构:
[0-247字节:填充数据] ← 填满248字节到达返回地址
[248-251字节:JMP ESP地址] ← 精准覆盖返回地址
[252字节开始:NOP+Payload] ← 放置在返回地址之后
欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论
每一份支持,都是我持续输出的光。感谢阅读,下一篇文章见。