关联漏洞
标题:
Microsoft OLE 资源管理错误漏洞
(CVE-2025-21298)
描述:Microsoft OLE是美国微软(Microsoft)公司的一种面向对象的技术。 Microsoft OLE存在资源管理错误漏洞。攻击者利用该漏洞可以远程执行代码。以下产品和版本受到影响:Windows Server 2019 (Server Core installation),Windows Server 2022,Windows Server 2022 (Server Core installation),Windows 10 Version 21H2 for 32-bit Systems,Wi
描述
CVE-2025-21298
介绍
# 🛑 CVE-2025-21298 – Critical Zero-Click RCE in Microsoft Windows OLE
---
## 📌 Overview
* **📂 Component:** Microsoft Windows OLE (Object Linking and Embedding) – specifically in `ole32.dll`
* **🐞 Vulnerability Type:** Double-free memory corruption
* **📌 Function Affected:** `UtOlePresStmToContentsStm`
* **🔥 Severity:** CVSS 3.1 score **9.8** – Critical
* **📅 Patch Release:** January 2025 Microsoft Security Updates
* **📥 Attack Vector:** Specially crafted RTF file
* **⚠️ Interaction Required:** None (zero-click, triggered on preview)
* **🎯 Primary Targets:** Outlook users, but also Word or any OLE-capable application
---
## ⚙️ Technical Details
1. **Double-Free Bug**
* When processing an RTF file containing certain embedded OLE objects, `ole32.dll` fails to properly manage memory cleanup.
* The `pstmContents` pointer is freed twice under specific conditions, leading to heap corruption.
2. **Exploitation Path**
* An attacker crafts a malicious RTF containing payload data that manipulates OLE structures.
* When the victim **previews** the email in Outlook, the RTF renderer calls OLE functions.
* The double-free allows overwriting heap metadata or function pointers.
* Attacker-controlled code is executed in the context of the user — potentially SYSTEM if chained with privilege escalation.
3. **Why It’s Dangerous**
* **Zero-click** → user doesn’t need to open the file manually.
* **Email-borne** → can be mass-exploited.
* **Widespread Reach** → affects almost all supported Windows versions.
---
## 💻 Affected Systems
* **Windows 10:** Versions 1507 → 22H2
* **Windows 11:** Up to 24H2
* **Windows Server:** 2008, 2008 R2, 2012, 2012 R2, 2016, 2019, 2022, 2025
---
## 🛡️ Mitigation
1. **Install Microsoft’s January 2025 patch** — fully fixes the issue.
2. If patching is delayed:
* 📜 Configure Outlook to display all emails as **plain text**.
* 📦 Block `.rtf` attachments at the mail gateway or via endpoint policies.
* 🔒 Disable preview pane for untrusted messages.
---
## 👀 Detection & Monitoring
* **Endpoint:** Look for processes loading `ole32.dll` when handling `.rtf` files from untrusted sources.
* **Network:** Monitor inbound email traffic for `.rtf` attachments with abnormal OLE object streams.
* **Security Tools:** Use EDR rules or Sigma detections for RTF OLE exploitation patterns.
---
## 📊 Risk Summary Table
| 📝 Aspect | 📌 Details |
| ------------------ | --------------------------------------------- |
| Vulnerability Type | Zero-click RCE via OLE double-free |
| Severity | 🔥 CVSS 9.8 – Critical |
| Attack Vector | Previewing crafted RTF in Outlook / Word |
| Impact | 🖥️ Remote code execution |
| Affected Systems | Windows 10, 11, Server 2008–2025 |
| Fix | 🛡️ January 2025 Patch |
| Workarounds | Block RTF, plain-text emails, disable preview |
---
## 🧠 Exploit Chain Diagram (Text Form)
```
📩 Attacker sends crafted RTF email
↓
📬 Victim receives email in Outlook
↓
👀 Victim previews message (no click required)
↓
🧩 RTF renderer calls OLE32.dll → double-free in UtOlePresStmToContentsStm
↓
💥 Memory corruption → payload execution
↓
🎯 Attacker gains code execution on target system
```
---
## 🕷️ vulnerability:
The vulnerability is located in `ole32.dll!UtOlePresStmToContentsStm`. The purpose of the function is ti convert data in an **"OlePres"** stream within an OLE storage into appropriately formatted data and insert it into the **"CONTENTS"** stream in the same storage. It receives an IStorage pointer to a storage object and three rather unimportant arguments.
Below we can see the implementation of the function with a diff from the Jan 2025 patch:
```json
__int64 __fastcall UtOlePresStmToContentsStm(IStorage *pstg, wchar_t *puiStatus, __int64 a3, unsigned int *lpszPresStm)
{
struct IStorageVtbl *lpVtbl; // rax
int v7; // r14d
+ bool IsEnabled; // al
IStream *v10; // rcx
bool v11; // zf
struct IStorageVtbl *v12; // rax
int v13; // ebx
HRESULT v14; // eax
const wchar_t *v15; // rdx
IStream *pstmContents; // [rsp+40h] [rbp-19h] BYREF
IStream *pstmOlePres; // [rsp+48h] [rbp-11h] BYREF
tagFORMATETC foretc; // [rsp+50h] [rbp-9h] BYREF
tagHDIBFILEHDR hdfh; // [rsp+70h] [rbp+17h] BYREF
*lpszPresStm = 0;
lpVtbl = pstg->lpVtbl;
pstmContents = 0LL;
v7 = 1;
// Create a "CONTENTS" stream in the storage and store it into pstmContents
if ( (lpVtbl->CreateStream)(pstg, L"CONTENTS", 18LL, 0LL, 0, &pstmContents) )
return 0LL;
// Immediately release pstmContents, we're not going to be using it right now
(pstmContents->lpVtbl->Release)(pstmContents);
+ IsEnabled = wil::details::FeatureImpl<__WilFeatureTraits_Feature_3047977275>::__private_IsEnabled(&`wil::Feature<__WilFeatureTraits_Feature_3047977275>::GetImpl'::`2'::impl);
+ v10 = pstmContents;
+ v11 = !IsEnabled;
v12 = pstg->lpVtbl;
+ if ( !v11 )
+ v10 = 0LL;
+ pstmContents = v10;
(v12->DestroyElement)(pstg, L"CONTENTS");
v13 = (pstg->lpVtbl->OpenStream)(pstg, &OlePres, 0LL, 16LL, 0, &pstmOlePres);// 2nd option to fail -> no OlePres stream
if ( v13 )
{
*lpszPresStm |= 1u;
if ( (pstg->lpVtbl->OpenStream)(pstg, L"CONTENTS", 0LL, 16LL, 0, &pstmContents) )
{
*lpszPresStm |= 2u;
}
else
{
(pstmContents->lpVtbl->Release)(pstmContents);
+ wil::details::FeatureImpl<__WilFeatureTraits_Feature_3047977275>::__private_IsEnabled(&`wil::Feature<__WilFeatureTraits_Feature_3047977275>::GetImpl'::`2'::impl);
}
return v13;
}
foretc.ptd = 0LL;
v13 = UtReadOlePresStmHeader(pstmOlePres, &foretc, 0LL, 0LL);
if ( v13 >= 0 )
{
v13 = (pstmOlePres->lpVtbl->Read)(pstmOlePres, &hdfh, 16LL);
if ( v13 >= 0 )
{
v13 = OpenOrCreateStream(pstg, L"CONTENTS", &pstmContents);
if ( v13 < 0 )
{
*lpszPresStm |= 2u;
goto $errRtn_197;
}
if ( foretc.dwAspect == 4 )
{
*lpszPresStm |= 4u;
v7 = 0;
v13 = 0;
goto $errRtn_197;
}
if ( foretc.cfFormat == 8 )
{
v14 = UtDIBStmToDIBFileStm(pstmOlePres, hdfh.dwSize, pstmContents);
LABEL_19:
v13 = v14;
goto $errRtn_197;
}
if ( foretc.cfFormat == 3 )
{
v14 = UtMFStmToPlaceableMFStm(pstmOlePres, hdfh.dwSize, hdfh.dwWidth, hdfh.dwHeight, pstmContents);
goto LABEL_19;
}
v13 = -2147221398;
}
}
$errRtn_197:
if ( pstmOlePres )
(pstmOlePres->lpVtbl->Release)(pstmOlePres);
// Release pstmContents if it still exists, we need to clean up
if ( pstmContents )
(pstmContents->lpVtbl->Release)(pstmContents);
if ( foretc.ptd )
CoTaskMemFree(foretc.ptd);
if ( v13 )
{
v15 = L"CONTENTS";
goto LABEL_31;
}
if ( v7 )
{
v15 = &OlePres;
LABEL_31:
(pstg->lpVtbl->DestroyElement)(pstg, v15);
}
return v13;
}
```
The problem is in the pstmContents variable. Initially it's used to store the pointer to the "CONTENTS" stream object that's created at the beginning of the function. The stream is immediately destroyed after being created and the pointer stored in pstmContents is released (which frees it in coml2.dll!ExposedStream::~ExposedStream). However, the variable still contains the free'd pointer. Further down in the function, the variable may be reused to store the pointer to the "CONTENTS" stream again - because of this, there's cleanup code at the end of the function that releases the pointer in case it's stored in the variable. The code fails to account for the fact that UtReadOlePresStmHeader may fail - if that happens, pstmContents will still point towards the free'd pointer and we'll fall through to the cleanup code, which will release the pointer again. As such, a double-free situation will happen.
---
## ⚠️ **Disclaimer**
This information about **CVE-2025-21298** is provided **strictly for educational and defensive purposes**.
Any attempt to exploit this vulnerability on systems without **explicit, prior, written authorization** is **illegal** and may result in **criminal charges**, civil liability, or both.
The goal is to help security professionals, researchers, and system administrators **understand, detect, and mitigate** the issue — **not** to encourage malicious activity.
Always conduct testing in a **controlled lab environment** or on systems you fully own and control.
文件快照
[4.0K] /data/pocs/ef40022ea093c35d868b951694eec13fb5da8639
├── [ 221] CVE-2025-21298.rtf
└── [8.5K] README.md
0 directories, 2 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。