Cyril François

ABYSSWORKER ドライバーに光を当てる

Elastic Security Labsは、マルウェア対策ツールを無効にするためにMEDUSAランサムウェア攻撃チェーンで使用される悪意のあるドライバーであるABYSSWORKERについて説明します。

16分で読めますマルウェア分析
ABYSSWORKER ドライバーに光を当てる

まとめ

サイバー犯罪者は、脆弱な正規のドライバーを悪用したり、カスタムビルドのドライバーを使用してEDR(Endpoint Detection and Response)システムを無効にしたり、検出や防止機能を回避したりして、独自のドライバーを持ち込むことが増えています。

Elastic Security Labsは、 HEARTCRYPTを詰め込んだローダーを使用してMEDUSAランサムウェアを展開する金銭的な動機を持つキャンペーンを監視しています。このローダーは、ABYSSWORKERと呼ばれる中国のベンダーから失効した証明書署名付きドライバーと一緒にデプロイされ、被害者のマシンにインストールし、さまざまなEDRベンダーをターゲットにして沈黙させるために使用します。このEDRキラードライバーは 、最近 ConnectWiseによって別のキャンペーンで報告され、異なる証明書とIO制御コードを使用しており、その時点でその機能の一部が議論されました。2022年、Google Cloud Mandiantは、このドライバについて最も早く言及されたと思われる POORTRY という悪意のあるドライバを公開しました。

この記事では、このドライバーを詳しく見ながら、そのさまざまな機能と手法を調べます。また、逆転した各コードスクリーンショットの下に相対仮想アドレス(RVA)を提供して、研究を参照サンプルにリンクし、このマルウェアをさらに実験するために使用できる小さなクライアントの例を提供します。

テクニカル分析

PEヘッダー

バイナリは smuol.sysという名前の 64 ビット Windows PE ドライバーであり、正規の CrowdStrike Falcon ドライバーを模倣しています。

分析時点で、VirusTotalには2024年8月8日から2025年2月24日までの12個のサンプルが見つかりました。ほとんどはVMProtectでいっぱいでしたが、2つ(以下の観測可能な表で参照)は保護されていませんでした。

すべてのサンプルは、中国企業から盗まれ、失効した可能性のある証明書を使用して署名されています。これらの証明書は広く知られており、さまざまなマルウェアサンプルやキャンペーンで共有されていますが、このドライバーに固有のものではありません。証明書のフィンガープリントを以下に示します。

fingerprint名前
51 68 1b 3c 9e 66 5d d0 b2 9e 25 71 46 d5 39 dc佛山GaomingKedeyu断熱材有限公司
7f 67 15 0f bb 0d 25 4e 47 42 84 c7 f7 81 9c 4fフェイ・シャオ
72 88 1f 10 cd 24 8a 33 e6 12 43 a9 e1 50 ec 1d福州Dingxin貿易有限公司
75 e8 e7 b9 04 3b 13 df 60 e7 64 99 66 30 21 c1長沙恒翔情報技術有限公司
03 93 47 e6 1d ec 6f 63 98 d4 d4 6b f7 32 65 6c新疆Yishilian Network Technology Co., Ltd
4e fa 7e 7b ba 65 ec 1a b7 74 f2 b3 13 57 d5 99深センYundian技術有限公司

難読 化

ABYSSWORKER は、不透明な述語と他の派生関数の組み合わせに依存して、常に同じ値を返す関数を使用します。たとえば、次のゼロを返す関数は、常にハードコーディングされた派生値に基づいて 0 を返します。

以下は、導出関数の 1 つです。

これらの定数を返す関数は、静的解析を妨げるためにバイナリ全体で繰り返し呼び出されます。ただし、このような関数は 3 つしかなく、述語では使用されず、単に呼び出されます。それらを簡単に特定できるため、これは非効率的な難読化スキームになります。

初期化

初期化時に、ドライバーはまず、いくつかのカーネル モジュールとそのクライアント保護機能 (次のセクションで説明します) へのポインターを取得します。

次に、パス が \\device\\czx9umpTReqbOOKF のデバイスと、パスが \\??\\fqg0Et4KlNt4s1JTのシンボリック リンクを作成します。

主要な関数のコールバックを登録することで初期化を完了します。

デバイスを開く際のクライアント保護

ドライバー デバイスが開かれると、 IRP_MJ_CREATE メジャー コールバックが呼び出されます。この関数は、保護するプロセスのリストにプロセス ID を追加し、実行中のプロセスのリストからターゲット プロセスへの既存のハンドルを削除する役割を担います。

この関数は、デバイスが開かれたときにクライアント プロセスのコンテキストでカーネル コールバックが実行されるため、現在のカーネル スレッドからプロセス ID を取得します。

