プロセス作成プロパティを使用して回避テクニックをキャッチする

news

Microsoft Defender for Endpointで、攻撃者が検出を回避するために使用するプロセス実行クラスの既知および未知のバリエーションをキャッチできる堅牢な検出方法を開発しました。このクラスのステルス実行手法は、セキュリティ製品によって行われたいくつかの仮定を破り、攻撃者が従来のプロセス作成 syscall を使用してプロセス作成コールバックを回避することにより、マルウェア対策スキャンを逃れることを可能にします。このクラスの公に知られているバリエーションは、プロセス ドッペルガング、プロセス ハーパダーピング、およびプロセス ゴースティングです。

攻撃者が使用する回避手法には、多くの場合、信頼できるプロセスのコンテキスト内でマルウェアを実行したり、ファイル システムやメモリ スキャナーからコードを隠したりすることが含まれます。より巧妙な攻撃者は、プロセス ホストを慎重に選択して、無害な理由でこれらのアクションを実行することが多いプロセスによってアクションが実行されるようにします。たとえば、インターネットと通信するブラウザ プロセスは完全に正常に見えますが、同じことを行うcmd.exeのインスタンスは親指のように突き出ています。ただし、このクラスのステルス実行手法により、マルウェアは独自の悪意のあるプロセスを作成し、マルウェア対策エンジンがそれを検出するのを防ぐことができます。

このブログ投稿では、このプロセス実行クラスがどのように機能するか、および Windows の機能を利用して検出を回避する方法に関する詳細な分析を紹介します。また、可能な限り堅牢で将来性のあるものにすることを目的とした検出方法の開発に入る研究、設計、およびエンジニアリングの懸念事項についても紹介します。

ステルス プロセス実行の一般的なクラス

Windows システムでは、攻撃者が別のプロセス内でコードを実行するために使用するほとんどの方法は、プロセス インジェクションプロセス ハロウイングの 2 つのクラスに分類されます。これらのクラスにより、攻撃者は、実行可能ファイルから明示的に作成したり、ダイナミック リンク ライブラリ (DLL) を読み込ませたりすることなく、別のプロセス内でコードを実行することができます。同様のクラスの手法はプロセス インジェクションとも呼ばれますが、この用語は明確にするために、より具体的な定義で使用されます。

プロセス注入

最も広範で最も一般的なクラスであるプロセス インジェクションは、攻撃者が提供する実行可能メモリを既に実行中のプロセスに導入するさまざまな手法で構成されます。このクラスのテクニックは、次の 2 つの主要な部分で構成されています。

  • 書き込みプリミティブ: Windows API 関数、またはターゲット プロセスにマルウェアを導入するために使用される一連の API。
  • 実行プリミティブ:プロセスの実行を攻撃者が提供するコードにリダイレクトする Windows API メソッド。

従来のプロセス インジェクション フローの例としては、 VirtualAllocEx API を使用してターゲット プロセス内にバッファを割り当て、 WriteProcessMemoryを使用してそのバッファにマルウェア モジュールの内容を格納し、 CreateRemoteThreadを使用してターゲット プロセスで新しいスレッドを開始し、以前に挿入されたコード。

中空加工

プロセス ハロウイングでは、すでに実行中のプロセスを悪用する代わりに、攻撃者は中断状態で新しいプロセスを開始し、書き込みプリミティブを使用して、プロセスが実行を開始する前にマルウェア モジュールを導入する可能性があります。中断を解除する前にプロセスのエントリ ポイントをリダイレクトすることにより、攻撃者は明示的な実行プリミティブを使用せずにコードを実行する可能性があります。

両方のクラスのバリアント (および場合によっては組み合わせ) が存在し、主に使用される API によって互いに異なります。ステップの 1 つの目標を達成するために使用される別の関数は、エンドポイント保護製品がそのような動作をインターセプトする多数のポイントを通過しない可能性があり、検出ロジックを壊す可能性があるため、API は異なります。

新しいステルス技術

