This post is also available in: English (英語)
2018年12月、「SandboxEscaper」というエイリアスで知られるハッカーが Windows エラー報告 (Windows Error Reporting, WER) コンポーネントに存在するゼロデイ脆弱性を公開しました。この公開内容をさらに深く掘り下げた結果、筆者はその脆弱性とはべつにもうひとつのゼロデイ脆弱性があることを発見しました。その脆弱性はシステム特権昇格に悪用される可能性があるもので、Microsoft のアドバイザリによれば、2019年5月にパッチがリリースされるまで攻撃者たちが当該脆弱性をゼロデイとして悪用していたようです。
そこで本稿では、当該脆弱性がどのような機序で悪用されるのかを見ていきます。
Microsoft Windows Error Reporting (WER: Windows エラー報告)とは
Windows エラー報告 は、イベントに基づいて柔軟なフィードバックを行うためのしくみで、Windows で検出可能なハードウェア/ソフトウェア関連の障害情報を収集し、その情報を Microsoft に報告し、ユーザーに利用可能な解決策を提供するよう設計されています。
たとえば、Windows がシステム クラッシュや障害に遭遇した場合、エラー レポートが生成され、Windows エラー報告のレポート キュー ディレクトリにそのレポートが保存されます (C:\ProgramData\Microsoft\Windows\WER\ReportQueue
)。このディレクトリ以下には、レポートごとのサブディレクトリと関連メタデータを含む一意の Report.wer INI ファイルが置かれます。すべてのプロセスが障害報告できるよう、ReportQueue ディレクトリは、どのユーザーでも書き込みが可能です (下図参照)。
図 1 Windows エラー報告のキュー ディレクトリ
生成後のレポートは、さらなる分析のために Microsoft に送信する必要があります。この情報のやりとりをトリガーする方法には何種類かあって、その 1 つがタスク スケジューラの Windows Error Reporting\QueueReporting
スケジュール タスクを利用する方法です。このタスクはセキュリティの観点で見て興味深く、次のような特徴をもっています。
- タスクの [セキュリティ オプション] セクションで定義されているとおり、システム権限で実行される
- タスクを要求時に実行できる
- 決め打ちのコマンドライン引数を指定して専用バイナリ コードを実行する (
wermgr.exe -upload
)
図 2 Windows エラー報告のタスク スケジュール
実行されると、wermgr.exe は保留になっているレポート ファイルやディレクトリとやり取りをする、つまりレポート ファイルを読み取り、解析し、ほかのディレクトリにコピーし、ときには削除することもあります。要するにここには、誰にでも書き込み権限のあるファイルにアクセス可能な、最上位特権で動作するコンポーネントがあり、注意して実装しないと深刻なセキュリティ脆弱性が生じる可能性がある、ということになります。
ファイルシステム リンクの悪用
Windows は、さまざまな種類のファイルシステム リンクをサポートしています。リンクを使用すれば、あるファイルやディレクトリがべつの意図したファイルやディレクトリを指すようにすることができます。ごく簡単に言うなら、リンクはいったんスキャン・再解析された後は、ユーザーを意図したべつのパスにリダイレクトするようになります。セキュリティの観点から見ると、最大の脅威はハードリンクとマウントポイントの悪用によるものでしょう。というのもこれらを悪用すれば、ユーザーは、もともと書き込み権限を持っていないファイルやディレクトリにもリンクできるようになるからです。
たとえば次の例は、kernel32.dll に対する書き込み権限を持っていないユーザーが、c:\temp\Dir\x.dll と C:\Windows\System32\kernel32.dll
の間にリンクを作成する様子を示しています。ハッカーにとっては、より高い特権をもつコンポーネントにリダイレクトさえできればそれで用が足りるのです。それだけあれば、機微な重要ファイルの読み書きに加え、それらの削除すら可能になります。
図 3 ユーザーが書き込み権限を持っていないファイルにハードリンクを作成する様子
Windows エラー報告の特権の昇格の脆弱性について
かいつまんで言えば、ハッカーは、Windows エラー報告の機能を悪用して、先に説明したファイルシステムのリンクを使ってレポート ディレクトリ内のファイルをコンピュータ上のべつの意図したファイルにリンクすることで、自分が読み取り・書き込み・削除をしたいほかのファイルに対し、そのための権限を割り当てることができるようになります。
もうすこし詳しく説明するなら、当該脆弱性は次のようにして悪用されます。
- ステップ 1: wermger.exe がレポート ディレクトリ以下すべてのファイルを 1 つずつ解析し、それらを Microsoft に送信します。
- ステップ 2: wermger.exe が Report.wer INI ファイルの破損を検出した場合、当該ファイルを削除するためにプロセス実行者権限を付与してファイルの DACL (discretionary access control list、随意アクセス制御リスト) プロパティを変更し、そののちに最終的な削除を行います。
- エクスプロイト: ハッカーは、「wermger.exe によるファイルの DACL 読み取り」から「当該ファイルに削除権限が付与されるまで」までのごく短かい隙を突きます。攻撃者がそうした破損ファイルとシステム上にあるべつのファイルとの間にリンクを作成した場合、DACL 読み取り後に wermgr.exe がほかのファイルのセキュリティ記述子を誤って変更してしまいます。これがきわめて、きわめて深刻なシナリオであることに疑いの余地はないでしょう。
ステップ 1:
最初に wermgr.exe -upload
が行うのは、wermgr!DoCoreUpload
関数の呼び出しです。wermgr!DoCoreUpload
関数は、ReportQueue 以下のすべてのサブディレクトリを一覧する関数です。この関数が、エラーレポートを読み取って、Microsoft に送信します。
1 2 3 4 5 6 7 8 9 10 11 |
int64 DoCoreUpload(/* ... */) { /* ... */ Ret = WerpSubmitReportFromStore(ReportPath, /* ... */); if (Ret >= 0) { /* Report successfully uploaded */ } else { if (Ret == ERROR_FILE_CORRUPT) { DeleteCorruptedReportFromStore(ReportPath); } } } |
ステップ 2:
wermgr.exe が Report.wer INI ファイルの破損を検出し、後で削除するために DACL を変更します。具体的には以下を行います。
- 最初に
wermgr!DeleteCorruptedReportFromStore
関数がレポートのサブディレクトリ以下のすべてのファイルを一覧にします。 - その後、
wermgr!PreparePathForDeletion
関数が各ファイルの権限を変更します。これが本脆弱性において核心となる部分です。なぜなら、この関数がkernel32!GetFileSecurity
関数を使ってファイルのセキュリティ記述子を読み込み、kernel32!SetFileSecurity
関数を呼び出して、削除を指定したセキュリティ記述子をファイルに適用するからです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
int64 PreparePathForDeletion(wchar_t* FileName) { PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; DWORD BytesRead = 0; PDACL Dacl = NULL; /* ... */ if ( !GetFileSecurity(FileName, DACL_SECURITY_INFORMATION, NULL, 0, &BytesRead) ) { /* ... */ return; } SecurityDescriptor = new BYTE[BytesRead]; if ( !GetFileSecurity(FileName, DACL_SECURITY_INFORMATION, SecurityDescriptor, BytesRead, &BytesRead) ) { /* ... */ return; } if ( GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted) ) { /* ... */ HANDLE TokenHandle = NULL; PACL NewAcl = NULL; EXPLICIT_ACCESS ExplicitAccess = {0}; /* ... */ LPVOID UserName = new BYTE[/* ... */]; GetTokenInformation(TokenHandle, TokenUser, UserName, &BytesRead); ExplicitAccess.Trustee.ptstrName = UserName; ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_NAME; ExplicitAccess.grfAccessMode = GRANT_ACCESS; ExplicitAccess.grfAccessPermissions = DELETE | /* ... */; /* ... */ SetEntriesInAcl(1, &ExplicitAccess, Dacl, &NewAcl); InitializeSecurityDescriptor(&SecurityDescriptor, 1); SetSecurityDescriptorDacl(&SecurityDescriptor, 1, NewAcl, 0); SetFileSecurity(FilePath, DACL_SECURITY_INFORMATION, &SecurityDescriptor); } } |
正確なタイミングでリンクを作成することは非常にむずかしいのですが、根気強いハッカーなら成功するまで何度でもやってみることでしょう。また、攻撃者はおそらく実行可能ファイル (DLL、EXE、またはスクリプト) を狙ってそれらを悪意のあるペイロードで上書きすることでしょう。なぜなら、上書きされたファイルが後でシステムの権限で実行されることを知っているからです。
Trapsの振る舞い検知によるシステム保護
エンドポイントの保護とレスポンスを提供するパロアルトネットワークスの Traps™ は、エンドポイント上の脅威を阻止し、ネットワーク、クラウドのセキュリティ対策と連携することにより、サイバー攻撃を未然に防ぎます。Traps は、高度な攻撃も自動検出して対応する機械学習 (ML) と人工知能 (AI) を組み込み、攻撃テクニック、攻撃の振る舞いを観測することにより、マルウェア、エクスプロイト、ランサムウェアを阻止します。本稿で説明したような脆弱性の悪用を防止するため、Traps の Behavioral Threat Protection (BTP、振る舞いベースの脅威保護) 機能は、一連のイベントにまたがる悪意のある行動を監視し、攻撃を検出すると直ちにこれを終了させます。さらに、機械学習による Traps のローカル解析は、悪意のあるペイロードの実行を防止します。
Traps について更に詳しくは https://www.paloaltonetworks.jp/products/secure-the-endpoint/traps をご確認ください。