カーネルの深淵を覗く:メモリフォレンジックで暴く「不可視の侵入者」
最近のEDRは優秀だ。ユーザーモードの不審な挙動や、シグネチャベースのマルウェアは、もはやSOCのダッシュボードに自動で弾き出される。しかし、我々DFIRの現場で「最後に行き着く場所」は、常にカーネルメモリの荒野だ。
攻撃者がリング0(カーネルモード)に到達した瞬間、OSの提供するAPIはもはや信用できない。彼らはSSDT(System Service Descriptor Table)やIDT(Interrupt Descriptor Table)を書き換え、OSの目を盗んで自身の存在を隠蔽する。今日は、そんな「システムに寄生した亡霊」を、メモリダンプからどう炙り出すか、その泥臭い実戦論を語ろう。
—
1. なぜ「静的解析」だけでは不十分なのか
攻撃者がカーネルレベルのルートキットをインストールすると、EnumProcessesのような標準的なAPIは、彼らが意図的にフィルタリングした結果しか返さなくなる。これが「隠蔽」の正体だ。
彼らは、カーネル関数が呼び出される際の「ジャンプ先」を自前の悪意あるコードへすり替える。これを特定するためには、OSのAPIを介さず、メモリダンプから直接データ構造の整合性を検証するしかない。我々は、OSが「信じているもの」と「実際にメモリ上に存在するバイナリ」の差異を追う必要がある。
2. フックポイントの特定:SSDT改ざんの検知
SSDTは、ユーザーモードからのシステムコール(NtCreateFileなど)をカーネル内の関数へと転送するためのテーブルだ。ここが書き換えられると、OSは正規の関数ではなく、攻撃者が仕込んだルートキットの関数を実行してしまう。
Volatility 3を用いた調査では、まずwindows.ssdtプラグインを実行する。ここで注目すべきは、関数のポインタが「カーネルモジュール(ntoskrnl.exeなど)の範囲外」を指していないかという点だ。
# Volatility 3を用いたSSDTフックの検証コマンド
python3 vol.py -f memory.dmp windows.ssdt
もし、特定のポインタが未署名のドライバや、不審なメモリセクションを指していれば、それが「銃口」だ。
—
3. IDTフックとインラインフックへの対抗策
SSDTだけでなく、ハードウェア割り込みを制御するIDTや、関数先頭を無理やり書き換えるインラインフック(Inline Hooking)は、より巧妙だ。
特にインラインフックは、関数先頭の数バイトをjmp命令に書き換えるため、テーブル上は正常に見えることが多い。この場合、メモリダンプ内の関数エントリーポイントを直接アセンブラレベルで比較する。
実践的な解析手法:メモリ比較ロジック
以下は、カーネル関数の先頭バイトを抽出して、オリジナルのプロローグ(通常はmov edi, ediのような標準的な命令)と乖離がないかを確認するための疑似的なロジックだ。
# メモリダンプから特定のカーネル関数先頭を読み取り、フックを検知するロジックの概念
def check_inline_hook(process_memory, target_function_address):
# 関数の先頭5バイト(jmp命令のサイズ)を読み込む
prologue = process_memory.read(target_function_address, 5)
# 正規の関数の先頭命令(例: 0x8B 0xFF ...)と比較
# ここでは仮に正規のバイトコードを定義
expected_prologue = b'\x8B\xFF\x55\x8B\xEC'
if prologue != expected_prologue:
print(f"[!] 警告: アドレス {hex(target_function_address)} でインラインフックを検出!")
# 攻撃者のジャンプ先アドレスを特定するために逆アセンブルを試みる
# ここで capstone エンジン等を活用して jmp 先を解析する
—
4. 防衛アーキテクチャへの昇華:根本原因を断つ
ルートキットがなぜ許されるのか。それはOSが「一度ロードされたドライバの整合性を継続的に監視しない」からだ。
チーフホワイトハッカーとして推奨したい防衛策は、単なるEDRの導入ではない。
- HVCI(ハイパーバイザーで保護されたコード整合性)の強制: カーネルモードでのコード改ざんをハードウェアレベルで阻止する。これがあれば、SSDTやIDTの書き換えは仮想化のレイヤでブロックされる。
- 通信の完全性: ルートキットはしばしばC2サーバーとの通信を隠蔽するためにネットワークスタックをフックする。これに対し、OS外のネットワークスイッチやIDSで、不審なプロトコルのエントロピーを確認する(暗号化された怪しい通信のパターン認識)。
- ゼロトラスト・カーネル: 「カーネルは一度ロードされたら不変である」という前提をアーキテクチャに組み込む。具体的には、重要なシステム構造体へのアクセスを、ハイパーバイザーレベルの読み取り専用属性として設定することだ。
結びに代えて:泥臭い現場の教訓
私が数々の侵害調査で学んだのは、「ツールが答えを教えてくれることは稀だ」という事実だ。ツールはあくまで「異常の兆候」を提示するに過ぎない。
最後に頼りになるのは、あなたがどれだけ低レイヤのバイナリ構造を理解し、メモリ上のオフセットを脳内で視覚化できるかという「技術的な直感」だ。OSが隠そうとする闇を見抜くには、OSそのものを疑う姿勢を忘れないでほしい。
次回の調査では、PTE(ページテーブルエントリー)の権限属性を解析し、RWX(読み取り・書き込み・実行)属性が不当に付与された不審なメモリページを特定する技術について深掘りしよう。防御は、攻撃者の思考を逆なでることから始まる。
コメント