Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-54107 — CVE-2026-54107の根本原因分析:Windows win32kfull.sysのuse-after-free。競合状態のデバッグ、静的解析、MSRCトリアージの洞察、実践的なカーネルエクスプロイト研究を含む。 | Kitploit
ツール/GitHubGitHub/pravin761/cve-2026-54107
静的分析脆弱性分析エクスプロイトリバースエンジニアリングデバッガ論文と研究学習と教育バイナリエクスプロイト
GitHubpravin761/cve-2026-54107

CVE-2026-54107

CVE-2026-54107の根本原因分析:Windows win32kfull.sysのuse-after-free。競合状態のデバッグ、静的解析、MSRCトリアージの洞察、実践的なカーネルエクスプロイト研究を含む。

リポジトリを見る
1112ヶ月前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

ValidateHwnd がゲートではないとき: CVE-2026-54107 の根本原因を追う

win32kfull.sys のウィンドウライフサイクル管理における use-after-free —— どのように見つけ、どうやって本物だと確信したか、そして研究者側から見た MSRC プロセスが実際どうだったか。

CVE-2026-54107 CWE-362 CVSS 8.8 MSRC 11xxxxx Bounty $8,000

午前2時近く、ターゲットのVMがデバッガーのハートビートに応答しなくなり、私が数週間にわたって到達可能だと主張してきた命令のまさにその場所でブレークに落ちた。アサーションでも、破損したプールの停止でもない——メッセージディスパッチ経路上の単純なアクセス違反で、別のスレッドが既に破棄したオブジェクトをデリファレンスしていた。

そのブレークは CVE-2026-54107 となり、MSRC ケース 11xxxxx として、2026年7月のセキュリティ更新で27のWindows製品にわたって修正された。

この投稿は、この話のうち非エンバーゴ部分である。根本原因、このバグクラスがなぜそうなのか、そしてそこに至った思考の筋道。悪用の詳細は省く。

目次

  • 1. なぜ win32k なのか、そしてなぜウィンドウオブジェクトなのか
  • 2. 私を止めさせた違和感
  • 3. 根本原因
  • 4. 影響度評価がなぜその値なのか
  • 5. 先に反証——候補のほとんどは脱落した
  • 6. 検証: 静的解析は仮説を与え、デバッガーは真実を与える
  • 7. カーネル研究におけるAI活用について
  • 8. MSRCタイムライン、正直に
  • 9. スナップショット
  • 10. これから始める人へのアドバイス
  • 11. 次の予定

1. なぜ win32k なのか、そしてなぜウィンドウオブジェクトなのか

Win32k は Windows グラフィカルサブシステムのカーネルモード側の半分である。古く、巨大で、そして決定的なことに、信頼されていないと想定されるコンテキストから到達可能である。この最後の性質こそが、20年にわたるハードニング、フィルタリング、システムコール制限の努力にもかかわらず、win32k が恒久的な研究対象であり続ける理由だ。

win32k の中でも、tagWND オブジェクト (PWND) は、そのライフタイムが複数のメカニズムによって同時に管理されているため、異常に興味深い。ウィンドウは次のようにして参照される:

  • ハンドルによる参照——ユーザーハンドルテーブルと ValidateHwnd スタイルのルックアップを通じて、
  • ポインターによる参照——ネストされた呼び出しとメッセージディスパッチをまたいで保持される、
  • 暗黙的な参照——親子、オーナー/オウンド、スレッド/デスクトップの関係を通じて、
  • そして、上記のすべてを正しい順序で巻き戻さなければならない破棄パスを通じて破棄される。

独立した参照経路が複数あり、破棄経路が1つしかないオブジェクトは、ゆっくり読む価値がある。これは脆弱性の主張ではない——どこに時間を割くべきかというヒューリスティックだ。

2. 私を止めさせた違和感

