エンドポイントに隠れる: シェルコードによる検出の回避

Windows API calls for CreateRemoteThread injection news

真のレッドチーム評価には、検出を回避するという二次的な目的が必要です。成功したレッドチーム評価の栄光の一部は、システム上の何にも、または誰にも検出されないことです。最新のエンドポイント検出および対応 (EDR) 製品が長年にわたって成熟してきたため、レッド チームはそれに追随する必要があります。このブログ投稿では、 FireEye Mandiant Red Teamが最新の EDR 製品をバイパスし、被害者のシステムで完全なコマンド アンド コントロール (C2) を取得するためにペイロードを作成する方法について、いくつかの洞察を提供します。

シェルコードのインジェクションまたはその実行は、被害者のシステムで C2 ペイロードを起動するための私たちのお気に入りの方法です。しかし、シェルコードとは何ですか? Michael Sikorski は、シェルコードを「自己完結型の実行可能コードを表すために一般的に使用される用語」と定義しています (Practical Malware Analysis)。 Empire、Cobalt Strike、Metasploit などのほとんどの商用ペネトレーション テスト フレームワークには、ツールに組み込まれたシェルコード ジェネレーターがあります。通常、シェルコード ジェネレーターは、生の出力として生成するかアプリケーション ソースとして生成するかに応じて、バイナリ形式または 16 進数形式のいずれかになります。

すべてのペイロードにシェルコードを使用するのはなぜですか?

レッドチームの評価ペイロードでシェルコードを使用することで、使用するペイロードの種類を非常に柔軟にすることができます。シェルコード ランナーは、さまざまな種類のペイロードに組み込むことができるさまざまなプログラミング言語で記述できます。この柔軟性により、ペイロードをカスタマイズして、クライアントの特定のニーズや、レッドチームの評価中に発生する可能性のある特定の状況をサポートできます。シェルコードはペイロード内から起動したり、すでに実行中のプロセスに挿入したりできるため、いくつかの手法を使用して、ターゲット環境のシナリオとテクノロジーに応じて、ペイロードが EDR 製品からの検出を回避する能力を高めることができます。暗号化やカスタム エンコーディングなど、シェルコードを難読化するためのいくつかの手法が存在するため、EDR 製品が商用 C2 ツールからシェルコードを単独で検出することは困難です。シェルコードの柔軟性と回避特性が、レッド チームの評価時にシェルコード ベースのペイロードに大きく依存している主な理由です。

シェルコードインジェクション対。実行

レッドチーム評価の最も重要な部分の 1 つは、ターゲット システムで正常に、確実に、密かに実行されるペイロードを開発することです。ペイロードは、独自のプロセス内からシェルコードを実行するか、最終的にシェルコードを実行する別のプロセスのアドレス空間にシェルコードを挿入できます。このブログ記事では、シェルコード インジェクションをリモート プロセス内で実行されるシェルコードと呼び、シェルコード実行をペイロード プロセス内で実行されるシェルコードと呼びます。

シェルコード インジェクションは、レッド チームや悪意のある攻撃者が EDR 製品やネットワーク防御者からの検出を回避するために使用する手法の 1 つです。さらに、多くの EDR 製品は、Windows プロセスの予想される動作に基づいて検出を実装しています。たとえば、任意のプロセス (たとえば、DefiniteNotEvil.exe) のコンテキストから Mimikatz を実行する攻撃者は、そのプロセスが lsass.exe にアクセスすることを EDR ツールが想定していないため、完全に検出またはブロックされる可能性があります。ただし、定期的に lsass.exe にアクセスする svchost.exe などの Windows プロセスに挿入することで、EDR 製品がこれを予期された動作と見なすため、これらの検出を回避できる可能性があります。

このブログ投稿では、シェルコードを実行するための 3 つの異なる手法について説明します。

  • スレッドの作成
  • CreateRemoteThread
  • QueueUserAPC

これらの各手法は、シェルコードへのスレッドの割り当てを担当する Windows API 関数に対応し、最終的にシェルコードが実行されます。 CreateThread はシェルコードの実行に使用される手法であり、CreateRemoteThread と QueueUserAPC はシェルコード インジェクションの形式です。

以下は、3 つの異なる手法のそれぞれでシェルコードを実行するプロセスの概要です。

スレッドの作成
  1. 現在のプロセスにメモリを割り当てます
  2. 割り当てられたメモリにシェルコードをコピーします
  3. 新しく割り当てられたメモリの保護を変更して、そのメモリ空間内からコードを実行できるようにする
  4. 割り当てられたメモリ セグメントのベース アドレスを持つスレッドを作成します。
  5. スレッドハンドルが戻るのを待つ
CreateRemoteThread
  1. 注入するプロセスのプロセス ID を取得する
  2. 対象プロセスを開く
  3. ターゲット プロセス内に実行可能メモリを割り当てる
  4. 割り当てられたメモリにシェルコードを書き込む
  5. 割り当てられたメモリ セグメントの開始アドレスを使用して、リモート プロセスにスレッドを作成します。
