CVE-2026-42978 — Windows Push Notifications (WpnService)におけるUse-After-Freeの競合状態。パッチ差分、根本原因分析、TOCTOUラボ、Sysmon/ETW検出ルール。
Windows プッシュ通知サービス (WpnService) における競合状態。このサービスは NT AUTHORITY\SYSTEM として実行されます。ローカルアクセスを持つ攻撃者は、プラットフォームのシャットダウン中に解放後使用 (use-after-free) を引き起こし、特権を昇格させる可能性があります。
WpnService は Windows プッシュ通知サービスです。セッション 0 で LocalSystem として svchost.exe -k netsvcs -p 内で実行されます。すべての通知配信 (トースト、タイル、バッジなど) はこのサービスを経由します。
脆弱性は wpncore.dll 内、特に クラスに存在します。このクラスはすべての通知 API 呼び出し (トースト配信、セッション管理、設定クエリなど) をラップし、 に委譲します。
PresentationEndpointFacadePresentationEndpointImplバグ: プラットフォームシャットダウン中に、NotificationPlatform オブジェクトが破棄されます。しかし Facade メソッドはシャットダウンが進行中かどうかをチェックしません。プラットフォームへのポインタを取得し、そのプラットフォームがシャットダウンスレッドによって解放され、Facade がダングリングポインタを使用します。古典的な解放後使用 (use-after-free) の競合状態です。
// PresentationEndpointFacade::ToastUnblockAll — VULNERABLE
long ToastUnblockAll(PresentationEndpointFacade *this) {
// No lock. No shutdown check. Just grab the platform pointer and go.
NotificationPlatformHandle::Get(this + 0x50);
if (platform == NULL) Throw_Hr(...);
// If shutdown frees the platform right here — use-after-free
return PresentationEndpointImpl::UnblockToastsForEachApp(...);
}
Ghidra: 脆弱な ToastUnblockAll — プラットフォームアクセス前の同期がない
// PresentationEndpointFacade::ToastUnblockAll — PATCHED
long ToastUnblockAll(PresentationEndpointFacade *this) {
if (Feature_4097557817::IsEnabled()) {
AcquireSRWLockShared(&Wns::s_platformLock); // 1. shared lock
if (Wns::s_platformShutdown) // 2. shutdown guard
Throw_Hr(E_APPLICATION_EXITING);
NotificationPlatformHandle::Get(this + 0x50);
// ... do work ...
ReleaseSRWLockShared(&Wns::s_platformLock); // 3. RAII release
} else {
// feature flag off — old behavior preserved for rollback
}
}
修正では以下の3つが追加されています:
AcquireSRWLockShared — 共有リーダーライターロック。複数の API 呼び出しを同時実行できますが、シャットダウンは排他ロックを取得してすべてをブロックします。s_platformShutdown チェック — シャットダウンがすでに開始されている場合は、即座に E_APPLICATION_EXITING で終了します。wil::unique_storage ラッパーで保持されるため、例外がスローされても解放されます。機能フラグ Feature_4097557817 は WIL (Windows Internal Library) による段階的なロールアウトのためのものです。これにより Microsoft は修正を段階的に有効にし、何か問題が発生した場合に無効にすることができます。
これは一つの関数だけのバグではありません。同じロック+ガードパターンが wpncore.dll の 49 個の関数 に追加されました:
| カテゴリ | 関数 |
|---|---|
| トースト操作 | ToastUnblockAll, ToastCreateSession, ToastCloseSession, ToastRequestAllNotifications, ToastSuppress |
| タイル操作 | TileCreateSession, TileCloseSession, TileRequestResourceForeground |
| 登録 | RegisterApplication, UnregisterApplication, RegisterHandler, UpdateRegistration, RegisterSystemApplication |
| 設定 | ChangeAppSetting, QueryAppSetting, QueryGlobalSetting, RegisterSettingCallback, UnregisterSettingCallback |
| 配信 | Deliver, GetPayloadForNotificationId, Submit, PostScheduledNotification |
| クエリ | GetRegisteredHandler, GetRegisteredHandlersFromParent, GetSettingsFromHandler, GetAssetsFromHandler |
プラットフォームにアクセスするすべての PresentationEndpointFacade::* メソッドに同じ修正が適用されました。下位の PresentationEndpointImpl::* メソッドは変更されていません — 問題は Facade 層のみにありました。
WpnService は SYSTEM として実行されます。競合に勝利した場合:
NotificationPlatform オブジェクトのメモリが再利用され、攻撃者制御のデータで埋められる可能性があります (ヒープスプレー)NT AUTHORITY\SYSTEM としてのコード実行実際の悪用 (ヒープスプレー、vtable ハイジャック、コード実行の達成) はこの研究の範囲外です。このリポジトリは 根本原因の理解 と 検出の構築 に焦点を当てています。
lab/ ディレクトリには、WpnService に触れることなくバグのクラスを再現するスタンドアロンの C デモが含まれています。WpnService と同様の名前付きパイプと共有メモリアーキテクチャを使用しています。
動作の仕組み:
vulnerable_service.exe は共有メモリからメッセージ長を読み取り、検証し、50ms スリープした後、再度 長さを読み取ります (ダブルフェッチ)。race_attacker.exe は安全な長さを設定し、サービスをトリガーした後、即座に共有メモリをオーバーフロー値に書き換えます。vulnerable_service.exe --patched を実行すると修正が確認できます: ローカル変数へのシングルフェッチキャプチャ。
左: サービスが競合を検出 (5/5)。右: 攻撃者が共有メモリ値を書き換え。
GCC (MinGW) が必要です。lab/ ディレクトリから:
build.bat
ターミナル 1:
vulnerable_service.exe
ターミナル 2:
race_attacker.exe 5
その後、vulnerable_service.exe --patched と比較してください — 同じ攻撃でも、競合は0検出されます。
detection/etw_wpn_monitor.ps1)7つの指標をチェックする PowerShell スクリプト:
powershell -ExecutionPolicy Bypass .\detection\etw_wpn_monitor.ps1
ETW モニター: WpnService 実行中 (PID 6432)、クラッシュなし、100 イベント/時間、システムはパッチ適用済み
detection/sysmon_wpn_race_detect.xml)継続的な監視のための6つのルールグループ:
| ルール | キャッチする内容 |
|---|---|
WPN_EoP_ChildProcess | svchost (netsvcs) が cmd/powershell/wscript を生成 |
WPN_PipeAccess | WPN 関連の名前付きパイプへの接続 |
WPN_FileCreation | 通知データディレクトリでのファイル作成 |
WPN_RegistryTampering | PushNotifications キーへのレジストリ書き込み |
WPN_ProcessAccess | svchost への PROCESS_ALL_ACCESS ハンドル |
WPN_ThreadInjection | svchost への CreateRemoteThread |
インストール:
sysmon64.exe -accepteula -i detection\sysmon_wpn_race_detect.xml
WpnService のアクティビティは Microsoft-Windows-PushNotifications-Platform/Operational に記録されます。注目すべき主要なイベント:
イベントビューアー: PushNotifications-Platform 操作ログ、イベント ID 1225
wpncore.dll の差分解析からの主な発見:
.text セクションが 18,432 バイト 増加 (49 関数にわたる新しいロック/ガードコード).data セクションが 96 バイト 増加 (新しい Wns::s_platformLock および Wns::s_platformShutdown グローバル変数)AcquireSRWLockShared/ReleaseSRWLockShared は既にインポートテーブルに存在していました~unique_any_t<...ReleaseSRWLockExclusive...> によりロックラッパーの追加が確認されました完全なレポートは reports/ にあります。
CVE-2026-42978 は、2026年6月に修正された9つの WPN 関連脆弱性のクラスターの一部です:
| CVE | 種類 | CWE |
|---|---|---|
| CVE-2026-42977 | EoP | 競合状態 |
| CVE-2026-42978 | EoP | 競合状態 |
| CVE-2026-42979 | EoP | 競合状態 |
| CVE-2026-42991 | EoP | 競合状態 |
| CVE-2026-42969 | 情報漏洩 | 競合状態 |
| CVE-2026-42970 | 情報漏洩 | 競合状態 |
| CVE-2026-42973 | 情報漏洩 | 競合状態 |
| CVE-2026-26167 | EoP | — |
| CVE-2026-32160 | EoP | — |
CVE-2026-42978/
├── README.md
├── lab/
│ ├── vulnerable_service.c # ダブルフェッチバグを持つモック WpnService
│ ├── race_attacker.c # ダブルフェッチを悪用する攻撃者プログラム
│ └── build.bat # GCC ビルドスクリプト
├── detection/
│ ├── etw_wpn_monitor.ps1 # 7つのチェックを行う PowerShell 検出器
│ └── sysmon_wpn_race_detect.xml # Sysmon ルール設定
├── reports/
│ ├── PE_DIFF_REPORT.txt # PE セクション/インポート差分結果
│ └── FUNCTION_DIFF_REPORT.txt # 関数レベルの差分 (49 個変更)
└── img/ # このREADME用のスクリーンショット
このプロジェクトは 防御的なセキュリティ研究 を目的としています。脆弱性は修正済みです。武器化されたエクスプロイトコードは含まれていません。TOCTOU ラボはスタンドアロンのモックサービス上でバグのクラスをデモンストレーションするものであり、WpnService やシステムコンポーネントとは相互作用しません。
お使いの Windows が最新であることを確認してください。etw_wpn_monitor.ps1 がシステムを未パッチと報告した場合は、直ちに 2026 年 6 月の累積更新プログラムをインストールしてください。
追加したいものがあれば (より良い検出ルール、エクスプロイトの概念実証、Ghidra Version Tracking セッション、YARA シグネチャ、またはこのクラスターの関連 CVE の分析など)、PR を歓迎します。
貢献のアイデア:
質問がある場合や研究について議論したい場合は、Issue を開いてください。
MIT