ここ数年で、前述のどのクラスにも厳密には当てはまらない、プロセス実行クラスからのステルス技術が出現しました。このクラスでは、既に作成されている (まだ実行されていない可能性がある) プロセスのメモリを変更する代わりに、マルウェアのイメージ セクションから新しいプロセスが作成されます。セキュリティ製品がファイルをスキャンする準備が整う頃には、マルウェアのビットは存在しなくなり、マルウェア対策スキャナーの敷物を効果的に引き離します。この手法では、防御者は別の検出方法を使用して、それを使用する攻撃をキャッチする必要があります。現在、このクラスの次のバリエーションは、次のように公に知られています。

  • プロセスのドッペルガング1:トランザクション NTFS 機能を悪用して、プロセスの作成に使用される実行可能ファイルの揮発性バージョンを作成し、ファイルがディスクにアクセスすることはありません。
  • プロセス ヘルパダーピング2:実行可能ファイルへの書き込み可能なハンドルを利用して、マルウェア対策サービスが実行可能ファイルをスキャンする前にディスク上のマルウェア ビットを上書きしますが、悪意のあるバージョンからプロセスが既に作成された後です。
  • プロセスのゴースト3:プロセスの実行可能ファイルに対する削除権限を持つハンドルを悪用して、スキャンされる前にプロセスを削除します。

上記のバリエーションを含むこのプロセス実行クラスは、オペレーティング システムの次の機能がセキュリティ製品による検出を回避するように設計されている方法を利用しています。

  • マルウェア対策エンジンは、変更のたびにファイルをスキャンするわけではありません。
  • プロセス作成コールバック (マルウェア対策エンジンが作成時にプロセスをスキャンできるようにするオペレーティング システムの機能) は、最初のスレッドがプロセスに挿入されたときにのみ呼び出されます。
  • 従来のプロセス作成 syscall であるNtCreateProcessExを使用すると、プロセスにスレッドを設定せずにプロセスを作成できます。

以下のセクションでは、これらの機能がどのように悪用されるかについて詳しく説明します。

ファイルはいつスキャンされますか?

このプロセス実行クラスの重要な機能は、ファイル スキャンを回避することです。理想的には、ファイルは変更されるたびにスキャンされます。そうしないと、攻撃者は単に既存のファイルを悪意のあるファイルに変更し、それを使用してプロセスを作成し、ファイルを元に戻すか削除する可能性があります。では、ファイルが変更されるたびにファイルがスキャンされないのはなぜでしょうか?

答えは、パフォーマンスの問題にあります。 1MB のファイルが開かれ、上書きが必要なバイトごとにWriteFileなどの API を呼び出すことによって上書きされるシナリオを考えてみましょう。ディスクに書き込まれるのは 1MB だけですが、ファイルを 100 万回スキャンする必要があるため、スキャンされるデータは最大 1 テラバイトになります。

この例は、検出可能な悪意のあるコンテンツがディスクに書き込まれないことを保証する良い方法ですが、消費する計算能力の量を考慮すると、実行不可能なソリューションになります。キャッシング ソリューションでさえ、リソースの使用率が高くなるのをメモリに移すだけです。製品は、マシン上で開かれているすべてのファイルの内容に関する情報を有用なものとして保持する必要があるからです。

したがって、ファイル スキャン エンジンの最も一般的な設計は、ファイル コンテンツのさまざまな一時的な状態を無視し、ファイルへのハンドルが閉じられるたびにスキャンを開始します。これは、アプリケーションによるファイルの変更が今のところ完了しており、スキャンが意味があることを示す最適なシグナルです。ファイルがプロセスとして実行しようとしているものを特定するために、マルウェア対策エンジンは、プロセス作成コールバックを通じてプロセス作成時にファイルの内容をスキャンします。

PsSetCreateProcessNotifyRoutineEx API によって提供されるものなど、カーネル内のプロセス作成コールバックは、マルウェア対策エンジンがプロセスの作成中にプロセスを検査できるようにするオペレーティング システムの機能です。プロセスが実行される前に、プロセスの作成を傍受し、関連する実行可能ファイルをスキャンすることができます。