Windows API calls for CreateRemoteThread injection
図 1: CreateRemoteThread インジェクションの Windows API 呼び出し
QueueUserAPC
  1. 注入するプロセスのプロセス ID を取得する
  2. 対象プロセスを開く
  3. ターゲット プロセス内でメモリを割り当てる
  4. 割り当てられたメモリにシェルコードを書き込む
  5. 新しく割り当てられたメモリの保護を変更して、そのメモリ空間内からコードを実行できるようにする
  6. 割り当てられたメモリ セグメントの開始アドレスを使用して、リモート プロセスでスレッドを開きます。
  7. スレッドが「アラート可能」状態になったときに実行のためにキューにスレッドを送信する
  8. スレッドを再開して「アラート可能」状態にする
QueueUserAPC インジェクションの Windows API 呼び出し
図 2: QueueUserAPC インジェクションの Windows API 呼び出し

コマンド実行

これまでに話したことを分解してみましょう。

  • 悪意のあるコードはシェルコードです。悪意のある作業を実際に実行するステージ 0 またはステージ 1 のコードです。
  • インジェクションまたは実行によってコードを実行する標準の「シェルコード ランナー」アプリケーション。ほとんどの人は独自のシェルコード ランナーを作成しているため、これを真のマルウェアと見なす必要はありません。真のマルウェアはシェルコードそのものです。

すべてをカバーしたので、コンパイルしたコードを実行するメソッドが必要です。通常、これは実行可能ファイル (EXE) またはダイナミック リンク ライブラリ (DLL) のいずれかです。レッド チームは、コンパイル済みコードを実行するLiving Off the Land Binaries (lolbins)コマンドの使用を好みます。

lolbin を利用できる理由は、管理されていないエクスポートのためです。大まかに言えば、実行可能ファイルが DLL を呼び出すとき、DLL 内の特定のエクスポートを探して、そのエクスポート内のコードを実行します。エクスポートが適切に保護されていない場合、実行可能ファイルが探しているとわかっているエクスポート名で独自の DLL を作成し、任意のコードを実行できます。この場合、これがシェルコード ランナーになります。

すべてを一緒に入れて

私たちは、アンマネージ エクスポートを通じて lolbin を利用するシェルコード ランナー DLL の開発に着手しました。また、コード ベースを更新する必要なく、注入されたシェルコードと注入されていないシェルコードの両方を実行する柔軟性を提供します。この努力の結果、 DueDLLigenceと呼ばれる C# シェルコード ランナーが生まれました。このソース コードは GitHub ページにあります。

DueDLLigenceプロジェクトは、図 3 に示すグローバル変数の値を切り替えるだけで、このブログ投稿で以前に説明したさまざまなシェルコード手法をすばやく簡単に切り替える方法を提供します。

シェルコード手法変数
図 3: シェルコード手法の変数

DueDLLigence DLL には、その中に 3 つのアンマネージ エクスポートが含まれています。これらのエクスポートは、図 4 に示すようにRasautouControl 、およびCoregenのネイティブ Windows コマンドで使用できます。

ネイティブ Windows 実行可能ファイル

必須のエクスポート名

実行に使用される構文

ラサウトゥ

パワーシェル

rasautou –d {dll へのフル パス} –p powershell –aa –ee

コントロール

クリップレット

コンパイルされた「dll」拡張子の名前を「cpl」に変更し、ダブルクリックするだけです。

MSIExec

Dllunregisterserver

msiexec /z {dll へのフル パス}

図 4: DueDLLigence の実行概要

ソース コードを開くと、例では図 5 に示すエクスポートが使用されていることがわかります。

エクスポートされたエントリ ポイントのソース コード
図 5: エクスポートされたエントリ ポイントのソース コード

最初にすべきことは、独自のシェルコードを生成することです。この例を図 6 に示します。この例では、Cobalt Strike を使用して「rev_dns」リスナー用の生のシェルコードを生成しています。それが完了したら、Linux でbase64 -w0 payload.bin > [outputFileName]コマンドを実行して、シェルコードの base64 エンコード バージョンを生成します (図 7 参照)。

シェルコード生成
図 6: シェルコードの生成
シェルコードを base64 に変換する
図 7: シェルコードを base64 に変換する

次に、58 行目の base64 でエンコードされたシェルコードを、独自の x86 または x64 シェルコードの base64 バージョンに置き換えるだけです。図 6 のスクリーンショットでは x86 ペイロードが生成されています。x64 ペイロードを生成するには、[x64 ペイロードを使用する] ボックスをオンにする必要があります。

この時点で、別のプロジェクトを使用しているときに適切に動作しないことがあるため、DueDLLigence Visual Studio プロジェクトに Unmanaged エクスポート ライブラリを再インストールする必要があります。図 8 に示す NuGet パッケージ マネージャー コンソールを開き、 Install-Package UnmanagedExports -Version 1.2.7 コマンドを実行して再インストールできます。

NuGet パッケージ マネージャーを開く
図 8: NuGet パッケージ マネージャーを開く

