機能不全の危機 — Wininit.exe を使用したリモート DoS 攻撃
編集・協力:Tricia Howard
エグゼクティブサマリー
Akamai のリサーチャーである Stiv Kupchik は、Microsoft の Wininit.exe に新たなサービス妨害(DoS)の脆弱性( CVE-2022-44707)を発見しました。この CVE の CVSS スコアは 6.5 です。
この脆弱性は、8 月に MSRC が責任を持って開示したもので、 12 月の Patch Tuesday 2022 の一部としてパッチがリリースされました。
この脆弱性は、 RPC のキャッシュメカニズムを悪用しますが、これは当社が今まで大規模に調査してきたものです。Akamai は、 RPC ツールキットでこの攻撃の概念実証を提供しています。
攻撃者はこの脆弱性を悪用して、キャッシュメカニズムによりセキュリティチェックを回避し、リモートの Windows マシン上のシャットダウンメカニズムとやり取りして、シャットダウンを停止または開始する制御を取得します。
この脆弱性は、Windows 8/Server 2012 以降の、パッチをまだ適用していないすべての Windows バージョンに関係するため、適切なタイミングでパッチを適用することの重要性が高まっています。
概要
以前の投稿の コールド・ハード・キャッシュで、当社の RPC ツールキットを使用して検出した RPC の脆弱性をいくつかご紹介することに触れましたが、今回は、RPC の別の問題として Wininit を取り上げます。
Wininit は、Windows オペレーティングシステムの起動とシャットダウンの両方で重要な役割を果たす、重要な Windows プロセスです(このプロセスがクラッシュするとシステム全体がクラッシュ)。そのため、シャットダウン機能を実装した複数の RPC インターフェースが公開されており、その一部が 記述されています。私たちが発見した脆弱性は、 WindowsShutdown インターフェースに存在します。
WindowsShutdown インターフェースとは
WindowsShutdown は、Wininit で公開されている数少ない RPC インターフェースの 1 つです。このインターフェースは、シャットダウン処理を担います(Wininit の他の RPC インターフェースと同様)。このインターフェースの UUID は d95afe70-a6d5-4259-822e-2c84da1ddb0dです。これは、 MS-RSP (リモート・シャットダウン・プロトコル)の一部であり、次の機能を備えています。
公開の IDL ファイルを見るとわかりますが、 WsdrInitiateShutdown および WsdrAbortShutdown のみが記述されています。では、記述されていない関数は気にしなくてよいのでしょうか(他のリサーチャーに聞いたことはありませんが)。その答えを得るために、このインターフェースのセキュリティコールバックを見てみましょう。
セキュリティコールバック
このコールバックは最初にトランスポートプロトコルをチェックし、ALPC または TCP のみを許可します。次に、認証レベルをチェックし、 RPC_C_AUTHN_LEVEL_PKT_PRIVACY のみを許可します。呼び出された関数が WsdrCheckForHiberbootでない場合は、リモート呼び出し元のユーザーのトークンがチェックされます。これは、トークンを SECURITY_NETWORK_RIDという既知の SID(WinInit の初期化中に作成されるグローバル変数に保存される ID)と比較することによって実行されます。 WsdrCheckForHiberboot の呼び出しは、セキュリティコールバックによる制限がまったくありません。
RPC インターフェースはデフォルトのキャッシュ動作で登録されているため、理論的には WsdrCheckForHiberbootの呼び出しが成功すれば、結果がキャッシングされるため、 WsdrInitiateShutdown および WsdrAbortShutdownの呼び出し以降では SID チェックを回避することができます。
では、 WsdrCheckForHiberbootを呼び出すには何をすればよいのでしょうか?
WsdrCheckForHiberboot
この関数が何をするのか、hiberboot(簡単に言うと Windows の高速スタートアップ)が何であるのかはあまり気になりませんが、正しく呼び出す方法はきちんと知っておく必要があります。この関数を IDL ファイルで正しく定義して、クライアントをコンパイルできるようにすればよいのです。関数は記述されていませんが、advapi の CheckForHiberbootを見ると、RPC クライアントで唯一見つかった WsdrCheckForHiberbootの記述があります。必要な引数は、ブール型ポインタとブール型の 2 つだけです。
これらの引数を指定して関数の定義を再作成すれば、IDL ファイルとプログラムをコンパイルすることができます。しかし、まだ何かが足りません。クライアントからリモートで関数を呼び出すと、RPC ランタイムは RPC スタブエラーを返して、関数の呼び出しが正しくないことを知らせてきます。
推測で進めるのはここでやめましょう。丹念に時間をかけて調べれば、できるようになります。RPC の インターフェーススタブには ProcFormatStringという名前のフィールドがあります。これは基本的に長いバイナリ文字列で、インターフェースによって公開されるすべての関数の引数タイプと戻り値を記述します。このフィールドは、RPC ランタイムが関数呼び出しをマーシャリングおよびアンマーシャリングする際に使用します(最初の試みで RPC スタブエラーを返したのはこのプロセス)。このバイナリ文字列を丹念に手間をかけながら調べた結果、ようやくこの関数には別の引数が必要であることがわかりました。その引数は、 wchar_t* という型の引数です。次の図で、 ProcFormatString の WsdrCheckForHiberbootセクションの様子を示しています。各部分にコメントを付けています。
関数定義に「new」引数を追加すれば、いよいよ先に進めます。 CheckForHiberboot が正常に返ってくるようになったため、 WsdrInitiateShutdown および WsdrAbortShutdownの両方を呼び出しできるようになりました。
いよいよ攻撃
では早速、キャッシング攻撃を仕掛けて、 WsdrInitiateShutdown を呼び出し、リモートシャットダウンを実行することにしましょう。今回は仕組みを理解したうえで手順を進めることができます。IDL ファイルに関数の定義を記述するだけでなく、advapi 関数の InitiateShutdownAの下に、指定する必要があるフラグを記述します。SHUTDOWN_GRACE_OVERRIDE、SHUTDOWN_HYBRID、SHUTDOWN_FORCE_OTHERS のフラグの組み合わせを使用すれば、強制的にシャットダウンできるようになります。
これで、基本的な攻撃チェーンが完成し、セキュリティコールバックとその SID チェックを回避してリモートからシャットダウンできるようになりました。技術的に見れば、これは権限のエスカレーションになります(認証されたユーザーが WsdrInitiateShutdown をリモートで呼び出すことができるようになり、 SECURITY_NETWORK_RIDのもとで許可されるものは必要ありません)。このインターフェースを使用した場合にのみシャットダウンが可能なため、この脆弱性は DoS 脆弱性に分類されています。
検知
パッチが適用されていない(したがって脆弱な)Wininit.exe のバージョンを検知する OSQuery を提供しています。 Akamai Guardicore Segmentation のお客様は、このクエリーと知見機能を併用して脆弱なアセットを検索できます。
WITH product_version AS (
WITH os_minor AS (
WITH os_major AS (
SELECT substr(product_version, 0, instr(product_version, ".")) as os_major, substr(product_version, instr(product_version, ".")+1) as no_os_major_substr
FROM file
WHERE path = "c:\windows\system32\wininit.exe"
)
SELECT substr(no_os_major_substr, instr(no_os_major_substr, ".")+1) as no_os_minor_substr, substr(no_os_major_substr, 0, instr(no_os_major_substr, ".")) as os_minor, os_major
FROM os_major
)
SELECT
CAST(substr(no_os_minor_substr, instr(no_os_minor_substr, ".")+1) AS INTEGER) AS product_minor,
CAST(substr(no_os_minor_substr, 0, instr(no_os_minor_substr, ".")) AS INTEGER) AS product_major,
CAST(os_minor AS INTEGER) AS os_minor,
CAST(os_major AS INTEGER) AS os_major
FROM os_minor
)
SELECT
CASE
WHEN NOT ((os_major = 6 AND os_minor = 3) OR (os_major = 6 AND os_minor = 2) OR (os_major = 10 AND os_minor = 0))
THEN "not supported"
WHEN os_major = 6 AND os_minor = 3 AND product_major = 9600 AND product_minor >= 20716 THEN "patched"
WHEN os_major = 6 AND os_minor = 2 AND product_major = 9200 AND product_minor >= 24011 THEN "patched"
WHEN (
(product_major = 14393 AND product_minor >= 5582)
OR
(product_major = 10240 AND product_minor >= 19624)
OR
(product_major = 19041 AND product_minor >= 1620)
OR
(product_major = 22621 AND product_minor >= 963)
OR
(product_major = 22000 AND product_minor >= 1335)
OR
(product_major = 20348 AND product_minor >= 1366)
OR
(product_major = 17763 AND product_minor >= 3770)
)
THEN
"patched"
ELSE
"not patched"
まとめ
この脆弱性の重要度は高くありませんが(起こるのはリモートシャットダウン だけ であり、不正にアクセスしたものでない)、Windows オペレーティングシステムの最も重要なサービスに組み込まれている MS-RPC が本質的に破壊的な潜在能力を秘めていることを表しています。また、他のタイプの脆弱性とは異なり、RPC ではほとんど憶測に頼る必要がありません。つまり、すべての手札(バイナリ)は揃っており、その札の読み方さえ知っていればよいのです。
Akamai は、このような重要な機能を悪用する方法を見つけるために MS-RPCにまで調査の範囲を広げています。広く使用されているにもかかわらず、全体から見ればほとんど調査されていません。今回ご説明したような脆弱性は、この種の作業がなぜ必要なのかを示しており、これをきっかけとして他の研究者が MS-RPC に取り組んでくれることを期待しています。
この脆弱性は、8 月下旬に責任を持って開示され、2022 年 12 月の Patch Tuesday の一部としてパッチがリリースされました。