プロセス ID を保護リストに追加する前に、ABYSSWORKER は、実行中の他のプロセスでクライアント プロセスへの既存のハンドルを検索して削除します。

これを実現するために、マルウェアは既存のプロセスを反復処理し、プロセスID(PID)をブルートフォースしてAPIに依存しないようにします。プロセスごとに、ブルートフォースを使用してハンドルを反復処理し、基になるオブジェクトがクライアントプロセスに対応しているかどうかを確認します。一致が見つかった場合は、パラメータとして渡された値 (0x8bb) を使用してアクセス権が削除されます。

最後に、PID を保護されたプロセスのグローバルリストに追加します。

前述のように、ドライバーは初期化フェーズ中に保護機能を設定します。この保護は、ObRegisterCallback API を使用して 2 つのpre-operationコールバックを登録することに依存しています。1 つは保護されたプロセスへのハンドルのオープンを検出し、もう 1 つは保護されたプロセスのスレッドへのハンドルのオープンを検出するためのコールバックです。

2 つのコールバックは同じように動作し、ハンドルに対する必要なアクセスを 0 に設定し、ハンドルの作成を事実上拒否します。

DeviceIoControl ハンドラー

デバイスの I/O 制御要求を受信すると、ABYSSWORKER は I/O 制御コードに基づいて要求をハンドラにディスパッチします。これらのハンドラは、ファイルの操作からプロセスやドライバーの終了まで、幅広い操作をカバーし、EDRシステムの終了または永久的な無効化に使用できる包括的なツールセットを提供します。

次の表で、さまざまな IO コントロールについて詳しく説明します。

名前コード
マルウェアを有効にする0x222080
ファイルをコピー0x222184
モジュール名によるコールバックとデバイスの削除0x222400
ドライバーの主要機能をモジュール名で置き換える0x222404
モジュール名でシステムスレッドを強制終了する0x222408
ミニフィルターデバイスの取り外し0x222440
ファイルの削除0x222180
マルウェアを無効にする0x222084
APIをロードする0x2220c0
すべてのドライバー参照カウンターを減らします0x222100
すべてのデバイス参照カウンターを減らす0x222104
プロセスの終了0x222144
スレッドの終了0x222140
Ntfs および Pnp ドライバーの主要機能からのフックの削除0x222444
リブート0x222664

マルウェアの有効化 (0x222080)

この ブログ記事で説明したように、クライアントは、パスワード (7N6bCAoECbItsUR5-h4Rp2nkQxybfKb0F-wgbJGHGh20pWUuN1-ZxfXdiOYps6HTp0X) をドライバーに送信してドライバーを有効にする必要があります (この場合は、 0x222080 IO コントロールを介して行われます)。

ハンドラは、ユーザー入力とハードコードされたパスワードを比較するだけです。正しければ、グローバル フラグを true (1) に設定します。このフラグは、他のすべてのハンドラーでチェックされ、実行を許可または拒否します。

API の読み込み (0x2220c0)

マルウェアのほとんどのハンドラは、このハンドラを使用してロードする必要があるカーネルAPIに依存しています。このハンドラーは、初期化中に以前に読み込まれたカーネル モジュール ポインターを使用して、これらのグローバルをいくつかの構造体と共に読み込みます。読み込みが完了すると、これらの API の可用性を示すグローバル フラグが設定されます。

このハンドラーには、フル モードとパーシャル モードの 2 つの操作モードがあります。フル モードでは、IO コントロールへの入力としてユーザーから提供された関数名と RVA のマッピング構造を使用して API を読み込みます。パーシャル モードでは、一部の API を単独で検索しますが、フル モードでロードされたすべての API をロードするわけではないため、パーシャル モードという用語が使用されています。このマッピング構造を提供できないためにユーザーがパーシャルモードを選択した場合、一部のハンドラは実行されません。この章では、操作の完全なモードのみについて説明します。

次に、使用される構造について詳しく説明します。

#define AM_NAME_LENGTH 256
typedef struct _struct_435
{
   uint64_t rva;
   char name[AM_NAME_LENGTH];
} struct_435_t;

#define AM_ARRAY_LENGTH 1024
typedef struct _struct_433
{
   struct_435_t array[AM_ARRAY_LENGTH];
   uint32_t length;
} struct_433_t;

以下に簡単な使用例を示します。

struct_433_t api_mapping = {
    .length = 25,
    .array = {
        [0] = {.rva = 0xcec620, .name = "PspLoadImageNotifyRoutine"},
        [1] = {.rva = 0xcec220, .name = "PspCreateThreadNotifyRoutine"},
        [2] = {.rva = 0xcec420, .name = "PspCreateProcessNotifyRoutine"},
        // (...)
        [24] = {.rva = 0x250060, .name = "NtfsFsdShutdown"},
}};

