This post is also available in: English (英語)
概要
Microsoft Windowsにおける2つの類似した特権昇格の脆弱性(CVE-2021-1732とCVE-2022-21882)の報告を見た私たちは、それぞれに関わるコードを深く理解するため、これらのCVEを分析することにしました。本稿はインサイドWin32kエクスプロイトの続編です。前編では、CVE-2021-1732とCVE-2022-21882にまつわる問題を探るための背景情報として、Win32kの内部とエクスプロイト全般について解説しました。
本稿では、CVE-2021-1732とCVE-2022-21882、およびこれらのCVEに関連する概念実証(PoC)エクスプロイトを深掘りしていきます。この2つのエクスプロイト分析を通じ、「CVE-2021-1732に対する修正プログラムがCVE-2022-21882の防止には不十分であった理由」を明らかにします。
本連載で取り上げる脆弱性は、いずれもCortex XDRのAnti-LPE保護モジュールにより検出・ブロックされます。いずれの脆弱性も、NT AUTHORITY\SYSTEMの特権トークンを現在の(エクスプロイトの)プロセスのそれにコピーすることで特権昇格を図る、データオンリー型の(システム上のデータ変更にコード実行を必要としない種類の)エクスプロイトです。Cortex XDRのAnti-LPEモジュールは、この特定の種類の特権昇格技術を監視します。
関連するUnit 42のトピック | Microsoft Windows, CVE-2021-1732, CVE-2022-21882 |
CVE-2021-1732とCVE-2022-21882の分析
このセクションではWin32kの2つのPoCエクスプロイト、CVE-2021-1732とCVE-2022-21882について論じます。これらの脆弱性はいずれも、xxxClientAllocWindowClassExtraBytesとNtUserConsoleControlを悪用し、隣接するウィンドウのtagWND.cbWndExtraのデータ フィールドを大きな値に上書きすることにより、任意のwriteプリミティブを取得できるようにするものでした。これらの脆弱性はいずれも、この任意のwriteプリミティブを使って、隣接するウィンドウ内で偽のspmenuを作成してから、GetMenuBarInfoを使って任意のreadプリミティブを作成します。そして、この任意のread/writeプリミティブを使い、NT AUTHORITY \SYSTEMトークンを現在の(エクスプロイトされた)プロセスへコピーします。
ここではCVE-2022-21882のPoCを詳細に分析します。CVE-2021-1732については、CVE-2022-21882の分析を進めるなかで適宜、相違点を説明するかたちで取り上げます。その後、MicrosoftがCVE-2021-1732に対してリリースした修正プログラムがCVE-2022-21882の防止に不十分であった理由を説明します。
CVE-2022-21882を論じるのに時間を割くことにした理由は、CVE-2021-1732についてはGoogleやDBAPPSecurity Threat Intelligence Centerが詳細に分析したブログが複数あるからです。
これらのエクスプロイトはいずれもデータオンリー型の攻撃です。データオンリー攻撃の場合、read/writeプリミティブだけあれば攻撃ができ、攻撃者がコントロールするコードの実行は必要ありません。最新のオペレーティング システムに導入されている現代的なエクスプロイト防止策は回避が難しいので、データオンリー型エクスプロイトの濫用は拡大してきています。
CVE-2022-21882の概要
この脆弱性は、2021年10月に開催された天府杯ハッキング コンテストで、RyeLv氏(@b2ahex)が発見したものです。Microsoftは、2022年1月に修正プログラムをリリースしました。CVE-2021-1732との類似性からすると、若干修正するだけでWindows 10のバージョン1709から21H2までが影響を受けていた可能性が高いと思われます。
MicrosoftはWindows 11用にも同脆弱性に対応する修正プログラムをリリースしています。本稿で解析するPoCは、Windows 10のバージョン21H2でテストしています。
脆弱性のトリガー
歴史的にエクスプロイトの作者はtagWNDやbitmapオブジェクトの悪用に頼ってread/writeプリミティブを実現していました。前稿で述べたように、Microsoftはこうしたオブジェクトを悪用しづらくするため多大な労力を費やしてきました。具体的には、Windows 10のバージョン 1703からは、SetWindowLongを使った場合、デスクトップ ヒープのユーザーモード コピー内のExtraBytesフィールドだけが変更され、カーネル デスクトップ ヒープは変更されないという制約が加わりました。ただし、コンソール ウィンドウで操作している場合にはこの制約が適用されません。
そこで、これらの脆弱性は2つとも、Windowsオペレーティング システムが想定しないタイミングでNtUserConsoleControlを呼び出すことにより、ユーザーモード コールバック中にウィンドウをコンソール ウィンドウに変換するという方法でこの制約をかいくぐっています。こうしてウィンドウをコンソール ウィンドウに変換した結果、この関数はtagWND.dwExtraFlagマスクに0x800を追加します。これにより、tagWND.pExtraBytesフィールドはもはやユーザーモード ポインターを表すのではなくカーネルに対するオフセットを表すようになります。
Windowsはウィンドウ種別の確認処理を何も入れていなかったので、このウィンドウに対してSetWindowLongが呼び出されれば、バージョン1703より前のWindows 10同様、カーネル デスクトップ ヒープに変更が加えられてしまいます。CVE-2022-21882のPoCを通しで眺めて、これがどのように実現されているのかを見てみましょう。
PoC (Proof of Concept: 概念実証)のウォークスルー
ではPoC (概念実証)を見ていきます。以下に簡単にまとめてみました。
- HMValidateHandleを見つける
- NtUserConsoleControl、NtCallbackReturnをロードする
- KernelCallbackTableを見つける
- xxxClientAllocWindowClassExtraBytesとxxxClientFreeWindowClassExtraBytesへのポインターを格納する
- ウィンドウ クラスをいくつか定義する
- ヒープ グルーミングを行う
- ウィンドウをいくつか作成する
- HMValidateHandleを使ってユーザーモードのtagWNDの位置を漏えいさせる
- HMValidateHandleを使ってユーザーモードのtagWNDの位置を漏えいさせる
- ウィンドウ間のオフセットを計算する
- 最も下位のウィンドウのアドレスでNtUserConsoleControlを呼び出す
- 3つめの(magic)ウィンドウを作成する
- NtUserConsoleControlとNtCallbackReturnを呼び出す悪意のあるバージョンでxxxClientAllocWindowClassExtraBytesをフックしてから正規のxxxClientAllocWindowClassExtraBytesに戻る
- NtUserMessageCallを使ってWndMagic上のフックされた関数をトリガーする
- SetWindowLongAを使って任意のwriteプリミティブを作成する
- SetWindowLongPtrAを使ってWnd1のspmenuのカーネル アドレスを漏えいさせ、それを偽のspmenuオブジェクトで置き換える
- 任意のread/writeプリミティブによりSystemのトークンを複製する
- System権限で新しいプロセスを作成して変更されたカーネルの値を修正する
次のセクションでは、このまとめをステップ1~5までを順に通しで説明します。
続きを読む ➠ セクション 2 – 詳細分析ステップ1-5