プロセス作成通知は、プロセス作成 API が呼び出されたときに呼び出されるのではなく、最初のスレッドがプロセスに挿入されたときに呼び出されます。しかし、プロセスを作成するためにすべての一般的な高レベル API で使用されるシステムコールであるNtCreateUserProcessは、カーネルでプロセスを作成するために必要な多くの作業を行うように設計されているため、作成されたプロセスへの初期スレッドの挿入は、システムコール自体のコンテキスト。これは、ユーザー モードが何かを実行する前に、プロセスがまだ作成されている間にコールバックが起動することを意味します。

システムコール NtCreateUserProcess から呼び出されるプロセス作成コールバックのリストを含むコードのスクリーンショット。
図 1. NtCreateUserProcess から呼び出されるプロセス作成コールバック

コール スタックは、このシナリオでは、プロセス作成コールバックの呼び出しを担当する関数であるPspCallProcessNotifyRoutinesが、プロセスへの初期スレッドの挿入中にPspInsertスレッドから呼び出されることを示しています。また、後続のプロセス作成コールバックがすべてNtCreateUserProcess内から呼び出され、syscall が戻る前に両方の実行が終了することも示しています。これにより、マルウェア対策は、プロセスが作成されたときにマルウェア アクティビティをスキャンできます。これは、プロセスがNtCreateUserProcessを使用して作成されている場合に機能します。ただし、研究者が発見したように、この syscall とは別にプロセスを作成する方法は他にもあります。

プロセスはどのように作成されますか?

syscall NtCreateUserProcessは、Windows Vista のリリース以降にのみ利用可能になりました。 CreateProcess API またはNtCreateUserProcess syscall を使用する任意の API によって作成されたプロセスは、実行可能ファイルへのパスのみを提供します。一方、カーネルは、変更を許可する可能性のある共有アクセスなしでファイルを開き (SHARE_WRITE/SHARE_DELETE なし)、イメージ セクションを作成し、プロセスを実行する準備が整った状態でユーザー モードに戻ります (ほとんどの正当な Windows プロセスでは、追加の作業が必要になります)。ただし、NtCreateUserProcess syscall は、プロセスが何らかのコードを実行するために必要な最小限の作業を行います)。これは、攻撃者がNtCreateUserProcessを呼び出した後、実行可能ファイルを変更する時間や機能を持っていないことを意味し、スキャンされる前にのみ実行可能ファイルを変更します。

Windows Vista のリリースより前のバージョンの NT カーネルでは、 NtCreateProcessExという別のシステムコールが使用されていました。この関数は、カーネルで多くの作業を行うという原則に準拠しておらず、実際、最新の Windows プラットフォームでのプロセス作成に通常関連する多くの作業をユーザー モードに委任しています。

システムコール NtCreateProcessEx の関数シグネチャのコードのスクリーンショット。 NtCreateUserProcess とは異なり、この syscall にはパス引数を受け取るコードが含まれていません。
図 2. NtCreateProcessEx の関数シグネチャ。 path 引数がなく、SectionHandle が存在することに注意してください。

2 つの違いの 1 つは、 NtCreateProcessExは、 NtCreateUserProcessの場合のように、プロセス実行可能ファイルへのパスを引数として受け取らないことです。 NtCreateProcessExは、アプリケーションが独自にファイルを開き、そのファイルからイメージ セクションを作成することを想定しています。これは、プロセスのメイン イメージ セクションとして使用され、 NtCreateProcessExに渡されるハンドルです。

また、 NtCreateUserProcessとは異なり、 NtCreateProcessExは、プロセスにスレッドを設定せずにプロセス オブジェクトを作成します。ユーザー アプリケーションは、 NtCreateThreadなどの API を使用して初期スレッドをプロセスに明示的に挿入する必要があります。

PspCallProcessNotifyRoutine と PspInsertThread を呼び出したコールスタックのスクリーンショット。両方の呼び出しが NtCreateThreadEx 内から発生することが観察されています。
図 3. このコールスタックでは、PspCallProcessNotifyRoutine と PspInsertThread の呼び出しは、プロセス作成システムコール内からではなく、NtCreateThreadEx 内から発生します。