uint32_t malware_load_api(HANDLE device)
{
    return send_ioctrl(device, IOCTRL_LOAD_API, &api_mapping, sizeof(struct_433_t), NULL, 0);
}

そのAPIをロードするために、関数は異なるカーネルオブジェクトタイプから3つの「コールバックリスト」をロードすることから始まります。これらは、特定のモジュールに属する登録済みの通知コールバックを削除するハンドラーによって使用されます。

次に、指定された構造体を使用して、関数名を検索し、関連付けられている RVA をモジュールのベース アドレスに追加するだけで、関数へのポインターを読み込みます。

これは、次の 25 関数に対して行われます。

  • PspLoadImageNotifyRoutine
  • PspCreateThreadNotifyRoutine
  • PspCreateProcessNotifyRoutine
  • CallbackListHead
  • PspSetCreateProcessNotifyRoutine
  • PspTerminateThreadByPointer
  • PsTerminateProcess
  • IopInvalidDeviceRequest
  • ClassGlobalDispatch
  • NtfsFsdRead
  • NtfsFsdWrite
  • NtfsFsdLockControl
  • NtfsFsdDirectoryControl
  • NtfsFsdClose
  • NtfsFsdCleanup
  • NtfsFsdCreate
  • NtfsFsdDispatchWait
  • NtfsFsdDispatchSwitch
  • NtfsFsdDispatch
  • NtfsFsdFlushBuffers
  • NtfsFsdDeviceControl
  • NtfsFsdFileSystemControl
  • NtfsFsdSetInformation
  • NtfsFsdPnp
  • NtfsFsdShutdown

ファイルのコピーと削除 (0x222184, 0x222180)

ファイルをコピーまたは削除するために、ABYSSWORKERは新しいものではありませんが、興味深い戦略に依存しています。NtCreateFileのような一般的な API を使用する代わりに、I/O 要求パケット (IRP) が最初から作成され、ターゲット ファイルを含む対応するドライブ デバイスに直接送信されます。

ファイルの作成

ファイル作成機能は、このメカニズムがどのように機能するかを示すために使用されます。この機能は、ファイルパスからドライブデバイスを取得することから始まります。次に、新しいファイルオブジェクトが作成され、ターゲットドライブデバイスにリンクされ、新しいオブジェクトがドライブに適切にリンクされていることが確認されます。

次に、新しい IRP オブジェクトを作成し、ファイル作成操作を実行するために必要なすべてのデータを設定します。この IRP の対象となる主要な関数は、 MajorFunction プロパティで指定され、この場合は、ファイル作成の想定どおり IRP_MJ_CREATEに設定されます。

次に、マルウェアは IRP をターゲット ドライブ デバイスに送信します。IoCallDriver API を使用してこれを行うこともできますが、代わりに、対応するデバイスの主要な関数を呼び出して IRP を手動で送信します。

この時点で、ファイル・オブジェクトはその後の使用に有効です。ハンドラーは、ファイル オブジェクトの参照カウンターをインクリメントし、後で使用するために出力パラメーターに割り当てることで作業を終了します。

ファイルのコピー

ファイルをコピーするために、ABYSSWORKER はソースファイルとコピー先の両方のファイルを開き、ソースから (IRP_MJ_READ) を読み取り、コピー先に (IRP_MJ_WRITE) を書き込みます。

ファイルの削除

削除ハンドラーは、読み取り専用ファイルの保護を解除するために file 属性を ATTRIBUTE_NORMAL に設定し、IRP_MJ_SET_INFORMATION IRP を使用してファイルを削除するためにファイルの性質を delete (disposition_info.DeleteFile = 1) に設定します。

モジュール名による通知コールバックの削除 (0x222400)

マルウェアクライアントは、このハンドラを使用して、EDR製品とその可視性を盲目にすることができます。登録されているすべての通知コールバックを検索して削除します。対象となるコールバックは、次の API に登録されているコールバックです。

  • PsSetCreateProcessNotifyRoutine
  • PsSetLoadImageNotifyRoutine
  • PsSetCreateThreadNotifyRoutine
  • ObRegisterCallbacks
  • CmRegisterCallback

さらに、MiniFilter ドライバーを介して登録されたコールバックを削除し、必要に応じて、特定のモジュールに属するデバイスを削除します。

これらの通知コールバックを削除するために、ハンドラーは、 ObRegisterCallbacksCmRegisterCallbackに登録されたコールバックを含む、読み込み API ハンドラーに以前に読み込まれた 3 つのグローバル コールバック リストなど、さまざまな方法を使用して通知コールバックを見つけます。その後、対応する API ( ObUnRegisterCallbacksCmUnRegisterCallbacksなど) を使用してそれらを削除します。

