【テクニカル・上級編】 メモリ上のコマンド履歴(Console Host History)の復元 – インシデントレスポンス & フォレンジック(DFIR)防御ガイド

侵入者の足跡を物理メモリから暴く:conhost.exeとコマンド履歴のフォレンジック

インシデントレスポンスの現場において、「攻撃者がコマンドを打ったか、打っていないか」を議論するのは時間の無駄だ。彼らは痕跡を消すために Invoke-History -Clear を実行し、ログを削除し、さらにはイベントログのID 1102を狙い撃ちにして消し去る。だが、彼らがどれほど巧妙にシステムをクリーンアップしようとも、OSの構造そのものに刻まれてしまう「物理メモリ上の残留物」までは完全には制御できない。

今日は、攻撃者がシェル(cmd.exe や powershell.exe)を操作する際に生成される conhost.exe のメモリ領域から、コマンド履歴を強制的に復元する技術的深淵に潜る。

なぜ conhost.exe なのか?

Windowsのシェル操作において、conhost.exe はユーザー入力と画面出力をブリッジする役割を担っている。歴史的な背景により、コンソール入力のバッファ管理は conhost.exe のプロセス内で行われる。

攻撃者がどれほど巧妙な難読化やメモリ上でのコード実行(Fileless Malware)を行っても、最終的にキーボードから入力されたコマンド、あるいはスクリプトが生成した標準入力は、conhost.exe のヒープ領域にある構造体として保持される。ここを叩けば、攻撃者が何をダウンロードし、どの認証情報を盗み、どのセグメントへラテラルムーブメントを試みたか、その「生」の履歴が手に入る。

メモリ解析の急所:Console History の構造

メモリ解析ツール(Volatilityなど)を使い、単に文字列を抽出するだけではノイズに埋もれる。我々が狙うべきは、conhost.exe が保持する HISTORY_BUFFER 構造体だ。

この構造体には、実行されたコマンドが循環バッファとして格納されている。特定のメモリ領域(_CONSOLE_INFORMATION 構造体配下の HistoryBuffer)を特定できれば、そこには攻撃者が打ち込んだコマンドが、あたかもタイムラインのように整列している。

実践:Volatility 3 を用いた履歴抽出のロジック

Volatility 3 を使用し、対象のメモリダンプからコマンド履歴を特定する際のワークフローを以下に示す。

# Volatility 3における conhost プロセスの特定とメモリダンプの基礎
# 攻撃者のセッションに関連する conhost.exe を特定する
vol -f memory.dmp windows.pslist --pid <conhost_pid>

# 特定したプロセスに対して、ヒープ領域を抽出する
# 実際の調査では、このダンプに対してカスタムのスクリプトを走らせる
vol -f memory.dmp windows.memmap --pid <conhost_pid> --dump

メモリダンプ取得後、以下のバイナリ解析ロジックで履歴を抽出する(概念的コード)。

import re

# conhost.exe のヒープからコマンド履歴のパターンを抽出する簡易ロジック
def extract_cmd_history(dump_file):
    # 典型的なコマンドの正規表現(攻撃者が好むツール群)
    pattern = rb'(powershell|cmd|certutil|bitsadmin|vssadmin|whoami|net user)'
    
    with open(dump_file, 'rb') as f:
        data = f.read()
        # 構造体の境界を考慮しつつ、文字列を検索
        matches = re.finditer(pattern, data)
        for match in matches:
            # 抽出したバイト列をデコードし、周囲のコンテキストを確認
            start = max(0, match.start() - 100)
            end = min(len(data), match.end() + 100)
            print(f"Detected potential command: {data[start:end].decode('utf-16', errors='ignore')}")

# このコードは解析の取っ掛かりに過ぎない。
# 実際には構造体オフセットを動的に解決する必要がある。

防御側のアーキテクトが考慮すべき「ガードレイル」

この解析手法が有効であるということは、逆に言えば攻撃者からすれば「メモリフォレンジックで自らの足跡が残る」ことを意味する。しかし、現代の高度な攻撃者は「メモリの断片化」や「セッションの早期終了」による揮発を利用し、痕跡の抹消を試みる。

我々防御側が実装すべきは、単なるログ取得ではない。以下のような「メモリ・インテグリティ」の観点が必要だ。

1. EDRの盲点を突くメモリ・インスペクション:
多くのEDRはAPIフックによる監視に依存している。しかし、conhost.exe へのダイレクトなメモリ書き込みや、パッチ適用によるフック回避は容易だ。メモリダンプの自動取得と自動解析をパイプライン化し、異常なコンソール操作をリアルタイムでスコアリングするアーキテクチャが必須である。
2. プロンプトインジェクションと実行権限:
生成AIを用いた攻撃において、プロンプトインジェクション経由でシェルが起動されるケースが増えている。この際、conhost.exe のメモリには、AIが生成した不正なコマンドがそのまま残る。サンドボックス内での実行だけでなく、実行プロセスの「メモリ状態」を監査対象に加えることで、AIモデルの誤用を検知する層を設けるべきだ。
3. 耐量子暗号とメモリ上のデータ:
将来的に耐量子暗号への移行が進むが、メモリ上の平文データ(コマンド履歴含む)は暗号化の対象外となることが多い。暗号化技術を「通信」だけでなく「プロセス間メモリ」にも適用する、セキュアなコンテナ・ランタイムの設計こそが、次世代の防衛技術の核となる。

最後に:フォレンジックは「執念」である

メモリ解析に魔法はない。あるのは、メモリダンプという巨大なゴミの山から、攻撃者が残したわずか数バイトの「意思」を見つけ出す執念だけだ。

攻撃者が conhost.exe を使ってコマンドを叩くとき、そこには必ず彼らの目的(ゴール)がある。その目的を、彼らが消去したはずの痕跡から復元する。それこそが、インシデントレスポンスにおける真の「証拠能力」であり、我々が対峙すべき戦場のリアリティである。

次回の調査では、strings コマンドで満足せず、必ず conhost.exe の構造体レイアウトを意識してほしい。そこには、攻撃者の最も生々しい思考が刻まれているはずだ。

コメント

タイトルとURLをコピーしました