このコンポーネントに腰を据えたきっかけは、インポート面だった。win32kfull.sys は、ntoskrnl から3つの異なるオブジェクト参照プリミティブを取り込んでいる:```c NTSTATUS ObReferenceObjectByPointer( void *Object, uint32_t DesiredAccess, POBJECT_TYPE ObjectType, char AccessMode);

NTSTATUS ObReferenceObjectByHandle( HANDLE Handle, uint32_t DesiredAccess, POBJECT_TYPE ObjectType, char AccessMode, void **Object, OBJECT_HANDLE_INFORMATION *HandleInformation);

NTSTATUS ObReferenceObjectByName(/* ... */);

入り口は3つ、出口は `ObfDereferenceObject` 経由の1つだけだ。

それはコードが間違っているという意味ではない。**不変条件が分散している**という意味だ — どの単一の関数も*「このオブジェクトは今まさに生きている」*を所有していない。したがって、正しさは、すべての呼び出し元が、自分が保持している参照がどれであり、それがどのくらいの期間有効であるかについて合意しているかに依存する。分散された不変条件は、レースコンディションが潜む場所である。なぜなら、レースとは単一の関数内で見えるロジックバグではないからだ。それは2つの関数にまたがって保持された前提のバグである。

そこで私が `PWND` に触れるすべての関数に対して問い始めたのは、*「このコードは正しいか?」*ではなく、次の問いだった:

> **このまったく同じ関数本体が、数命令分だけずれて2つのスレッド上で実行された場合、間違っているのはどちらか?**



## 3. 根本原因

この欠陥は、ウィンドウ破棄パスにおける**参照解放とオブジェクト破棄の間の time-of-check / time-of-use(TOCTOU)ギャップ**であり、並行してハンドルを検証するコンシューマに対する適切な同期が欠如している。

その形だけに単純化すると:```c
/* Thread A — teardown */
NtUserDestroyWindow(HWND hwnd)
{
    PWND pWnd = ValidateHwnd(hwnd);
    if (pWnd) {
        ObfDereferenceObject(pWnd);   /* reference released */

        /* <-- race window: object may become reclaimable here */

        FreeWindowObject(pWnd);       /* teardown proceeds on a pointer
                                         no longer guaranteed live      */
    }
}

