Loki C2を用いたWindows Defenderアプリケーション・コントロールのバイパス
Windows Defenderアプリケーション・コントロール(WDAC)は、実行の対象を、信頼できるソフトウェアのみに制限するセキュリティー・ソリューションです。セキュリティー境界として分類されているため、Microsoftでは、適格なバイパスに対してバグ・バウンティー(脆弱性報奨金制度)の支払いを提供しており、競争の激しい活発な研究分野となっています。
WDACバイパス・バグ・バウンティー申請の典型的な結果は次のとおりです。
Microsoft社のWDAC推奨ブロック・リストを見ると、Jimmy Bayne氏(@bohops) やCasey Smith氏(@subTee)のような伝説的な人物が、修正されずに名誉ある言及を与えられているWDACバイパスを発見しています。このリスト以外にも、 LOLBAS Projectには、Microsoft社のブロック・リストで認識されていない、未修正のバイパスがさらに含まれています。一例として、Microsoft Teamsアプリケーションが挙げられますが、これはLOLBASで文書化されているにもかかわらず、依然としてWDACバイパスとして有効です。
レッド・チーム・オペレーション中にWDACに遭遇した際、私たちはそれを正常にバイパスし、以下の手法を使用して第2段階のコマンド・アンド・コントロール(C2)ペイロードを実行しました。
1. MSBuild.exeのような既知のLOLBINを使用
2. 信頼できないDLLを使用して、信頼できるアプリケーションをDLLサイドローディングする
3. クライアントのWDACポリシーからカスタム除外ルールをエクスプロイト
4. C2デプロイメントを可能にする信頼できるアプリケーションで、新しい実行チェーンを見つける
Ruben Boonen(@FuzzySec)がWild West Hackin' Festの講演「Statikk Shiv:エクスプロイテーション後のElectronアプリケーションの活用」で説明したように、Electronアプリケーションは、HTML、JavaScript、CSSなどの標準Webテクノロジーを使用してデスクトップ・アプリケーションをレンダリングするWebブラウザとして機能します。ElectronのJavaScriptエンジンはNode.jsで、ホスト・オペレーティング・システムと対話できる強力なAPIを提供します。これらのAPIにより、ファイルの読み取りや書き込み、プログラムの実行、ネイティブ・アプリケーションに特有のオペレーションなどのアクションが可能になります。
ランタイム時にElectronアプリケーションはJavaScriptファイルを読み取り、そのコードを解釈し、Electronプロセス内で実行します。以下のアニメーションは、Microsoft Teams Electronアプリケーションがランタイム時にJavaScriptファイルを読み取り、child_processモジュールを使用してwhoami.exeを実行する方法を説明しています。
この例では、Teams ElectronプロセスがJavaScriptファイルを読み取り、child_processモジュールを使用してwhoami.exeを生成します。このモジュールはElectronプロセスをトリガーして、エクスポートされたAPIであるuv_spawnを実行し、オペレーティング・システムと対話して新しいプロセスを作成します。
Windowsアプリケーションの従来のアーキテクチャーは次のように構成されています。
EXEは、DLLからエクスポートされた関数を呼び出し、その機能を拡張します。しかし、Electronアプリケーションはこのアーキテクチャーを逆転させます。DLLからAPIを呼び出すEXEの代わりに、Electron EXE自体がAPIエクスポートを公開します。これは、次のものによって呼び出されます。
この構造により、Node.js JavaScriptおよびノード・モジュールは、従来のブラウザ内のJavaScriptでは不可能な方法でオペレーティング・システムと対話できるようになります。
下の画像では、@hasherezadeが開発した素晴らしいツールであるPE Bearを使用して、Teams Electronアプリケーションを検証しています。この結果を見ると、Teams Electron実行ファイルには2,977のエクスポートされたAPIが含まれていることがわかります。この大規模なAPIサーフェスは、Node.jsのJavaScriptファイルとノード・モジュールがオペレーティング・システムと対話するために活用できる広範な機能を提供します。
Electronアプリケーションはランタイム時にJavaScriptを実行するため、このJavaScriptファイルを変更すると、攻撃者は任意のNode.jsコードをElectronプロセスに挿入することができます。Node.jsとChromium APIを活用することで、JavaScriptコードはオペレーティング・システムと対話できるようになります。
信頼できるElectronアプリケーションのJavaScriptファイルを変更し、任意のNode.js JavaScriptコードを実行する機能は、私には発見できませんでした。見つけることができた最も古い参考情報は、2022年まで遡ります。
2022年初頭、Andrew Kisliakovがブログ「LOLbinsとしてのMicrosoft Teamsおよびその他のElectronアプリ」を公開しました。Andrewと@mrd0xは、調査結果をLOLBASプロジェクトに提供しました。
2022年後半には、Valentina Palmiotti(@chompie1337)、Ellis Springe(@knavesec)、Rubenがこのアプローチをさらに探め、その後レッド・チーム・オペレーションで使用される内部永続化ツールの開発につながりました。
同じく2022年には、Michael TaggartがElectronアプリケーションを修正してコマンド実行を可能にするツールであるquASARプロジェクトをリリースしました。彼のブログ「Quasar:Electronアプリの脆弱性」では、2022年9月にElectronプロジェクトのメンバーから連絡があり、整合性チェックは実験的な機能であり、将来的には完全にサポートされることを期待していると告げられたことが書かれています。
Signalのような新しいElectronアプリケーションを個人的に試してみたところ、JavaScriptファイルの変更を妨げている一部のElectronアプリケーションでは、整合性チェックが実施されていることがわかりました。それでも、積極的に配信されているElectronアプリケーションの多くは依然として脆弱です。
この手法は実際の攻撃でも観察されています。2022年には、配信サーバー上でバンドルされているJavaScriptファイルを変更するという手段で、ある脅威アクターがMiMiチャット・アプリケーションにバックドア攻撃を仕掛けました。Trend Microは、これをサプライチェーン攻撃と特定しました。これにより、侵害されたElectronアプリがエンドユーザーに配信され、第2段階のC2ペイロードをダウンロードして実行する悪意のあるJavaScriptコードが実行可能になりました。
2024年4月に私Bobby Cooke(@0xBoku)は、金融分野のクライアント向けのレッド・チーム・オペレーションに備えて、使用する新しい実行チェーンを探していました。この分野では、セキュリティー基準が高くて規制も厳しく、WDACなどの追加のセキュリティー・コントロールが実装されることが多くあります。調査中に、私は別の脆弱なElectronアプリケーションを発見しました。ただし、Microsoftが署名したものではないため、クライアントのWDACポリシーをバイパスする可能性は低いとみなしました。
次に、レガシーのMicrosoft Teamsアプリケーションに切り替えました。このアプリケーションはMicrosoftが署名しており、最も厳格なWDACポリシーもパイパスできます。この時点でDylan Tran(@d_tranman)も私の調査に参加し、私たちは任意のNode.js JavaScriptの実行から、第2段階のC2シェルコードの実行にエスカレーションする方法を探し始めました。
Node.jsはAPIを通じてオペレーティング・システムと対話できますが、開発者がWINAPIやNTAPIを直接呼び出すことができるC言語の機能性の一部が欠けています。このギャップを埋めるために、開発者はNode.jsフレームワークの機能を拡張するノード・モジュールを作成しました。C++コードからコンパイルされたこれらのモジュールは、WINAPIを呼び出し、Node.js APIと対話し、Electronアプリケーション内でJavaScriptを実行できます。コンパイル済みノード・モジュールは.node拡張子を有し、DLLロード・イベントを介してWindowsプロセスにロードされます。
調査中に複数のElectronアプリケーションを検証し、そこに署名されたノード・モジュールを分析しました。これらのモジュールはJavaScriptから直接操作できることがわかり、その組み込み機能を活用できるようになりました。
シェルコードを実行するための独自のカスタム・ノード・モジュールを作成することは実行可能なアプローチであり、Loki C2の機能でもありますが、「鶏が先か卵が先か」という問題が生じます。JavaScriptからノード・モジュールをロードすると、DLLロード・イベントがトリガーされますが、未署名のDLLに対する厳格なルールを適用するWDACポリシーによってブロックされる場合があります。幸いなことに、正規のElectronアプリケーションには多数の署名付きノード・モジュールが存在します。
ペイロードを実行するこのアプローチは有望であると思われたので、調査結果をValentinaに共有し、彼女もこの調査に加わりました。彼女の助けを借りて、署名付きノード・モジュールのリバース・エンジニアリングをさらに深く掘り下げ、任意のシェルコードの実行を可能にする脆弱性や組み込みの機能を探しました。
有用な機能を備えたノード・モジュールの一例として、Visual Studio CodeにバンドルされているMicrosoftの署名付きモジュールであるwindows_process_tree.nodeが挙げられます。PE Bearで検証すると、次のような2つのエクスポートされた関数が存在することが明らかになりました。
従来のDLLとは異なり、ノード・モジュールは利用可能なすべての関数をエクスポート・テーブルにリストアップしません。napi_register_module_v1エクスポート関数は、Electronプロセスによって呼び出され、モジュールをロードし、エクスポートされた機能をElectronプロセスに公開する役割を担います。これはブリッジとして機能し、Electronプロセス内のJavaScriptがモジュールの関数を呼び出して対話できるようにします。
ノード・モジュールに呼び出し可能なすべての関数をリストアップする簡単な方法は、次のNode.jsコードを活用することです。
PowerShellでこのNode.jsスクリプトを実行すると、windows_process_tree.nodeに2つの呼び出し可能な関数が存在することがわかります。それらはgetProcessListとgetProcessCpuUsageです。
粘り強く取り組めば、JavaScriptからこれらの関数を呼び出す方法を特定できます。Node.jsの制限の1つは、システム上で実行されているすべてのプロセスをリストアップするためのAPIが組み込まれていないことです。この制限こそが、MicrosoftがこのモジュールにgetProcessList関数を導入した理由です。導入の結果、VS Code Electronアプリケーションの機能は拡張されました。
child_processモジュールを使用してPowerShellを子プロセスで実行し、実行中のプロセスの詳細を返すことで、JavaScriptで直接この情報を取得できます。以下の画像では、Loki C2がプロセス・リストを取得するPowerShell子プロセスを生成しています。
このアプローチは、重大なオペレーション上のセキュリティー・リスクをもたらします。PowerShell子プロセスを実行すると検出率が高くなり、オペレーションにフラグが付けられたり、書き込みが行われる可能性が高くなります。これを回避するために、Loki C2はwindows_process_tree.nodeなどの署名付きノード・モジュールを活用して、Node.jsの機能を拡張しています。
Loki C2にはpsコマンドが含まれています。このコマンドは、以下の図のように、windows_process_tree.nodeのMicrosoft署名付きモジュールをロードし、getProcessList関数を呼び出すことでプロセス情報を取得します。
windows_process_tree.nodeモジュールのgetProcessList関数を呼び出すLoki C2 JavaScriptコードは以下のとおりです。getProcessListはプロセス・データをJSON形式で返します。Loki C2はこれを構造化されたテーブルにフォーマットし、可読性を高めます。
ノード・モジュール内の関数を適切に呼び出す方法を決定することは、その内部構造が文書化されていないため、困難な場合があります。しかし、NSAが開発したGhidraなどのツールを使用し、Valentinaのような熟練したリバース・エンジニアと協力することで、私たちはこれらのモジュールの分析とその機能との相互作用を特定することができました。
Valentinaは最終的に、未署名のDLLをロードせずに第2段階のC2シェルコードを実行する方法を発見しましたが、詳細の開示については彼女に任せることにします。Dylan、Valentina、そして私は協力して、今後のフィッシング・キャンペーンの安定性を確保するための技術の改良に取り組みました。
残念ながら、私たちの初回のEメール・フィッシング・キャンペーンは、ブルー・チームによって報告およびブロックされてしまいました。この挫折の後、Brett Hawkins(@h4wkst3r) と私は2回目のキャンペーンの準備を始めました。指定されたペイロード担当者として、私は同じペイロードを再利用したくありませんでした。再利用すると、ブルー・チームが私たちを追跡し、2回目のキャンペーンを阻止するのが非常に簡単になるためです。しかし、Valentinaの技術を新しいペイロードに適用する時間が十分になかったため、別のアプローチを使用して新しいペイロードの開発を開始しました。
通常、信頼できるElectronアプリケーションで任意のJavaScriptを実行する機能は、C2エージェントをデプロイするコマンドの実行に使用されます。しかし、Valentinaの技術がなければ、このアプローチはWDACに対して失敗するでしょう。というのも、最終的には未署名のプログラムを実行する必要があり、ブロックされる可能性が高いからです。
2回目のキャンペーンの準備に数日しか残されていない中、私は「C2フレームワーク全体をJavaScriptで構築するのはどうだろう」と考えました。
C2エージェント自体がJavaScriptで完全に記述されている場合、最も厳格なWDACポリシーに照らしてもC2チャネルを確立できます。そこから偵察を行い、第2段階のC2ペイロードをデプロイする方法を見つけられるでしょう。未署名のDLLロード・イベントは発生せず、信頼できるTeamsプロセス内で実行されるJavaScriptのみが発生します。
私たちが必要としていたのは、次のことを実行するための機能でした。
調査中に記述したNode.jsコードをすべて活用し、一晩でC2の概念実証をまとめました。翌日、私はその内容をDylanに共有し、一緒にそれを完全に機能するJavaScriptベースのC2へと迅速に拡張しました。私たちのC2には次の機能がありました。
現在はLoki C2として知られるJavaScript C2は、2回目のキャンペーンで成功を収めました。それ以来、私たちはLoki C2の改良と拡張を続け、さらに機能を追加し、安定性を高め、機能を強化してきました。
この調査から得たElectronに関するすべての知識を活かして、私はElectronフレームワークを使用したLoki C2用のグラフィカル・ユーザー・インターフェースを構築しました。
以下の動画では、Loki C2を使用して厳格なWDACポリシーをパイパスする方法を説明します。以下の2つのセクションでは、動画内で起こっている内容について解説しています。
このデモでは、AWSの最新のWindows Server 2025 EC2インスタンス上に、App Control Policy Wizardを介してWDACがデプロイされます。このウィザードには、次の3つの基本ポリシー・テンプレートが用意されています。
デフォルトWindowsモードは最も厳格で、次の実行が可能です。
こちらのデモでは、デフォルトWindowsモード・ポリシーが選択されています。デフォルトの監査モードは無効になっており、WDACはポリシーを即座に適用します。さらに、Microsoftの推奨WDACブロックリストのルールを含む「Merge with recommended block lists(推奨ブロックリストと統合)」オプションがオンになります。App Control Wizardは、WDACポリシーのXMLおよびCIPファイルを生成し、CITool.exeを使用してサーバーにデプロイします。
WDACがアクティブになった後にLoki C2 Agent.exeの実行を試みても、実行ファイルがMicrosoftによって署名されていないため、WDACはこのファイルをブロックします。
この制限を回避するには、Loki Agentの/resources/app/ディレクトリーのコンテンツをコピーします。デスクトップ上には「teams」という名前のフォルダーがあり、正規のレガシーMicrosoft Teamsアプリケーションが含まれています。Teams.exeのプロパティを表示すると、Microsoftによる署名を確認できます。
次に、Teamsのアプリケーションの/resources/ディレクトリーに移動し、既存のファイルをすべて削除します。削除後、以前コピーしたLoki C2 Agentの/resources/app/ディレクトリーを~/Desktop/teams/resources/app/にペーストします。
この変更により、Teams.exeをクリックして実行できるようになります。Teamsの実行ファイルはMicrosoftが署名しているため、WDACはこれをブロックしません。System Informerでは、WDACの介入なしにTeamsプロセスが正常に作成されたことを確認できます。ただし、Teamsの/resources/app/ ディレクトリーをLoki C2 Agentのコードに置き換えたため、ElectronベースのTeamsアプリケーションは、信頼できるTeamsプロセス内でLoki C2 AgentのJavaScriptを実行可能になりました。
Teamsプロセスは、Loki C2クライアントに正常にコールバックします。その後、いくつかのコマンドを実行して侵害されたサーバーのリモート制御を実証します。
Loki C2で初期アクセスを取得した後、Shawn Jones(@anthemtotheego)と私が開発した内部C2であるDragonなど、より高機能な第2段階C2エージェントを実行する複数の方法を特定しました。Loki C2の最初の作成以降に発見したさまざまなエスカレーション方法は、この投稿ですべては公開しませんが、今後のリリースで取り上げる予定です。
正しく実装された場合、この手法は継続的にトップクラスのエンドポイントの検知と対応(EDR)ソリューションをバイパスします。ただし、ステルス性の高い第2段階C2がない場合、オペレーターは子プロセスでコマンドを実行するspawnによるコマンド実行に頼らざるを得ません。これにより、主要なEDRに対するエクスプロイテーション後の検知が迅速にトリガーされます。
Loki C2は、MITRE ATT&CK テクニック「T1218.011 - System Binary Proxy Execution:Electronアプリケーション」に準拠しています。
インターネットで検索した結果、Electronアプリケーションを空洞化し、そのコードを公開中のC2に置き換えるという手法が公に開示されたり、実際に利用されたりしている事例は見つかりませんでした。しかし、Loki C2を信頼できるレッド・チームと共有したところ、社内で同様の機能を開発したことが確認されました。
MITRE ATT&CK TTP、複数の研究出版物、およびLOLBASエントリーがあっても、このElectronアプリケーションの空洞化技術自体は検出されないままになっています。私の仮定では、EDR(エンドポイントの検知と対応)ソリューションは、これを検出することに焦点を当てているのではなく、コマンドを実行するための子プロセスの生成など、エクスプロイテーション後のインジケーターに焦点を当てています。私たちはこのような一般的なエクスプロイテーション後の検知を回避しながら、第2段階のC2をデプロイする手法を開発したため、検知を回避しながら複数のエンゲージメントでこの技術を使用することに成功しました。
これらすべてを念頭に置いて、次にベンダーが「100%のMITREカバレッジ」を謳っているのを聞いときは、それが実際に何を意味するのかを問うてみる価値があります。