これらの方法を使用してEDRを盲検化することは、それ自体がブログ記事に値します。この投稿を簡潔にするために、ここでは詳細を提供しませんが、これらの手法を実装する 2 つの十分に文書化されたプロジェクトでこれらの方法を探求することをお勧めします。

ドライバーの主要機能をモジュール名で置き換える 0x222404

ドライバーに干渉する別の方法は、このハンドラーを使用して、そのすべての主要な関数をダミー関数に置き換え、ターゲット モジュール名を指定してドライバーとの対話を無効にすることです。

これを実現するために、ABYSSWORKER は Driver object ディレクトリと Filesystem オブジェクト ディレクトリの driver オブジェクトを反復処理します。ドライバー オブジェクトごとに、基になるモジュール名とターゲット モジュールを比較し、一致する場合は、その主要な関数をすべて IopInvalidDeviceRequestに置き換えます。

ミニフィルターデバイスの取り外し(0x222440)

このハンドラーは、 Driver オブジェクト ディレクトリと FileSystem オブジェクト ディレクトリで見つかったすべてのドライバー オブジェクトを反復処理します。ドライバーごとに、そのデバイス ツリーを探索し、ミニ フィルター ドライバーに関連付けられているすべてのデバイスをデタッチします FltMgr.sys

この関数は、 AttachedDevice ポインターと NextDevice ポインターを使用してドライバーのデバイスを反復処理し、各デバイスに関連付けられているドライバーのモジュール名を取得し、パラメーター (”FltMgr.sys”) として渡されたターゲット モジュール名と比較することで機能します。名前が一致する場合は、 IoDetachDevice 機能を使用してデバイスのリンクを解除します。

モジュール名によるシステムスレッドの強制終了 (0x222408)

このハンドラーは、スレッド ID をブルートフォースすることでスレッドを反復処理し、スレッドがシステム スレッドであり、その開始アドレスがターゲット モジュールに属している場合は、スレッドを強制終了します。

スレッドを終了するために、マルウェアはAPC(非同期プロシージャコール)をキューに入れて、標的のスレッドのコンテキストでコードを実行します。実行されると、このコードは PsTerminateSystemThreadを呼び出します。

プロセスの終了とスレッドの終了 (0x222144、0x222140)

これら 2 つのハンドラーを使用すると、 PsTerminateProcessPsTerminateThreadを使用して、PID またはスレッド ID (TID) によって任意のプロセスまたはスレッドを終了できます。

Ntfs および Pnp ドライバーの主要機能からフックを削除する (0x222444)

一部の EDR は、通知コールバックの登録に加えて、 NTFS ドライバーと PNP ドライバーの主要な機能をフックすることを好みます。これらのフックを削除するために、マルウェアはこのドライバーを呼び出して、それらのドライバーの元の主要な機能を復元できます。

ABYSSWORKER は、登録された各メジャー関数を単純に反復処理し、その関数がドライバーモジュールに属しているかどうかを確認し、そうでない場合は、関数がフックされたことを意味するため、元の関数に置き換えます。

リブート 0x222664

マシンを再起動するために、このハンドラは文書化されていない関数 HalReturnToFirmwareを使用します。

クライアントの実装例

このブログ記事では、小規模なクライアント実装例をご紹介します。この例は参照サンプルと連動し、デバッグに使用されましたが、ドライバーのすべての IOCTRL が実装されているわけではなく、将来更新される可能性は低いです。

ただし、それを有効にしてAPIをロードするためのすべての機能が含まれているため、この記事の情報の助けを借りて、やる気のある読者がそれを拡張し、このマルウェアをさらに実験できることを願っています。

プロジェクトのリポジトリは こちらから入手できます。

マルウェアと MITRE ATT&CK

Elasticは、 MITRE ATT&CK フレームワークを使用して、脅威がエンタープライズネットワークに対して使用する一般的な戦術、手法、手順を文書化します。

戦術(Tactics)

手法

手法は、敵対者がアクションを実行することによって戦術的な目標を達成する方法を表します。

対策

ヤラ

Elasticセキュリティは、この記事に関連する以下のYARAルールを作成しました。

観測

この研究では、次の観測量が議論されました。

すぐれた監視性タイプ参考日時
6a2a0f9c56ee9bf7b62e1d4e1929d13046cd78a93d8c607fe4728cc5b1e8d050SHA256ABYSSWORKER リファレンスサンプルVT初公開日: 2025-01-22
b7703a59c39a0d2f7ef6422945aaeaaf061431af0533557246397551b8eed505SHA256ABYSSWORKER のサンプルVT初公開: 2025-01-27

参照資料

この記事を共有する