The input chunk is empty — no content was provided to translate. Please supply the Markdown text for chunk 5 of 13.```c /* Thread B — consumer, concurrent / NtUserMessageCall(HWND hwnd, UINT msg, ...) { PWND pWnd = ValidateHwnd(hwnd); / may resolve a handle whose object is mid-teardown */

if (pWnd->fnid == FNID_BUTTON)    /* use-after-free */
    ...

}

これが問題になるには2つの条件が真でなければならず、その両方が成立していた:

**(a) その時間窓は本物である。** `ValidateHwnd` はハンドルベースのアクセスを安全にするためのゲートである。既に破棄が始まっているオブジェクトに対して検証が成功し得るのなら、そのゲートはゲートではなく、単なる提案に過ぎない。

**(b) 解放されたメモリは攻撃者が影響を与えられる。** 検証直後に読み取られるフィールドには、メッセージディスパッチを駆動する `fnid` が含まれる。再利用されたメモリから下されたディスパッチの決定は、*"信頼できないクラッシュ"* と *"セキュリティ境界の侵害"* の違いを生む。この区別こそが、これが安定性バグではなく、EoP 影響を伴う CWE-362 であるすべての理由である。

> 観測された **破壊(corruption)** は use-after-free であり、**原因** は CWE-362、すなわち不適切な同期による共有リソースの並行実行である。この2つは別の命題であり、MSRC が重視するのは後者である。**症状だけでなく原因を報告せよ。**

### win32k の競合状態が構造的に難しく見える理由

他のサブシステムでバグを競わせた経験があるなら、win32k は苛立たしいだろう。なぜなら、アーキテクチャが3つの具体的な方法で敵対してくるからだ。

**ウィンドウにはスレッド親和性がある。** ウィンドウは、それを生成したスレッドに属する。サブシステムの多くは、所有スレッドがオブジェクトに触れるという前提の上に構築されている。つまり、素朴に「2つのスレッドを回して同じ API を呼ぶ」というアプローチは、しばしば何も重なり合わない——競合しているのではなく、キューイングしているのだ。2つのパスを同じオブジェクト上で本当に衝突させるには、どの操作が呼び出し元スレッドで実際に実行され、どの操作が所有者側にマーシャリングされるのかを理解する必要がある。

**メッセージディスパッチは部分的に直列化される。** Send と Post は動作が異なり、クロススレッドと同一スレッドのディスパッチもまた異なる動作をする。並行処理の機会に見えるものの一部は、関心のあるコードに到達する前に、静かに順序付けられた操作に変換される。自分のトリガーがどのカテゴリに該当するかを知らなければ、本当の競合状態は到達不能だと結論してしまう——これは「ここにバグはない」と見分けがつかない偽陰性である。

**クリティカルセクションは呼び出し元側に隠れている。** サブシステムの多くは、注視している関数よりずっと上位で取得される粗いロックの下で実行される。これは win32k 監査における最大の時間の無駄の源泉である。可視的な同期がなくても、そこへのすべての経路が既に直列化されているため完全に安全な関数、というものが存在するのだ。**ロックの適用範囲は手続き間の性質である。** 関数を読むだけでなく、コールグラフを遡って調べなければならない。

この3点目こそ、*"この関数にはロックがない"* というシグナルがほぼ無価値である理由であり、今回の探索作業のほとんどが欠陥そのものではなく到達可能性に費やされた理由である。

## 4. 影響度評価がこの値になる理由

MSRC はこれを **重要(Important)、特権昇格(Elevation of Privilege)、CVSS 8.8、攻撃ベクトルはローカル、認証済み** と評価した。これを決定づけたのは2つの性質である:

**低整合性レベルからの到達可能性。** Win32k のメッセージ呼び出し面は、SYSTEM よりはるかに低いコンテキストから到達可能である。これこそがサンドボックスエスケープチェーンに関連する理由であり、サンドボックス内で既にコード実行を達成したレンダラープロセスでも、この面には到達できる。カーネルバグの深刻度は、ほぼ専ら *誰が触れることができるか* の関数であり、破壊がどれほど巧妙かではない。

**ディスパッチに影響を与える破壊。** `switch` が実行対象とするフィールドを破壊することは、ログに記録されるだけのフィールドを破壊することよりも質的に悪い。前者はメモリバグを制御フローの問題に変える。

ここで1つ正確に述べておきたい。なぜなら、初めての CVE を報告する投稿がこれを誇張するのを見たことがあるからだ: **私は競合状態と use-after-free を実証した。兵器化された SYSTEM レベルのエクスプロイトを納品したわけではない。** サンドボックスエスケープという枠組みは、このバグタイプが属する *チェーンのクラス* と、その面が価値を持つ理由を説明するものであり、到達可能性についての議論であって、私がエクスプロイトを構築したという主張ではない。影響度の誇張はベンダーとの信頼を失う最短経路であり、重要なのは私の評価ではなく MSRC の評価である。

## 5. 反証が先——ほとんどの候補は脱落した

誰も書かない部分: これは最初の候補ではなかった。生き残った唯一の候補だったのだ。

私の作業規則は、**候補は有罪が証明されるまで有罪とみなす** というものだ。有望なパターンにはすべて、*悪用できるはずがない* 具体的な理由を書き留め、トリガーを試す前にその理由を確立しに行く。今回の候補より前に私が切り捨てた候補には以下があった:

- 同期がないように見えたが、1フレーム上のロックによって直列化されていたパス、
- 「解放された」オブジェクトが実際には解放ではなくキャッシュされていたパス、
- 実際に競合状態ではあるが、低権限ユーザーが駆動できる呼び出し元からは到達不能なパス。

そのすべては、私が MSRC *に送らなかった* 発見である。そこが要点だ。研究者のスループットとは、生成する候補の数ではなく、誤った候補をどれだけ速く殺せるか——午前2時までそれらを抱え続けなくて済むか——である。

**ほとんどの候補を殺した3つの質問:**

1. **自分より上流で誰かがロックを保持しているか?** ローカルではなく手続き間で見る。関数内にロックがないことは何も意味しない。
2. **非特権の呼び出し元が実際に両方の経路に到達できるか?** 異なる権限レベルを必要とする2つのパス間の競合は、競合ではなく思考実験である。
3. **解放されたメモリは、自分が影響を与えられる時間窓の中で再利用可能か?** 実用上、破棄がアトミックに完了するなら、報告する価値のあるバグは存在しない。

## 6. 検証: 静的解析は仮説を与え、デバッガーは真実を与える

`win32kfull.sys` の静的解析は私に仮説を与えた。しかし、バグそのものを与えることは決してなかった。**競合状態は逆コンパイラには見えない。** 欠陥は命令の中にあるのではなく、インターリーブ(交錯)の中にあるからだ。

### 実験環境

| 役割 | 構成 |
| --- | --- |
| ホスト / デバッガー | Windows 11、WinDbg |
| ターゲット | Windows Server 2022、Build 20348.2159 |
| 解析 | Kali Linux + Windows 11 VM |
| デバッグ転送 | VMware シリアル COM、ホスト → ターゲットのカーネルデバッグ |
| 静的解析 | GhidraMCP 経由の Ghidra |
| トリアージ補助 | 逆コンパイル出力に対する AI 支援パス |

実際の作業を行ったのは3つのインストルメンテーション層である。

### スペシャルプールと Driver Verifier

カーネル UAF 調査における単一の最高レバレッジ手順。デフォルトでは、解放されたプールメモリは、同じサイズの次の割り当てによってほぼ即座に再利用される。つまり use-after-free は通常 *フォルトを起こさない*。他人の有効なデータを読み、実行を継続し、数分後に無関係な場所で爆発する。そしてあなたは無実の関数の監査に3日を費やすことになる。
ツールをダウンロード