アンマネージ エクスポート ライブラリを再インストールし、58 行目の base64 でエンコードされたシェルコードを置き換えたら、コンパイルの準備は完了です。ソースをビルドし、bin フォルダーで DLL を探します。 DLL をテストして、適切なエクスポートが関連付けられていることを確認することを強くお勧めします。 Visual Studio Pro には Dumpbin.exe ユーティリティが付属しており、これを DLL に対して実行してエクスポートを表示できます (図 9 参照)。

Dumpbin.exe の出力
図 9: Dumpbin.exe の出力

GitHub ページにあるさらに多くの lolbin テクニックを使用して、リストを必要なだけ拡張できます。

ペイロードのフットプリントが小さくなるように、生成されたそれぞれのペイロードで使用されないアンマネージド エクスポートを削除することをお勧めします。一般に、ペイロードを作成したりコードを書いたりする場合、これは優れたトレード クラフトです。私たちの業界では、最小権限の原則があります。これが最小コードの原則です。

シェルコード インジェクションの最新の検出

シェルコードが提供するすべての回避的な利点にもかかわらず、シェルコード インジェクションの検出に関しては希望があります。プロセス インジェクションのいくつかの異なる方法を調べました。

このシェルコード ランナーでは、シェルコード インジェクション手法 (CreateRemoteThread および QueueUserAPC) によってプロセスが中断状態で生成され、実行中のプロセスにシェルコードがインジェクトされます。挿入するプロセスを explorer.exe として選択し、ペイロードが MSIExec で実行されるとします。これにより、cmd.exe が msiexec.exe を生成し、msiexec.exe が次に explorer.exe を生成するプロセス ツリーが作成されます。

プロセスツリー分析
図 10: プロセス ツリー分析

エンタープライズ環境では、SIEM を使用してテレメトリ データを収集し、すべてのエンドポイントで cmd.exe -> msiexec.exe -> explorer.exe プロセス ツリーが発生する頻度を特定できます。親子プロセスの関係を使用して、防御側は異常検出を通じて潜在的なマルウェアを特定できます。

API フックは、マルウェア作成者が一般的に使用する Windows API 呼び出しの使用を監視および検出するために、EDR および AV 製品で一般的に使用されます。セキュリティ ソフトウェアは、PsSetCreateProcessNotifyRoutine(Ex) や PsSetCreateThreadNotifyRoutine(Ex) などのカーネル ルーチンを利用して、CreateRemoteThread などの特定の API 呼び出しがいつ使用されたかを監視できます。この情報をプロセス レピュテーションや企業全体のテレメトリなどの他のデータと組み合わせることで、潜在的なマルウェアに対する忠実度の高いアラートを提供できます。

プロセス インジェクションが発生すると、あるプロセスが別のプロセスのアドレス空間にあるメモリ領域のメモリ保護を変更します。 VirtualProtectEx などの API 呼び出しの使用を検出することにより、あるプロセスが別のプロセスに許可されているアドレス空間のメモリ保護を変更することになります。特に PAGE_EXECUTE_READWRITE アクセス許可が使用されている場合、このアクセス許可はシェルコード内での書き込みと実行を許可するために使用されます。同じメモリ空間。

レッドチームや悪意のあるアクターが新しいプロセス インジェクション技術を開発し続けているため、ネットワーク防御者やセキュリティ ソフトウェアは絶えず変化する状況に適応し続けています。 VirtualAllocEx、VirtualProtectEx、CreateRemoteThread、NTQueueAPCThread などの Windows API 関数呼び出しを監視すると、潜在的なマルウェアを特定するための貴重なデータを得ることができます。 CREATE_SUSPENDED フラグと CREATE_HIDDEN フラグを指定した CreateProcess の使用を監視すると、攻撃者が中断された非表示のプロセスを作成して挿入するプロセス インジェクションの検出に役立つ場合があります。

隠しエンドポイント

これまで見てきたように、プロセス インジェクション手法は、Windows API 関数を呼び出す一貫した順序に従う傾向があります。たとえば、どちらのインジェクション手法も VirtualAllocEx を呼び出してから WriteProcessMemory を呼び出し、プロセスがこれら 2 つの API をこの順序でいつ呼び出すかを識別することは、プロセス インジェクションを検出するための基礎として使用できます。

結論

評価中にペイロードの最終段階としてシェルコードを使用することで、レッド チームは、検出を回避する手法を実装しながら、さまざまな環境でペイロードを柔軟に実行できます。 DueDLLigence シェルコード ランナーは、シェルコードとプロセス インジェクションの両方の回避特性を利用して、レッド チームに検出を回避する方法を提供する動的ツールです。コマンド ラインでの LOLbin の実行と、API およびプロセス レベルでのプロセス インジェクションの検出は、攻撃者がアプリケーション ホワイトリストの採用の増加に伴い、ますます土地を離れて生活することを余儀なくされているため、防御方法論に組み込む必要があります。

参照: https://www.mandiant.com/resources/blog/staying-hidden-on-the-endpoint-evading-detection-with-shellcode

Comments

Copied title and URL