❽⁄₇ ⟦ OSCP ⬖ 研记 ⟧ 修改漏洞利用脚本 ➱ 深入剖析JMP ESP原理

**郑重声明:**本文所涉安全技术仅限用于合法研究与学习目的,严禁任何形式的非法利用。因不当使用所导致的一切法律与经济责任,本人概不负责。任何形式的转载均须明确标注原文出处,且不得用于商业目的。

🔋 点赞 | 能量注入 ❤️ 关注 | 信号锁定 🔔 收藏 | 数据归档 ⭐️ 评论| 保持连接💬

🌌 立即前往 👉 🚀

▶ 信息收集

▶ 漏洞检测

初始立足点 ➢ 深入剖析JMP ESP原理 ➢🔥🔥🔥

▶ 权限提升

▶ 横向移动

▶ 报告/分析

▶ 教训/修复

目录

1.ESP寄存器在函数返回时的特殊位置

[1.1 复习核心载荷结构](#1.1 复习核心载荷结构)

[1.1.1 再次复习 Python 漏洞利用代码 (42928.py)](#1.1.1 再次复习 Python 漏洞利用代码 (42928.py))

[1.1.1.1 核心载荷分析](#1.1.1.1 核心载荷分析)

[1.1.2.2 POST请求构造](#1.1.2.2 POST请求构造)

[1.2 核心问题剖析](#1.2 核心问题剖析)

[1.2.1 完整的原理剖析](#1.2.1 完整的原理剖析)

[1.2.1.1 构造恶意数据](#1.2.1.1 构造恶意数据)

[1.2.1.2 栈内存状态变化图](#1.2.1.2 栈内存状态变化图)

[1.2.1.3 详细执行流程](#1.2.1.3 详细执行流程)

[1.2.2 如何找到JMP ESP指令地址?](#1.2.2 如何找到JMP ESP指令地址?)

方法1:在系统DLL中搜索

方法2:使用已知通用地址

方法3:通过调试器获取

[1.2.3 执行时间线与ESP变化(重要)](#1.2.3 执行时间线与ESP变化(重要))

[1.2.3.1 详细的内存布局图](#1.2.3.1 详细的内存布局图)

[1.2.3.2 执行流程验证](#1.2.3.2 执行流程验证)

[1.2.3.3 形象比喻](#1.2.3.3 形象比喻)

①快递中转站

②地铁换乘系统

[1.2.3.4 技术细节:寄存器状态变化](#1.2.3.4 技术细节:寄存器状态变化)

[1.2.4 防御视角:如何阻止这种攻击](#1.2.4 防御视角:如何阻止这种攻击)

[1.3 总结核心要点](#1.3 总结核心要点)

[欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论](#欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论)


1.ESP寄存器在函数返回时的特殊位置

本例以Sync Breeze Enterprise**(这是一个文件管理同步软件)** 为目标,对其漏洞利用分析与修改,并最终利用,利用缓冲区溢出漏洞,类似漏洞编号:CVE-2017-14980。

之前的一系列文章写的是,如果寻找漏洞利用的脚本,并利用缓冲区溢出原理加以利用,按照实际测试环境的情况修改脚本后编译为可执行文件,最终拿到反向shell。主要要非常了解栈结构、出入栈原理,以及shellcode的结构等。但,这里有一个核心问题不知道你们有没有想过:

"为什么覆盖了返回地址后,当执行漏洞利用文件时,返回地址指向的不是shellcode的地址,而是JMP ESP指令?"

② "为什么返回地址指向JMP ESP指令,就能执行我们的shellcode?"

至少,我脑袋中想到了这个很细节、但有非常核心的问题!那么,我们试试把它弄懂。


1.1 复习核心载荷结构

1.1.1 再次复习 Python 漏洞利用代码 (42928.py)

在此复习42928.py源代码,开始进行分析。


1.1.1.1 核心载荷分析

重点看漏洞利用脚本中的HTTP服务器模块,通过构造特殊的 POST请求 触发缓冲区溢出。以下是核心代码段的解读:

代码片段 说明
offset = "A" * 780 创建780个字符"A"作为偏移量填充,用于覆盖缓冲区直至返回地址位置
JMP_ESP = "\x83\x0c\x09\x10" 跳转指令 ,指向内存地址 0x10090c83(JMP ESP),用于重定向执行流。 这里具体的是,在偏移量780处,使用内存地址为0x10090c83的JMP ESP指令覆盖指令指针。
shellcode = "\x90"*16 + msf_shellcode Shellcode构造 :16个NOP指令(\x90)作为滑道 + 实际负载代码 这个shellcode的作用是执行攻击者想要运行的恶意操作,比如:打开反向Shell连接、执行任意命令等。

结构

python 复制代码
[缓冲区填充] → [覆盖返回地址,跳转至JMP ESP地址] → [执行NOP滑道] → [运行Shellcode]

1.1.2.2 POST请求构造

漏洞利用通过HTTP POST的请求体携带来发送恶意载荷:

POST请求结构如下:

XML 复制代码
POST /login HTTP/1.1
Host: <目标IP>
Content-Type: application/x-www-form-urlencoded
Content-Length: <长度>

username=<偏移量><JMP_ESP><NOP滑道><Shellcode>&password=A

1.2 核心问题剖析

"++为什么返回地址指向JMP ESP指令,就能执行我们的Payload?++"

1.2.1 完整的原理剖析

1.2.1.1 构造恶意数据
复制代码
攻击数据结构:
[低地址] [填充数据] [JMP ESP地址] [NOP滑块] [Payload] [剩余填充] [高地址]
         ↑              ↑              ↑         ↑
     填满缓冲区    覆盖返回地址    安全缓冲    恶意代码
1.2.1.2 栈内存状态变化图
复制代码
函数返回前栈布局:
高地址
├─────────────────┤
│    Payload      │ ← 实际在返回地址之后
├─────────────────┤
│    NOP滑块      │
├─────────────────┤ ← ESP移动到这里(ret执行后)
│  JMP ESP地址    │ ← 返回地址(被覆盖)
├─────────────────┤ ← ESP初始位置(ret执行前)
│    填充数据      │
│   (缓冲区)     │ ← 类似780个A来做填充
低地址
1.2.1.3 详细执行流程

为什么这样设计?------ 解决Payload地址不确定问题

问题根源

  • 栈地址可能变化(不同系统、不同运行环境)

  • 攻击者无法精确知道Payload在目标栈中的确切地址(解决的核心痛点)

  • 直接硬编码Payload地址成功率极低

🧩 JMP ESP的巧妙之处!!!

复制代码
固定地址问题解决方案:
┌─────────────────────────┬─────────────────────────────┐
│       直接跳转方案       │        JMP ESP间接方案       │
├─────────────────────────┼─────────────────────────────┤
│ 需要知道Payload的精确地址 │ 只需要知道JMP ESP指令的地址   │
│ 地址随栈变化而变化        │ 地址在系统DLL中固定(无ASLR时)│
│ 成功率低                 │ 成功率高                     │
└─────────────────────────┴─────────────────────────────┘

1.2.2 如何找到JMP ESP指令地址?

方法1:在系统DLL中搜索
复制代码
# 示例:在Windows DLL中搜索JMP ESP指令(机器码FF E4)
# 使用调试器或专用工具搜索
JMP_ESP_ADDRESS = 0x75CB52CB  # kernel32.dll中的地址
方法2:使用已知通用地址
复制代码
常见系统JMP ESP地址(无ASLR时):
• Windows XP SP3: 0x7C86467B (kernel32.dll)
• Windows 7 SP1: 0x75C8E2E4 (kernel32.dll)
• Linux (特定版本): 可变,通常需要自定义
方法3:通过调试器获取
复制代码
1. 在目标环境运行调试器(如OllyDbg、GDB)
2. 加载目标程序
3. 搜索指令 "JMP ESP" 或机器码 "FF E4"
4. 记录找到的地址

1.2.3 执行时间线与ESP变化(重要)

布局方式 内存结构 执行结果 为什么
❌ 错误布局 [填充][恶意代码][JMP ESP地址] 攻击失败 ESP指向JMP ESP地址之后,但那里没有代码
✅ 正确布局 [填充][JMP ESP地址][恶意代码] 攻击成功 ESP指向恶意代码开始处
1.2.3.1 详细的内存布局图

正确布局(攻击成功)

复制代码
低地址
├─────────────────┤ ← 缓冲区起始
│   AAAA...AAAA   │ ← 填充数据 (填满缓冲区)
├─────────────────┤ ← 原返回地址位置
│   0x75CB52CB    │ ← JMP ESP指令地址 (4字节)
├─────────────────┤ ← ESP执行ret后指向这里!
│   0x90 0x90...  │ ← NOP滑块 (可选,增加容错)
├─────────────────┤
│   shellcode     │ ← 恶意代码 (Payload)
│   (恶意指令)     │
├─────────────────┤
│   更多填充...    │ ← 如果需要
└─────────────────┘
高地址

1.2.3.2 执行流程验证
复制代码
1. ret执行前: ESP → 0x75CB52CB (在栈中)
2. ret执行: 
   - EIP = 0x75CB52CB (JMP ESP指令地址)
   - ESP = ESP + 4 → 指向NOP滑块开始处
3. 执行JMP ESP:
   - EIP = ESP → 指向NOP滑块开始处
4. 执行NOP滑块 → 滑向shellcode
5. 执行shellcode → 攻击成功!

1.2.3.3 形象比喻
①快递中转站
  • 你(攻击者):要寄送一个秘密包裹(Payload)

  • 收件人(目标程序):住在经常搬家的公寓(栈地址变化)

  • 快递公司(程序执行流):必须把包裹送到正确地址

传统方法的困境

复制代码
你的计划:直接告诉快递公司"送到A公寓201室"
问题:收件人可能已经搬到B公寓302室
结果:包裹送错地方,任务失败 ❌

JMP ESP方案的巧妙

复制代码
你的新计划:
1. 告诉快递公司"先送到中央中转站"(JMP ESP地址)
2. 在中转站,有一个智能机器人(JMP ESP指令)
3. 机器人会问:"包裹接下来应该送到哪里?"
4. 快递员(ESP寄存器)回答:"哦,收件人刚刚告诉我,他现在在C公寓105室"
5. 机器人立即把包裹送到C公寓105室(ESP指向的地址)
6. 包裹准确送达,任务成功 ✅
地铁换乘系统
  • 你(CPU):要去朋友家(执行正常代码)

  • 攻击者:想把你引导到秘密基地(执行Payload)

  • 地铁系统(程序执行流):有固定线路

正常路线(无攻击)

复制代码
你家 → 乘坐2号线 → 在**人民广场站**换乘 → 乘坐8号线 → 朋友家

攻击者的篡改

攻击者知道:

复制代码
1.人民广场站(JMP ESP地址) 的位置固定

2.从2号线换乘时,你会自动走到8号线站台(ESP指向的位置)

3.他可以在8号线站台放置引导员(NOP/Payload)

攻击实施

复制代码
1. 攻击者修改路线图:把"人民广场站"标记为必须换乘站
2. 你到达人民广场站(JMP ESP地址)
3. 车站广播(JMP ESP指令):"请前往您当前所在的站台"
4. 你已经在8号线站台(ESP指向NOP/Payload)
5. 站台上的引导员(NOP)带你到秘密基地(Payload)

为什么这招高明?

  • 攻击者无需知道秘密基地的确切地址

  • 他只需要知道人民广场站的固定位置

  • 地铁系统的换乘逻辑(ret指令) 会自动把你带到正确站台

  • 8号线站台总是在人民广场站之后(ESP总指向返回地址后)

为什么这个方案可靠?

  • 中转站地址固定:JMP ESP指令在系统DLL中,地址不变

  • 总是知道最新地址:ESP寄存器始终指向正确位置

  • 总是可用:JMP ESP指令在系统启动时就存在

📊 攻击成功的关键要素表

要素 要求 为什么重要
JMP ESP地址 必须准确且可执行 这是攻击的"跳板",必须可靠
ESP指向 必须指向NOP/Payload 确保跳转后能执行到恶意代码
缓冲区大小 必须精确计算偏移 确保JMP ESP地址覆盖正确位置
Payload位置 必须在返回地址之后 这样ESP才会指向它
无坏字符 避免\x00等特殊字符 防止数据被截断

1.2.3.4 技术细节:寄存器状态变化
复制代码
函数返回时刻的寄存器状态:
      执行ret前                执行ret后
EIP: 指向ret指令         EIP: JMP ESP指令地址
ESP: 指向返回地址        ESP: 返回地址+4(指向NOP开始)
EBP: 可能被覆盖          EBP: 可能已被破坏

关键计算:
返回地址偏移 = 缓冲区大小 + EBP大小(4字节)
Payload偏移 = 返回地址偏移 + 4(JMP ESP地址大小)

1.2.4 防御视角:如何阻止这种攻击

防御技术 如何阻止JMP ESP攻击 效果
ASLR 随机化系统DLL加载地址 JMP ESP地址难以预测
DEP/NX 标记栈为不可执行 即使跳转到Payload也无法执行
栈Canary 检测返回地址是否被修改 在ret执行前就发现攻击
CFG 控制流保护,限制间接跳转 阻止跳转到非常用地址

1.3 总结核心要点

  1. 间接跳转原理 :不直接跳转到Payload,而是通过固定指令中转

  2. ESP的关键作用自动指向返回地址之后,提供动态跳转目标

  3. 地址稳定性:JMP ESP指令在系统DLL中,地址相对固定

  4. 攻击链完整性:每个环节必须精确计算,环环相扣

最终答案

因为JMP ESP指令是固定的中转站 ,而ESP寄存器是智能的向导,它总是在正确的时间指向正确的位置。攻击者利用这个系统特性,让不可预测的栈地址问题通过可预测的系统指令解决,从而可靠地执行Payload。

📊 不同类型攻击的布局对比

攻击类型 内存布局 适用场景
直接跳转 [填充][shellcode地址][shellcode] 知道shellcode确切地址(概率极低)
JMP ESP [填充][JMP ESP地址][NOP][shellcode] 栈地址随机,但系统库地址固定(本例)
寄存器跳转 [填充][JMP EAX地址][shellcode] EAX指向shellcode

欢迎❤️ 点赞 | 🔔 关注 | ⭐️ 收藏 | 💬 评论

每一份支持,都是我持续输出的光。

相关推荐
中科固源15 小时前
应用层|低空应用安全的 “精工锻造者”,中科数测以多工具矩阵赋能应用从开发到运维的全周期安全
安全·网络安全·低空
白帽子凯哥哥1 天前
转行网络安全学习计划与报班建议
学习·安全·web安全·网络安全·渗透测试·漏洞挖掘·网安培训
logic_51 天前
VLAN的配置
网络安全
介一安全1 天前
【Frida Android】实战篇15:Frida检测与绕过——基于/proc/self/maps的攻防实战
android·网络安全·逆向·安全性测试·frida
躺柒1 天前
读捍卫隐私07智能家居
信息安全·智能家居·数据安全·隐私·隐私保护·互联网隐私保护
小白勇闯网安圈1 天前
upload、very_easy_sql、i-got-id-200
python·网络安全·web
logic_51 天前
DHCP+DNS
网络安全·udp·信号处理
爱浦路 IPLOOK1 天前
高校5G实验室助力人才培养的五种创新模式
计算机网络·5g·网络安全·可信计算技术
是毛毛吧1 天前
开发环境配置指南:解决 GitHub 连接超时与依赖下载失败的问题
网络·git·网络安全·docker·信息与通信