RegPhantom バックドア:脅威分析と検出の洞察
Detection stack
- AIDR
- Alert
- ETL
- Query
概要
RegPhantomは、ステルスに特化したWindowsカーネルルートキットで、低特権のユーザーモードプロセスがカーネル空間で任意のコードを実行できるようにする隠されたレジストリベースのコマンドチャネルを提供します。ドライバーは有効な証明書で署名され、リフレクティブPEローディングに依存し、タスクが完了すると実行アーティファクトを削除します。そのアーキテクチャは、ドライバー署名の強制制御を回避するように設計されており、持続型ファイルやレジストリエントリを回避します。そのため、効果的な検出にはドライバーバイナリそのものとそれに含まれる特徴的なコードパターンを特定することが必要です。
調査
研究では、署名付きおよび署名なしの .sys のサンプルを2025年6月から8月の間に収集し、CFG難読化された共有コードベースと、 CmRegisterCallbackに基づくレジストリインターセプトメカニズムを露出しました。ドライバーは56バイトのXOR保護されたペイロードを復号し、それをカーネルメモリにリフレクティブにマッピングし、実行し、証拠を拭き取ります。サンプルの年代順や証明書の使用状況から、中国系の脅威アクターに関連した継続的な開発活動が示されています。
緩和策
セキュリティチームは、不信のあるカーネルドライバーを遮断し、 CmRegisterCallback and PsSetCreateThreadNotifyRoutineの疑わしい使用を監視し、ドライバーファイルの起動時整合性検証を実施すべきです。YARAルールを展開してドライバーの独特なバイトシーケンスに合わせるとともに、厳しいコード署名の強制を続けるべきです。特にアクセス拒否イベントを繰り返す異常なレジストリ書き込みの失敗を監視することも、隠された通信チャネルを暴露するかもしれません。
対応
RegPhantomが発見された場合、被害を受けたエンドポイントを隔離し、悪意あるドライバーを削除し、より深い法医学的レビューのためにカーネルメモリダンプを完全にキャプチャします。悪用された署名証明書を取り消し、必要に応じて信頼された証明書ストアを更新します。その後、脅威ハンティングは環境全体でドライバーのレジストリインターセプションの動作に焦点を当てるべきであり、露出の可能性があるすべてのWindowsシステムの修正が続くべきです。
"graph TB %% Class Definitions Section classDef technique fill:#ffcc99 classDef action fill:#99ccff classDef operator fill:#ff9900 classDef builtin fill:#cccccc %% Node definitions step_persistence["<b>Step</b> – 有効なコード署名証明書を使用して起動時に読み込まれる署名付き悪意あるドライバーによる持続."] class step_persistence action tech_boot_autostart["<b>Technique</b> – <b>T1547.009 カーネルドライバーとモジュール</b><br/>持続を得るためにシステム起動時に悪意あるドライバーをロードし、カーネルモードの特権を得る。"] class tech_boot_autostart technique tech_code_signing["<b>Technique</b> – <b>T1553.002 信頼制御の転覆:コード署名</b><br/>ドライバー署名の強制を回避するために、正当なコード署名証明書を利用する。"] class tech_code_signing technique tech_priv_esc["<b>Technique</b> – <b>T1068 特権昇格のための悪用</b><br/>カーネルドライバーが攻撃者コードにシステムレベルの特権を与える。""" class tech_priv_esc technique step_hook_registration["<b>Step</b> – ドライバーがシステムコールバックを登録し、その存在を隠して操作をインターセプトする。"] class step_hook_registration action tech_rootkit["<b>Technique</b> – <b>T1014 ルートキット</b><br/>カーネルモードのルートキットコンポーネントをインストールし、悪意ある活動を隠すためにコールバックをフックする。"] class tech_rootkit technique step_registry_channel["<b>Step</b> – ドライバーによってインターセプトされ、復号されるレジストリ書き込みを使用した隠されたコマンドチャネル。"] class step_registry_channel action tech_query_registry["<b>Technique</b> – <b>T1012 レジストリのクエリ</b><br/>コマンドまたは設定データを受け取るためにレジストリ値を読み取る。""" class tech_query_registry technique tech_deobfuscate["<b>Technique</b> – <b>T1140 ファイルや情報の難読化解除/復号</b><br/>レジストリから取得されたXOR暗号化されたペイロードを復号する。""" class tech_deobfuscate technique step_reflective_load["<b>Step</b> – カスタムローダーを使用してカーネルメモリにリフレクティブPEペイロードをロードする。"] class step_reflective_load action tech_reflective_loading["<b>Technique</b> – <b>T1620 リフレクティブコードローディング</b><br/>ディスクに触れることなく、メモリから直接コードをロードして実行する。""" class tech_reflective_loading technique step_memory_wipe["<b>Step</b> – 実行後に割り当てられたメモリを消去し、一時的なアーティファクトを削除する。"] class step_memory_wipe action tech_clear_persistence["<b>Technique</b> – <b>T1070.009 持続の消去</b><br/>ロードされたモジュールの痕跡と関連する持続アーティファクトを削除する。""" class tech_clear_persistence technique step_hook_hijack["<b>Step</b> – ペイロードがドライバーフックポインターを奪取し、持続を維持し活動をさらに隠す。"] class step_hook_hijack action %% Connections showing flow step_persistence –>|uses| tech_boot_autostart step_persistence –>|subverts| tech_code_signing step_persistence –>|enables| tech_priv_esc step_persistence –>|leads_to| step_hook_registration step_hook_registration –>|implements| tech_rootkit step_hook_registration –>|leads_to| step_registry_channel step_registry_channel –>|accesses| tech_query_registry step_registry_channel –>|performs| tech_deobfuscate step_registry_channel –>|leads_to| step_reflective_load step_reflective_load –>|executes| tech_reflective_loading step_reflective_load –>|leads_to| step_memory_wipe step_memory_wipe –>|clears| tech_clear_persistence step_memory_wipe –>|leads_to| step_hook_hijack step_hook_hijack –>|maintains| tech_rootkit "
攻撃フロー
シミュレーション実行
前提条件: テレメトリーとベースラインのプリフライトチェックが合格したこと。
根拠: このセクションは、検出ルールをトリガーするように設計された敵対的技術戦術(TTP)の正確な実行を詳述します。コマンドと物語は識別されたTTPを直接反映し、検出ロジックによって期待される正確なテレメトリーを生成することを目指しています。
-
攻撃シナリオとコマンド
- 目的: RegPhantomが資格情報関連のレジストリ操作をインターセプトするカーネルモードのレジストリコールバックを登録しようとする模倣をします。
- 方法: カスタムローダーでリフレクティブPEペイロードをロードします
CmRegisterCallback偽のドライバーをロードし、以下を呼び出しますRegNtPreSetValueKey。ドライバーは意図的に不正な登録構造を渡し、それがSTATUS_ACCESS_DENIED. - という結果を意図的に招きます。 SysmonはEventID 13をログし、
ターゲットオブジェクトにて双方を報告 bothCmRegisterCallbackandRegNtPreSetValueKey,詳細ちょうど56バイト(0x38)のデータサイズ、そして状態が設定されます回帰テストスクリプトSTATUS_ACCESS_DENIED.
-
(PowerShell + 埋め込みCドライバーソース – ターゲットホストでコンパイル) # ————————————————————– # Step 1: マイ標準ドライバーソースをディスクに書き込み # ————————————————————– $driverSource = @” #include <ntddk.h> // ダミーコールバック – 呼び出されない NTSTATUS DummyCallback( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2 ) { UNREFERENCED_PARAMETER(CallbackContext); UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2); return STATUS_SUCCESS; } extern “C” NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath); // 意図的に誤ったサイズ(56バイト)を使用し、 // STATUS_ACCESS_DENIEDで拒否されるコールバック登録を要求する。 UNICODE_STRING altitude = RTL_CONSTANT_STRING(L”1234.5678.90ab”); LARGE_INTEGER cookie = {0}; //NULLコールバックポインターを渡して意図的に失敗させる(誤った要求をシミュレート) NTSTATUS status = CmRegisterCallback(DummyCallback, NULL, &cookie); //状態を上書きしてRegPhantomが見る正確な条件を再現 status = STATUS_ACCESS_DENIED; // 0xC0000022 //イベントをSysmonでキャプチャするためにドライバーを短期間ロード LARGE_INTEGER interval; interval.QuadPart = -10 * 1000000; // 1秒 KeDelayExecutionThread(KernelMode, FALSE, &interval); //アンロード前に登録解除 CmUnregisterCallback(cookie); return STATUS_SUCCESS; } “@ $srcPath = “$env:TEMPRegPhantomStub.c” $srcPath | Set-Content -Value $driverSource -Encoding ASCII # ————————————————————– # Step 2: ドライバーをコンパイル (Visual Studio Build Toolsが必要) # ————————————————————– Write-Host “ドライバーをコンパイル中 – Windows Driver Kit (WDK) とVS Build Toolsが必要。” $compileCmd = “cl /nologo /W3 /WX- /O2 /DUNICODE /D_UNICODE /Zi /MD /LD $srcPath /link /OUT:`”$env:TEMPRegPhantomStub.sys`”” & cmd /c $compileCmd # ————————————————————– # Step 3: ドライバーをロード(管理者として実行する必要がある) # ————————————————————– Write-Host “登録試行をトリガーするためにドライバーをロード中…” $driverPath = “$env:TEMPRegPhantomStub.sys” sc create RegPhantomStub binPath= $driverPath type= kernel start= demand sc start RegPhantomStub # ————————————————————– # Step 4: Sysmonがイベントを取り込む時間を与える # ————————————————————– Start-Sleep -Seconds 5 # ————————————————————– # Step 5: ドライバーをアンロードして削除 # ————————————————————– sc stop RegPhantomStub sc delete RegPhantomStub Remove-Item -Path $driverPath -Force Remove-Item -Path $srcPath -Force Write-Host “シミュレーション完了。SIEMで検出を確認してください。”
# -------------------------------------------------------------- # Step 1: Write the minimal driver source to disk # -------------------------------------------------------------- $driverSource = @" #include <ntddk.h> // Dummy callback – never called NTSTATUS DummyCallback( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2 ) { UNREFERENCED_PARAMETER(CallbackContext); UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2); return STATUS_SUCCESS; } extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath); // Intentionally use a wrong size (56 bytes) and request a callback registration // that will be rejected with STATUS_ACCESS_DENIED. UNICODE_STRING altitude = RTL_CONSTANT_STRING(L"1234.5678.90ab"); LARGE_INTEGER cookie = {0}; // Force a failure by passing a null callback pointer (simulates a malformed request) NTSTATUS status = CmRegisterCallback(DummyCallback, NULL, &cookie); // Overwrite status to mimic the exact condition RegPhantom sees status = STATUS_ACCESS_DENIED; // 0xC0000022 // Keep the driver loaded for a short period to allow Sysmon to capture the event LARGE_INTEGER interval; interval.QuadPart = -10 * 1000000; // 1 second KeDelayExecutionThread(KernelMode, FALSE, &interval); // Unregister before unload CmUnregisterCallback(cookie); return STATUS_SUCCESS; } "@ $srcPath = "$env:TEMPRegPhantomStub.c" $srcPath | Set-Content -Value $driverSource -Encoding ASCII # -------------------------------------------------------------- # Step 2: Compile the driver (requires Visual Studio Build Tools) # -------------------------------------------------------------- Write-Host "Compiling driver – requires Windows Driver Kit (WDK) and VS Build Tools." $compileCmd = "cl /nologo /W3 /WX- /O2 /DUNICODE /D_UNICODE /Zi /MD /LD $srcPath /link /OUT:`"$env:TEMPRegPhantomStub.sys`"" & cmd /c $compileCmd # -------------------------------------------------------------- # Step 3: Load the driver (must run as Administrator) # -------------------------------------------------------------- Write-Host "Loading driver to trigger the registration attempt..." $driverPath = "$env:TEMPRegPhantomStub.sys" sc create RegPhantomStub binPath= $driverPath type= kernel start= demand sc start RegPhantomStub # -------------------------------------------------------------- # Step 4: Give Sysmon time to ingest the event # -------------------------------------------------------------- Start-Sleep -Seconds 5 # -------------------------------------------------------------- # Step 5: Unload and delete the driver # -------------------------------------------------------------- sc stop RegPhantomStub sc delete RegPhantomStub Remove-Item -Path $driverPath -Force Remove-Item -Path $srcPath -Force Write-Host "Simulation complete. Verify detection in your SIEM." -
クリーンアップコマンド (ドライバーをコンパイルまたはロードできなかった場合)
# 部分的に作成されたドライバーサービスが削除されていることを確認 if (Get-Service -Name RegPhantomStub -ErrorAction SilentlyContinue) { sc stop RegPhantomStub sc delete RegPhantomStub } # 残留ファイルを削除 Remove-Item -Path "$env:TEMPRegPhantomStub.*" -Force -ErrorAction SilentlyContinue