Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2025-21298 — 重要なWindows OLEゼロクリック脆弱性。これはCVE-2025-21298 - Windows OLE リモートコード実行の脆弱性(CVSS 9.8)の概念実証です。これはメモリ破損のPoCです。 | Kitploit
ツール/GitHubGitHub/thebl4ckph4nt0m/cve-2025-21298
メモリフォレンジック脆弱性分析エクスプロイトバイナリエクスプロイト
GitHubthebl4ckph4nt0m/cve-2025-21298

CVE-2025-21298

重要なWindows OLEゼロクリック脆弱性。これはCVE-2025-21298 - Windows OLE リモートコード実行の脆弱性(CVSS 9.8)の概念実証です。これはメモリ破損のPoCです。

リポジトリを見る
11年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2025-21298

コンテンツ

これは CVE-2025-21298 - Windows OLE リモートコード実行の脆弱性 (CVSS 9.8) の概念実証です。これは メモリ破損 PoC であり、エクスプロイトではありません。

脆弱性

脆弱性は ole32.dll!UtOlePresStmToContentsStm にあります。この関数の目的は、OLE ストレージ内の "OlePres" ストリーム内のデータを適切にフォーマットされたデータに変換し、同じストレージ内の "CONTENTS" ストリームに挿入することです。この関数は、ストレージオブジェクトへの IStorage ポインタと、それほど重要ではない3つの引数を受け取ります。

以下は、2025年1月のパッチとの差分を示した関数の実装です:

root@kitploit:~
__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;
}

問題は pstmContents 変数にあります。最初にこの変数は、関数の先頭で作成される "CONTENTS" ストリームオブジェクトへのポインタを格納するために使用されます。ストリームは作成後すぐに破棄され、pstmContents に格納されているポインタは解放されます (coml2.dll!ExposedStream::~ExposedStream 内で解放されます)。しかし、変数には解放済みのポインタが依然として保持されています。関数の後の方で、この変数は "CONTENTS" ストリームへのポインタを再度格納するために再利用される可能性があります。そのため、関数の最後には、ポインタが変数に格納されている場合に解放するクリーンアップコードがあります。このコードは、UtReadOlePresStmHeader が失敗する可能性があることを考慮していません。もし失敗した場合、pstmContents は依然として解放済みのポインタを指しており、クリーンアップコードに到達してポインタが再度解放されることになります。これにより、二重解放が発生します。

パッチの差分からわかるように、Microsoft は、最初に含まれていたポインタが解放された後に pstmContents をゼロに設定することでこの問題を修正しました。

再現

リポジトリには、この脆弱性を再現する rtf ファイルがあります。私は MS Word でファイルを開いてテストしましたが、RTF データを解析する他のアプリケーション (例: Outlook) でもテストできます。OLE オブジェクトを埋め込む他の形式を介した悪用も可能かもしれませんが、試していません。

動画:

poc

ツールをダウンロード