この情報をプロセス作成のコールバックについて知っていることと組み合わせることで、このステルスなプロセス作成手法の一般的なフローを考え出すことができます。

  1. 攻撃者はマルウェア ファイルを開き、一時的に変更可能な状態 (ハンドルを閉じずに書き込み可能、保留中またはコミットされていないトランザクション、およびその他の未公開トランザクションを削除) にしますが、マルウェア コンテンツは保持します。攻撃者はまだファイルを閉じていません。
  2. 攻撃者は、 NtCreateSection(Ex)を使用してファイル ハンドルから画像セクションを作成します。
  3. 攻撃者は、画像セクション ハンドルを入力として使用してプロセスを作成します。
  4. 攻撃者は、ファイルの一時的な状態を良性の状態に戻し (ファイルが削除または上書きされるか、トランザクションがロールバックされます)、ハンドルが閉じられます。この時点では、イメージ セクション オブジェクトがまだ存在するため、マルウェアのビットはメモリ内にまだ存在していますが、ディスク上にマルウェア コンテンツの痕跡はありません。
  5. 攻撃者は最初のスレッドをプロセスに挿入し、そのプロセスのプロセス作成通知コールバックを開始します。その時点で、スキャンするマルウェア コンテンツは残っていません。
  6. 攻撃者は、バッキング ファイルをスキャンせずにマルウェア プロセスを実行するようになりました。

この一般化されたフローでは、セキュリティ製品は、プロセスが従来のNtCreateProcessEx syscall を使用して作成されたことを認識できる場合、この手法のバリエーションを検出できる必要があります。これにより、敵対者は一時的な状態のファイルからプロセスを実行できます。

もちろん、DLL をロードして同様のトリックを実行することで、 NtCreateProcessExの必要性を回避できます。ただし、このシナリオでは、攻撃者は新しい DLL をプロセスにロードすることができます。プロセスは、ID を変更せずに完全なコード実行機能を既に備えているか、問題のある DLL を別のプロセスにリモートで配置して、本質的にプロセス インジェクションを実行します。どちらの場合も、回避方法としてのテクニックの有効性は大幅に低下します。

レガシー プロセスの作成の検出

この手法を使用して攻撃を検出するために認識される最初の異常は、プロセスが従来のNtCreateProcessEx syscall を使用して作成されたかどうかを調べることです。

これを行う最も簡単な方法は、NTDLL ライブラリの適切な関数でユーザー モード フックを利用することです。ただし、システムコールを呼び出すプロセスで攻撃者が任意の実行機能を持っていると想定されるため、このアプローチは簡単に回避できます。これは、セキュリティ製品によって傍受された機能をアンフックしたり、独自のアセンブリ コードからシステムコールを直接呼び出したりできることを意味します。セキュリティ製品がプロセス作成コールバックからユーザー モード コール スタックを走査し、戻りアドレスを既知の値と照合したとしても、攻撃者はアセンブリ コードでいくつかの創造的なプッシュとジャンプを使用して、なりすましユーザー モード コール スタックを自分の好みに合わせて構築します。

この動作の堅牢な検出を作成するには、ユーザー モードの敵対者によって変更またはスプーフィングできない情報を使用する必要があります。この良い例は、 追加の作成パラメーター(ECP) と呼ばれる Windows ファイル システムの概念です。

ECP は、カーネルまたはドライバーがキーと値の情報をファイルの作成/開く操作に添付できるようにする概念です。考え方は拡張ファイル属性と非常に似ていますが、ECP はディスク上のファイル全体に適用されるのではなく、開いているファイルの特定のインスタンスに関連する一時的なプロパティです。このメカニズムにより、オペレーティング システムとドライバーは、特定の状況下で開かれているファイルに応答できます。

このような特殊な状況の例として、サーバー メッセージ ブロック (SMB) を介して開かれるファイルがあります。これが発生すると、 GUID_ECP_SRV_OPENをキーとして、 SRV_OPEN_ECP_CONTEXT構造がIRP_MJ_CREATE IRPに追加されます。

この ECP コンテキストには、SMB クライアントとの通信に使用されるソケットに関する情報、アクセスされた共有の名前、いくつかの oplock 情報が含まれています。ドライバーはこの情報を使用して、オープン操作を適切に処理できます。これには、操作がリモートで行われたため、特別な処理が必要になる場合があります。

