VBS エンクレーブの悪用による回避型マルウェアの作成
目次
1. はじめに
2. 仮想信頼レベル
3. VBSエンクレーブとは
4. エンクレーブマルウェア
5. 検知
6. 結論
7. 謝辞
概要
仮想化ベースのセキュリティ(VBS)は、最近の最も魅力的なセキュリティの進歩の 1 つです。OS の重要なコンポーネントを隔離する機能により、Microsoft は Credential Guard や Hypervisor-Protected Code Integrity(HVCI)などの機能を使用して、大幅なセキュリティ向上を実現しました。
VBSによって実現される、見落とされがちな機能の1つが、VBSエンクレーブです。これは、プロセスの領域を分離し、他のプロセス、プロセス自体、さらにはカーネルにアクセスできないようにする技術です。
VBS エンクレーブにはさまざまなセキュリティアプリケーションが含まれており、Microsoftはそれらを使用していくつかの注目すべきサービスを実装しています。これには、物議を醸しているリコール機能も含まれています。。さらに、Microsoft は VBS エンクレーブのサードパーティ開発をサポートし、積極的に導入を推進しています。
エンクレーブはシステムのセキュリティを確保するのに役立ちますが、攻撃者にとっても非常に魅力的です。エンクレーブ内で実行されるマルウェアは、メモリーベースの検知やフォレンジックでは発見されない可能性があります。
私たちは VBS エンクレーブを調査し、それが悪意のある目的でどのように使用される可能性があるかを理解することを目指しました。このブログ記事では、その主な調査結果について詳しく説明します。また、これまでに文書化されていない VBS エンクレーブの動作を調査し、攻撃者がその内部で悪性コードを実行するために利用するシナリオを説明し、「エンクレーブマルウェア」が使用できるさまざまな手法を検証することで、VBS エンクレーブについて詳しく説明していきます。
また、Mirageについても紹介します。Mirageは、「脆弱なエンクレーブの持ち込み」と呼ばれる新しいアプローチに基づくメモリ回避手法です。攻撃者は正当なエンクレーブの古い、脆弱性のあるバージョンを使用して、このようなステルスな回避技術をどのように実装するのか、詳しく説明します。
仮想信頼レベル
Windows は従来、プロセッサー・リング・レベルによって、ユーザーアプリケーションによる OS の改ざんを防いでいました。このハードウェアの機能では、OS とユーザーアプリケーションを分離できます。カーネルは ring0 で動作し、ring3 ユーザー・モード・アプリケーションから分離されます。このアプローチの問題は、攻撃者に OS を侵害するための比較的簡単なパスを提供してしまうことです。これが Kernel Exploit です。
Windows カーネルは非常に広範な攻撃面を公開しています。カーネル自体が公開するさまざまなサービスと同様に、膨大な数のサードパーティ製ドライバーによって、Kernel Exploit と思われるものが絶えず発生しています。このような脆弱性を悪用するプログラムを使用することで、攻撃者は OS のあらゆる側面を制御できる可能性があります。ユーザー/カーネル モードの境界は不十分であることが証明されました。
このギャップを埋めるために、Microsoft は仮想信頼レベル(VTL)の形で OS にセキュリティの境界を追加しました。VTL 権限はメモリーアクセスに基づいています。各信頼レベルにより、その下で実行されているエンティティにはそれぞれ異なる物理メモリーへのアクセス権限が与えられます。これらの権限により、下位の VTL は上位の VTL のメモリーにはアクセスできなくなります。
従来のプロセッサー・リング・アーキテクチャと同様に、VTL は OS を VTL0 から(最大で)VTL16 までのさまざまな実行「モード」に分離します。ring0 の権限が最も高いプロセッサーリングとは異なり、上位の VTL ほど権限は高くなります。
Windows は現在、VTL0 と VTL1 の 2 つ(VTL2 も使用されますが、このブログ記事では扱いません)の主要な信頼レベルを使用しています。VTL0 は、カーネルやユーザーモードのアプリケーションなど、従来の OS コンポーネントを実行するために使用されます。VTL1 は VTL0 よりも権限が高く、セキュアカーネルモードと隔離ユーザーモードという2つの新しい実行モードを作成します。
セキュア カーネル モード
セキュア カーネル モードとは、ring0 VTL1 実行モードを指します。このモードは、セキュアカーネルを実行するために使用されます。カーネルが VTL1 で動作するため、通常のカーネルより権限が高くなっています。これらの権限を使用して、セキュアカーネルは通常のカーネルにポリシーを適用し、機密性の高いメモリー領域へのアクセスを制限することができます。
前述したように、カーネルは大きな攻撃面を公開しており、侵害されやすくなっています。カーネルからいくつかの権限を削除し、その権限をセキュアカーネルに付与することで、カーネル侵害の影響を軽減することができます。
理論的には、セキュアカーネルの侵害によって攻撃者がシステムを完全に侵害する可能性もありますが、このシナリオははるかに可能性が低くなります。なぜなら、セキュアカーネルは非常に限定的であり、サードパーティ製のドライバーをサポートしていないため、攻撃面が大幅に減少しているからです。
隔離されたユーザーモード
VTL1 では、「隔離されたユーザーモード」(IUM)と呼ばれる、別の興味深い実行モードも作成されます。これは、ring3 VTL1 実行モードを指します。IUM は、セキュアプロセスを実行するために使用されます。これは、VTL1 のメモリー隔離機能を使用する特別なタイプのユーザー・モード・プロセスです。IUM 内部のメモリーは、通常のカーネルを含む VTL0 コードからはアクセスできません。この実行モードは、Credential Guard などの隔離ベースの機能の基盤となっています。
つまり、VTL0/1 を導入すると、実行モードが 4 つになります(図 1)。
- Ring0 VTL0:通常のカーネルモード
- Ring0 VTL1:セキュア カーネル モード
- Ring3 VTL0:通常のユーザーモード
- Ring3 VTL1:隔離されたユーザーモード
VBS エンクレーブとは
IUM によって有効になるもう 1 つの機能は、VBS エンクレーブです。VBS エンクレーブは、IUM 内に存在するユーザー・モード・プロセスの一部であり、ここには「エンクレーブモジュール」と呼ばれる DLL をロードできます。
モジュールはエンクレーブにロードされると、「信頼された実行環境」になります。エンクレーブ内のデータやコードは、VTL0 で実行されているものにアクセスできないため、改ざんや窃取を防ぐことができます(図 2)。この機能は、システムを侵害する可能性のある攻撃者から機密性の高い操作を隔離するのに役立ちます。
ユーザーモードのプロセスは、専用のWindows API を呼び出してエンクレーブを作成し、そのエンクレーブにモジュールをロードして初期化することができます。エンクレーブモジュールは、この目的のために特別にコンパイルされた DLL の形式で提供されます。エンクレーブが初期化されると、ホスティングしているユーザー・モード・プロセスはそのメモリーにアクセスできなくなり、エンクレーブモジュールによってエクスポートされた関数を CallEnclave API を使用して呼び出すことによってのみ、エンクレーブと対話できるようになります。
図3は、このプロセスを実装するコードの例です(より詳細な例は Microsoft が提供しています)。
Microsoft は VTL1 へのアクセスを可能な限り制限することを目指しているため、DLL をエンクレーブにロードするためには、Microsoft が発行した特別な証明書を使用して適切に署名されている必要があります。このような署名なしでモジュールをロードしようとすると、失敗します。エンクレーブモジュールに署名するオプションは、信頼できるサードパーティにのみ委任されます。興味深いことに、これらのモジュールを 誰が ロードできるかには制限はありません。署名されている限り、どんなプロセスでも、任意のモジュールをエンクレーブにロードできます。
エンクレーブモジュールは小さな「計算ユニット」として機能することを目的としており、システムとのやり取りやシステムへの影響は非常に限られています。そのため、エンクレーブモジュールは最小限の API セットしか使用できず、ほとんどのOSコンポーネントにアクセスできません。
エンクレーブ内で使用可能な API は、VTL1 にロードされた専用ライブラリからインポートされます。たとえば、通常のプロセスは ntdll.dll ライブラリに依存してOSからサービスを要求しますが、エンクレーブモジュールは vertdll.dll を使用します。これは、Syscall を介してセキュアカーネルと通信するために使用される「代替」ntdll です。
エンクレーブマルウェア
エンクレーブマルウェアの概念は、攻撃者にとって極めて魅力的です。それには次の 2 つの大きな利点があります。
隔離されたメモリー領域で実行される:エンクレーブのアドレス空間は、VTL0 で実行されているもの(EDR や分析ツールなど)にはアクセスできないため、検知が非常に複雑になります。
追跡不能な API コール:エンクレーブ内からの API コールは EDR には検知されません。EDR は、システムライブラリ内にフックを配置してユーザーモードで API を監視し、ドライバーを使用してカーネル内のアクティビティを監視します。エンクレーブからトリガーされた API コールは、VTL1 から実行され、これらの「フック」された VTL0 コンポーネントを経由しないため、これらの手法では検出できません。
図 4 に、この利点を示します。Windows API を呼び出す通常のプロセスは、NTDLL 内部のフックまたはカーネル自体を介して監視できます。しかし、エンクレーブモジュールは VTL1 常駐vertdllを通過し、セキュアカーネルへの呼び出しを実行します。どちらも EDR にはアクセスできません。
この可能性を認識し、私たちはエンクレーブマルウェアの概念を調査することにしました。この目的のためにエンクレーブを活用するためには、次の 2 つの疑問に答える必要があります。
- 攻撃者はエンクレーブ内でどのようにして悪性コードを実行するのか
- エンクレーブ内で実行に成功した攻撃者はどのような手法を使用するのか
攻撃者はエンクレーブ内でどのようにして悪性コードを実行するのか
前述したように、エンクレーブモジュールは、Microsoft が発行した証明書を使用して署名されている必要があります。つまり、エンクレーブ内で独自のコードを実行できるのは、エンクレーブモジュールによって承認されたエンティティだけです。それにもかかわらず、攻撃者にはいくつかの選択肢があります。
まず、攻撃者は OS の脆弱性を利用することができます。その一例が、CVE-2024-49706です。Alex Ionescu 氏(Winsider Seminars & Solutions 在籍)によって発見されました。この脆弱性により、攻撃者は署名されていないモジュールをエンクレーブにロードできる可能性があります。この脆弱性は Microsoft によって修正されましたが、将来的に、意欲的な攻撃者が同様のバグを発見する可能性があります。
2つ目の簡単なアプローチは、正当な署名を取得することです。これは、Microsoftが Trusted Signing プラットフォームを通じてエンクレーブ署名をサードパーティに公開しているため可能です。決して簡単ではありませんが、高度な攻撃者が Trusted Signing エンティティへのアクセス権を取得し、独自のエンクレーブに署名できることもあります。
私たちは、これら 2 つのオプションに加えて、攻撃者が VBS エンクレーブ内でコードを実行できるようにする、デバッグ可能なエンクレーブモジュールの悪用と脆弱なエンクレーブの悪用の 2 つの追加テクニックについても詳しく調査しました。
デバッグ可能なエンクレーブモジュールの悪用
VBS エンクレーブモジュールを作成する際、開発者はデバッグ可能になるように設定できます。この設定でモジュールをコンパイルすると、デバッグが可能になります。エンクレーブモジュールは VTL1 で実行されるため、デバッグは通常不可能です。デバッガーがエンクレーブメモリーにアクセスしてデータを取得したり、ブレークポイントを配置したりできないためです。図 5 に、エンクレーブ内のメモリーアドレスからのデバッガーの読み取りが失敗する例を示します。
興味深いことに、デバッグ可能なエンクレーブモジュールが実行された場合、このモジュールは VTL1 にロードされます。デバッグを有効にするために、セキュアカーネルはデバッグ可能なエンクレーブモジュールに適用されるいくつかの例外を実装しています。たとえば、そのようなモジュールのメモリーからの読み込みを試みると、通常のカーネルは SkmmDebugReadWriteMemory セキュアカーネル呼び出しを実行し、対象のモジュールが本当にデバッグ可能であることを検証した上で、要求された操作を実行します。
この例を図 6 に示します。デバッグ可能なエンクレーブモジュールをロードすると、デバッガーはエンクレーブメモリーから正常に読み取ることができます。
同様に、デバッグ可能なエンクレーブモジュール内のメモリ権限も VTL0 プロセスによって変更できます(SkmmDebugProtectVirtualMemory セキュアカーネル呼び出しで実装されている、例外)。
エンクレーブの核心的な目的である VTL0 からのメモリーの分離が損なわれるため、Microsoft では、開発者にデバッグ可能なエンクレーブモジュールを出荷しないよう強く呼びかけています(図 7)。デバッグ可能なモジュールを使用すると、そのモジュールで処理されるデータが簡単に公開される可能性があります。
デバッグ可能なエンクレーブモジュールを実行する本番アプリケーションのリスクは明らかですが、攻撃者は実際、未署名のコードを VTL1 で実行するという別の目的のためにそれらを悪用する可能性があります。攻撃者が 1 つでも、デバッグ可能な署名済みエンクレーブモジュールを入手した場合、次の4つのステップを実行することでVTL1コードを実行できます。
- GetProcAddress を使用して、エンクレーブモジュール内のルーチンのアドレスを取得する
- ルーチンメモリー保護を RWX に変更する
- ルーチンコードを任意のシェルコードで上書きする
- CallEnclave を使用して、ルーチンをトリガーする
図 8 に、このプロセスを実装するコードを示します。
攻撃者の視点から見た明らかな問題は、これが両刃の剣であることです。攻撃者がエンクレーブメモリーにアクセスできるのと同様に、EDR もアクセスできるからです。とはいえ、これには API 監視を回避できるという利点があります。エンクレーブモジュールによって実行される API コールは依然として VTL1 DLL とセキュアカーネルを経由し、EDR の可視性が制限されます。
全体的に、この手法は、エンクレーブ内で実行することによって得られるいくつかの利点を活かした、ステルス性の高い「semi-VTL1」インプラントを作成する場合に役立つかもしれません。
私たちは、VirusTotal などの情報源を使用して、デバッグ可能な署名付きエンクレーブモジュールを特定しようとしましたが、執筆時点ではうまくいっていません。しかし、十分に時間が経ち、エンクレーブテクノロジーが普及してくれば、最終的に何らかのモジュールが流出するのは間違いないでしょう。
脆弱なエンクレーブの持ち込み
ここまで説明したように、Windows は署名を使用して、信頼されていないエンクレーブが VTL1 にロードされるのを防いでいます。このアプローチは、エンクレーブ特有のものではありません。この概念は、信頼されていないドライバーが Windows カーネルで実行されるのを防ぐドライバー署名の強制(DSE)を通じて生まれました。
この強制を回避するために、攻撃者はBring Your Own Vulnerable Driver(BYOVD)という手口を使用し始めました。つまり、攻撃者は自分のドライバーをロードできないため、代わりに既知の脆弱性を持つ、正規の署名済みドライバーをロードします。次に、攻撃者はこの脆弱性を悪用することで、カーネルで未署名コードを実行することができます。
私たちはこの方法を、エンクレーブの観点から詳しく調査したいと考えました。つまり問題は、脆弱な署名済みエンクレーブモジュールを悪用して IUM でコードを実行できるのかということです。
最初のステップは、このようなエンクレーブを見つけることでしたが、すぐに CVE-2023-36880 にたどり着きました。これは、Microsoft Edge で使用されている VBS エンクレーブモジュールの脆弱性です。この脆弱性により、攻撃者はエンクレーブ内の任意のデータを読み書きすることができます。この脆弱性は、Microsoft によって情報漏洩の脆弱性として評価されましたが、注釈には、限定的なコード実行の可能性があることも示されています(図 9)。
この脆弱性は、Chrome Security Teamの Alex Gough 氏により発見され、同氏は、この脆弱性を悪用する概念実証も共有しました。このエンクレーブの脆弱なバージョンを VirusTotal で見つけた後、私たちはこの脆弱性を悪用したコードの実行を開始しました。
当初は、読み取り/書き込みプリミティブを悪用して、エンクレーブスタックを ROP チェーンで上書きすることで、最終的にエンクレーブ内でシェルコードを実行できるようになると考えていました。このオプションを検討している間に、興味深い事実に遭遇しました。それは、エンクレーブが任意のコードガード(ACG)を使用して、未署名のコードが実行されないように保護されているということです。
ACG は、動的に生成されたコード(元のプロセス実行可能ファイルや DLL の一部ではなく、実行時に作成されたコード)の実行をブロックするように設計されたセキュリティの緩和策です。ACG は、次の 2 つのルールを適用して実装されています。
- プロセスの初期ロード後に、新しい実行可能ページを生成することはできない
- 既存の実行可能なページは書き込み可能にできない
ACG は通常のカーネルではデフォルトで適用されますが、ユーザーモードでは、使用するように設定されたプロセスにのみ適用されます。調査により、エンクレーブを含む IUM プロセスでは、ACG は通常のカーネルと同様に自動的に適用されることがわかりました。
これは、VirtualAlloc を使用して、エンクレーブ内に新しい RWX ページの割り当てを試みることで確認できます。この操作は、エラーコード 0x677、STATUSE_DYNAMIC_CODE_BLOCKED で失敗します(図 10)。VirtualProtect を使用して実行可能ページの権限を変更したり、ページの実行可能ファイルを変更したりしようとすると、同じ結果になります。
このふるまいを理解するために、SecureKernel!NtAllocateVirtualMemoryEx を調べます。これは、IUMで動的メモリ割り当てを処理するセキュアカーネル関数です。この関数は、要求された保護マスクを評価し、実行可能ページが要求されると、ACGエラー STATUS_DYNAMIC_CODE_BLOCKED を返します。既存の IUM ページへの変更を防ぐため、SkmmProtectVirtualMemory にも同様のチェックが実装されています(図 11)。
エンクレーブ内で ACG をバイパスし、未署名コードをそのコードにロードする方法は見つかりませんでした。理論的には、完全な ROP 攻撃が可能であり、攻撃者が VTL1 で任意の API を呼び出すことができる可能性がありますが、この方向は追求していません。それでも、脆弱なエンクレーブに対応する別の興味深いアプリケーションを特定することができました。これについては、この記事の後半で説明します。
エンクレーブ内で実行に成功した攻撃者はどのような手法を使用するのか
エンクレーブには悪意のあるアクティビティが発生する可能性が多く、動機のある攻撃者であればそれを起動することも可能であると理解したうえで、次に取り組んだ問題は、この種のマルウェアにどのような手法が利用可能かということでした。
最も簡単なのは、エンクレーブを本来の使用目的に従うことです。エンクレーブが攻撃者から機密データを保護できるのと同様に、攻撃者は自身の「秘密」を VTL0 エンティティから隠して使用することができます。
これは、ペイロードを EDR の範囲外に保存したり、暗号化キーをアナリストから隠したり、機密性の高いマルウェア設定をメモリーダンプから除外したりするなど、多くのシナリオで役立ちます。
より高度なオプションに関しては、従来のマルウェア技術の多くは、エンクレーブ内では実装できません。エンクレーブはシステム API の限られたサブセットしか使用できないため、ファイル、レジストリ、ネットワーク、その他のプロセスなどの主要な OS コンポーネントとは相互作用できません。
それにもかかわらず、エンクレーブ内で実行可能な技術はいくつか存在し、IUM で動作することによる利点を活かすことができます。
VTL0 ユーザー・モード・メモリーへのアクセス
システムへのアクセスは制限されていますが、エンクレーブは依然として 1 つの重要なリソース、つまりプロセスメモリーにアクセスできます。エンクレーブは、VTL0 を含むプロセスアドレス空間全体で読み取り/書き込み操作を実行できます。
このアクセスには、いくつかの制限が適用されています。エンクレーブ内で実行されるコードはメモリーのアクセス許可に準拠し、それを変更することができません。つまり、エンクレーブは書き込み不可能なメモリーに書き込むことも、実行不可能なメモリーの実行可能ファイルを変更することもできません。図 12 は、エンクレーブ内で実行されるコードを示しており、これらのさまざまな可能性と制約を示しています。
VTL0 ユーザー・モード・メモリーにアクセスすることで、さまざまな有用な技術を実装できます。悪意のあるエンクレーブをターゲットプロセスにロードすることで、こっそりと機密情報を監視して盗むことも、プロセス内の値を修正して、その動作を変更することもできます。
エンクレーブを使用してこれらの手法を実装することには大きな利点があります。前述のように、エンクレーブから API をトリガーすることで、EDR の監視を回避できます。これらの手法のメモリーアクセスはエンクレーブによって実行されるため、検出されないままの可能性があります。
VTL0 ユーザー・モード・コードの実行
エンクレーブは、適切な権限を与えられた VTL0 ユーザー・モード・メモリーから読み取り/書き込みを行うことができますが、VTL0 に保存されたコードは、実行権限を持っていてもエンクレーブ内では実行できません。
エンクレーブ内で VTL0 コードを実行できないにもかかわらず、エンクレーブにはそれを「リモート」トリガーするオプションがあります。VTL0 アドレスを指定した CallEnclave API を使用することで、エンクレーブは通常のユーザー・モード・スレッドで VTL0 コードの実行をトリガーできます(図 13)。
ユーザー・モード・プロセスを「代わりに動作」させることで、エンクレーブは通常は不可能な方法でシステムに間接的にアクセスできます。たとえば、エンクレーブは、ファイルからの読み取り、ソケットの作成などを行う VTL0 ルーチンをトリガーすることができます。
ただし、この方法でユーザー・モード・コードを実行しても回避の面での利点はありません。コードは他のユーザー・モード・コードと同様に実行されるため、EDR に検出される可能性があります。
アンチデバッグ
エンクレーブマルウェアのもう 1 つの興味深い用途は、アンチデバッグです。エンクレーブ内で実行されているコードは、デバッガーを含む VTL0 アプリケーションからアクセスできないため、マルウェアにはそれらに対して大きな優位性が与えられます。
エンクレーブに公開される API の数が減少したことは、従来のすべてのアンチデバッグ技術がエンクレーブから利用できるわけではないことを意味します。たとえば、NtQueryInformationProcess や IsDebuggerPresent API、およびすべての日時APIは、エンクレーブでは使用できません。これにもかかわらず、いくつかの選択肢があります。
まず、プロセスの VTL0 アドレス空間へのエンクレーブのアクセスを利用して、プロセス PEB を手動で読み取り、「BeingDebugged」フラグの値を確認することができます。デバッガーが検知された場合、プロセスはエンクレーブで終了できます。
もう 1 つのアプローチは、時間ベースのアンチデバッグ技術を実装することです(図 14)。エンクレーブでは Date and Time API を使用できませんが、rdtsc アセンブリ命令を使用することはできます。この命令は、起動時からのプロセッサー・クロック・サイクル数を返します。これを使用して、異なるエンクレーブ呼び出し間の所要時間を測定し、大きな遅延が検知された場合はプロセスを終了することができます。
デバッグ対策チェックとともにコードの重要な部分をエンクレーブに移動することで、動的分析にほぼ完全に対抗するマルウェアを作成できます。 マルウェアは正常に動作するためにエンクレーブを必要とし、ユーザー・モード・プロセスでは内部で実行されているチェックを修正することはできません。正しく実装されている場合、このアプローチは Hyper-V またはセキュアカーネルのデバッグによってのみ無効にできます。
BYOVE — ラウンド 2
前のセクションでは、IUM でコードを実行するために、脆弱なエンクレーブモジュールの悪用を試みました。これが不可能かもしれないとわかったとき、私たちは、BYOVE の概念に他の用途があるかどうかを確認し、脆弱なエンクレーブモジュールをさらに調査することにしました。
この脆弱性(CVE-2023-36880)は、エンクレーブモジュールによってエクスポートされる、SealSettings関数とUnsealSettings関数に起因します。SealSettings 関数は、データバッファへのポインターを受け取り、それを暗号化し、結果を呼び出し側から提供された宛先アドレスに書き込みます。UnsealSettings は同様の方法で動作し、指定されたバッファを復号して、指定されたアドレスに書き込みます。
これら両関数の問題点は、宛先アドレスも送信元バッファアドレスのいずれも検証しないため、エンクレーブ自体の内部アドレスも含めてプロセス内の任意のアドレスを指すことができることです。図15は、脆弱なコードを示しています。UnsealSettings は、ユーザーが指定した任意のアドレスに対してmemcpyを実行しています。
この脆弱性は、攻撃者に 2 つの機能を提供します(図 16)。
エンクレーブ内の任意の書き込み:攻撃者はSealSettingsを呼び出して任意のデータを暗号化し、次にUnsealSettingsを呼び出して、エンクレーブ内の宛先アドレスを指すことができます。これにより、元のデータがエンクレーブメモリーに書き込まれます。
エンクレーブ内の任意の読み取り:攻撃者は、送信元バッファーポインターとしてエンクレーブ内のアドレスを提供しながら、SealSettingsを呼び出すことができます。これにより、エンクレーブはエンクレーブメモリーからデータを暗号化し、攻撃者が制御する場所に書き込みます。攻撃者は、その後UnsealSettingsを呼び出してこのデータを復号化し、エンクレーブから任意のデータを読み取ることができます。
Mirage:VTL1 ベースのメモリー回避
VTL1 でコードを実行することはできませんでしたが、任意の書き込みプリミティブによって、次の 2 つの独自の機能が提供されます。
VTL1 に任意のデータを保存し、VTL0 エンティティからアクセスできなくする
通常のプロセスアドレス空間(VTL0)に VTL1 から任意のデータを書き込み、VTL0エンティティがこの操作を監視できないようにする
さらに、これらの機能は、署名済みのエンクレーブモジュールのロードによって促進されるため、攻撃者に利用されるる可能性があります。攻撃者自身が署名を行う必要はありません。
これらの機能の可能性を示すために、私たちは、メモリースキャン回避技術を考案して「Mirage」と名付けました。Mirageは、無害な状態と武器化された状態を継続的に切り替えるペイロードを作成する回避技術である、Gargoyleから着想を得ています。(図 17)。
Gargoyle は、実行可能メモリーと実行不可能メモリーを切り替えることでこれを実装していますが、Mirage は VTL1 と VTL0 メモリー間を移行することで同様の結果を達成することを目指しています。VTL1 エンクレーブメモリーにシェルコードを保存し、定期的に VTL0 に転送して実行し、VTL0 メモリーからすぐに消去します(図 18)。
このアプローチには主に 2 つの利点があります。まず、ペイロードはほとんどの時間を VTL1 に隠れて過ごすため、メモリースキャンやダンプに対して耐性があります。これは、Gargoyle 技術よりも有利です。なぜなら、休止段階では、ペイロードは「ステルス性がある」だけでなく、アクセスできないからです。
2 番目の利点は、VTL0 へのシェルコードの書き込みがエンクレーブによって実行されることです。前述したように、EDR は VTL1 で実行されるコードを監視できません。つまり、通常の EDR フックでは、シェルコードがメモリーに書き込まれている際に、それを傍受できません。
私たちは Mirage の PoC を開発しました(図19)。この PoC は、この手法の背景にあるアイデアを実証するためだけのものであり、完全に武器化されたものではありません。
検知
現在、エンクレーブは非常に限られた数のアプリケーションでのみ使用されています。より広く採用されるようになったとしても、任意のプロセスではなく、特定のプロセスによってのみロードされるでしょう。たとえば、calc.exe が VBS エンクレーブをロードすることはないでしょう。
このため、異常なエンクレーブを使用することで検知される可能性が大きく高まります。防御者は、VBS エンクレーブの既知の合法的な使用のベースラインを構築し、それからの逸脱をフラグすることで、これを活用する必要があります。エンクレーブの使用は、エンクレーブ API を監視し、ロードされたエンクレーブ DLL を検知するという 2 つの方法で識別できます。
エンクレーブ API
次の API は、ホストプロセスによって VBS エンクレーブを管理するために使用され、ロードされていることを示している可能性があります。
- CreateEnclave
- LoadEnclaveImageW
- InitializeEnclave
- CallEnclave
- DeleteEnclave
- TerminateEnclave
ロード済み Enclave DLL
エンクレーブの異常な使用を検知する別の方法としては、エンクレーブによって一般的に使用される環境 DLL(Vertdll.dll と ucrtbase_enclave.dll)のロードを検知する方法があります。これらの DLL はエンクレーブ以外では使用できないため、プロセスでエンクレーブが使用される可能性が高いことを示します。
結論
VBS エンクレーブは、開発者がアプリケーションの機密性の高いセクションを保護するための優れたツールを提供しますが、これまでに示したように、脅威アクターがマルウェアを「保護」するために使用することもできます。この概念はほとんど理論上のものですが、将来、高度な脅威アクターが悪意のある目的で VBS エンクレーブを使用し始める可能性は確かに存在します。
謝辞
最近、このプロジェクトと非常に類似した研究プロジェクトを行った Offsec の Matteo Malvica 氏と Outflank の Cedric Van Bockhaven 氏の取り組みに感謝の意を表します。2 部構成の連載の第 1 部のブログ記事もご覧ください。第 2 部は、Insomni’Hack 2025 の後に公開予定ですので、どうぞお楽しみに。