标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2025-3533]   作者: ShYLie 发表于: [2025-04-15]

本文共 [10] 位读者顶过

前言

CVE-2025-21298 漏洞其实是在三个月前被研究人员发现的,然后于 2025 年 1 月被微软官方披露,该漏洞 CVSS 评分 9.8 分。

当受害者在 Microsoft Outlook 中打开或预览电子邮件时,漏洞就会被触发,从而允许攻击者在受影响的系统上执行任意代码。

POC

Github 已放出该漏洞的概念验证(PoC),通过演示视频可以看到这是一个内存损坏的 PoC,并非漏洞利用程序(EXP),但不得不说,这种零点击(0-Click)漏洞非常讨“黑客”们的喜爱。

https://github.com/ynwarcs/CVE-2025-21298

漏洞成因

漏洞主要位于ole32.dll!utoLepresstmtocontentsstm中,该函数的目的是将OLE存储中的“Olepres”流中的数据转换为适当格式的数据,然后将其插入同一存储中的“CONTENTS”流中,它接收一个指向存储对象的IStorage指针和三个不重要的参数。

通过查看该函数的实现,并进行补丁差异对比可以看到:

__int64 __fastcall UtOlePresStmToContentsStm(IStorage *pstg, wchar_t *puiStatus, __int64,a3, unsigned int *lpszPresStm)[出自:jiwo.org]
{
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
constwchar_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) )
    return0LL;
// 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;
}

问题主要出在pstmContents变量,最初它用于将指针存储到在函数开头创建的“CONTENTS”流对象,创建后立即销毁该流,并释放存储在pstmContents中的指针(在coml2.dll!ExposedStream::~ExposedStream中释放了它)。

然而该变量仍然包含已释放的指针,在函数的后续部分,变量可能会被重新使用,以再次存储指向 "CONTENTS "流的指针--正因为如此,函数末尾有清理代码来释放指针,以防它在变量中存储,代码未能考虑到UtReadOlePresStmHeader可能会失败。

如果发生这种情况,pstmContents仍将指向已释放的指针,从而进入清理代码,再次释放指针,那么就会出现经典的双重释放(UAF)的情况。

在补丁对比中可以看到,微软通过在包含它的指针最初释放后将pstmContents设置为零修复了这个问题。

漏洞复现

首先打开 Word:


然后使用 WinDbg 附加到正在运行的 WINWORD.EXE 进程中:


打开Github 中给出的 poc.rtf ,就会看到 WORD 崩溃的调试信息:


缓解措施与建议

微软已发布补丁来修复该漏洞,强烈建议用户和组织及时应用这些更新来降低潜在风险。

参考资料:https://www.offsec.com/blog/cve-2025-21298/

评论

暂无
发表评论
 返回顶部 
热度(10)
 关注微信