興味深いことに、 FsRtlIsEcpFromUserModeという名前のエクスポートされ、文書化された関数が存在し、ECP がユーザー モードまたはカーネル モードで発生したかどうかを判断します。これにより、ドライバーまたは OS でこの関数を使用することを忘れると、ユーザー モードの敵対者が ECP をスプーフィングする可能性があるため、セキュリティ上の問題が発生する可能性があるという懸念が生じます。ただし、OS には、ユーザーがユーザー モードから任意の ECP を直接指定できる機能がないため、そうではありません。関数自体は、不透明な ECP ヘッダー構造に特定のフラグが設定されているかどうかをチェックしますが、このフラグを変更できるコードが OS に存在しません。

プロセス作成 API 認識のための ECP の使用

Windows 10 以降、 NtCreateUserProcessを使用して新しいプロセスが作成されるたびに、非常に興味深い ECP がオペレーティング システムに追加されました。 Windows カーネルがプロセス実行可能ファイルを開くと、 GUID_ECP_CREATE_USER_PROCESS ECP とそれに関連するCREATE_USER_PROCESS_ECP_CONTEXTコンテキストがIRP_MJ_CREATE操作に適用されます。この ECP には、作成されるプロセスのトークンが含まれています。実際、実行可能パスを開くために使用される関数は、特にこの操作で ECP をサポートするために、 ZwOpenFileからIoCreateFileExに変更されました。

CREATE_USER_PROCESS_ECP_CONTEXT を示すコードのスクリーンショット。
図 4. CREATE_USER_PROCESS_ECP_CONTEXT

一方、前述のように、 NtCreateProcessExはプロセス実行可能ファイルを単独で開くのではなく、ユーザー自身が開いたファイルから作成されたセクション ハンドルの提供をユーザーに依存します。ユーザーが独自のハンドルにプロセス作成 ECP を設定する方法がないため、 NtCreateProcessExを使用して作成されたプロセスは、メイン イメージのIRP_MJ_CREATEにこの ECP がありません。レガシ API を使用していない場合でも ECP が存在しない場合がありますが、それらは認識できます。これらのケースを除いて、プロセスのメイン イメージに関連するファイル オブジェクトのIRP_MJ_CREATE操作でのCREATE_USER_PROCESS ECP の存在を使用して、 NtCreateUserProcessによって作成されたプロセスとNtCreateProcessExによって作成されたプロセスを正確に区別できるようになりました。

一時的な状態のファイルから作成されたプロセスの検出

従来のプロセス作成 API がいつ使用されたかを確認できるようになったので、次のステップは、従来のプロセス作成 API の使用が時間チェック時間 (TOCTOU) を悪用するために使用されていないかどうかを確認することです。 ) プロセス作成のコールバックに関する問題。これは、プロセスの作成に使用された実行可能イメージが開かれ、一時的な状態で使用されたことを意味します。これは、マルウェア対策エンジンによってスキャンされるときに、既にロールバックされています。 TOCTOU が悪用されたかどうかを特定するには、プロセスのメイン実行可能ファイルのイメージ セクションを調べることが重要です。

Windows は実行可能イメージをメモリに読み込み、メモリ セクション (メモリ マップ ファイルとも呼ばれます) を使用してプロセス間でメモリを共有します。開いているファイルの各FILE_OBJECT構造体には、 SectionObjectPointersと呼ばれるメンバーが含まれています。このメンバーには、ファイルがデータ ファイルとしてマップされているか実行可能ファイルとしてマップされているかに応じて、ファイルに関連するデータおよびイメージ セクション制御領域へのポインターが含まれています。このようなセクションで記述されたビットは、ディスク上のファイルまたはページ ファイルのいずれかによってバックアップされる場合があります (この場合、セクションのビットはディスク上に保持されません)。このプロパティは、マップされたセクションをフラッシュしてファイルまたはディスクから回復できるか、または単純にページアウトできるかを決定します。

ただし、画像セクションとそのバッキング ファイルの間の接続が切断されると、興味深いことが起こります。これは、たとえば、ファイルがリモート マシンまたは一部のリムーバブル ストレージにある場合、コピー オン ライトがトリガーされた場合、または最も重要なこととして、セクションが作成された後にファイルが何らかの形で変更された場合、または変更される可能性がある場合に発生する可能性があります。将来的に変更されます。このような場合、イメージ セクションは、作成元のファイルではなく、ページ ファイルによってバックアップされます。

イメージ セクションとそのバッキング ファイルの間の接続が切断されたときに生成されるコードのスクリーンショット。 WritableUserReferences メンバーが設定されているコード行が強調表示されます。
図 5. ディスクとのコヒーレンシを壊すセクションの制御領域。 WritableUserReferences メンバーが設定されていることに注意してください。

MmDoesFileHaveUserWritableReferences関数は、セクションのファイル オブジェクトへの書き込み可能な (より正確には変更可能な) 参照の数を呼び出し元に提供し、トランザクションの原子性を維持するためにカーネル トランザクション マネージャーによって使用されます。そうしないと、トランザクションがコミットされるときに、ファイルが書き込まれたり、削除されたり、単になくなったりする可能性があります。ゼロ以外の戻り値は、セクションの一貫性が失われ、セクションのバッキングをページ ファイルに切り替えるロジックがトリガーされたことを意味するため、この関数を検出に使用できます。これは、ファイルが TOCTOU を悪用して検出を回避するために必要な一時的な状態の 1 つにあることを判断するのに役立ちます。

Microsoft Defender for Endpoint による検出

前述の 2 つのプリミティブは、検出ロジックに組み合わせることができます。まず、 GUID_ECP_CREATE_USER_PROCESS ECP がないことで、プロセスがレガシー API NtCreateProcessExを使用して作成されたかどうかが検証されます。次に、関数MmDoesFileHaveUserWritableReferencesは、ファイルのイメージ セクションがページ ファイルによってサポートされているかどうかをチェックし、ファイルが一時的な状態にある間にプロセスが作成されたことを確認します。両方の条件を満たしていれば、TOCTOU が悪用されていると判断できます。これは、公開されている手法のいずれか、または同様の概念を使用しているがドライバーに組み込まれた機能を悪用して同様の効果を生み出すそのバリエーションによって行われます。

Microsoft Defender for Endpointは、このクラスのステルス プロセス実行における既知の手法をそれぞれ検出し、実際に見られるプロセス ゴースト、ヘルパダーピング、およびドッペルガングのバリエーションに対して特定のアラートを発します。各バリエーションの特定のアラートとは別に、一般化されたフローと、未公開のバリエーションを含むレガシー プロセス作成 API の悪用に対する検出が存在します。

プロセス ゴースト、ヘルパダーピング、およびドッペルガングに関連する検出に関する Microsoft Defender for Endpoint からの通知のサンプル スクリーンショット。
図 6. プロセス ゴースト、ヘルパダーピング、およびドッペルギャングのバリエーションに対する Microsoft Defender for Endpoint 検出。

このブログ投稿では、Windows 内部の知識を共有し、Microsoft Defender for Endpoint で検出回避を防ぐのに役立つ新しい検出方法を紹介します。 Microsoft Defender for Endpoint からのデータとシグナルはMicrosoft 365 Defenderにもフィードされるため、この新しい検出方法は保護テクノロジをさらに強化し、脅威に対する包括的で調整された脅威防御をお客様に提供します。

ここで説明するステルス実行手法は、脅威の状況が常に進化していること、および攻撃者が検出を回避するための新しい手段を常に探していることをさらに証明しています。これは、潜在的な攻撃ベクトルと将来性のあるソリューションに関する継続的な調査の重要性を強調しています。このブログ投稿で紹介されている原則が、他の研究者が同様のソリューションを開発する際に使用できることを願っています。

フィリップ・ツケルマンアミール・カッチャートマー・キャブリー
Microsoft 365 Defender 研究チーム


1 https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf

2 https://jxy-s.github.io/herpaderping/

3 https://www.elastic.co/blog/process-ghosting-a-new-executable-image-tampering-attack

参照: https://www.microsoft.com/en-us/security/blog/2022/06/30/using-process-creation-properties-to-catch-evasion-techniques/

Comments

Copied title and URL