【テクニカル・上級編】 Windowsイベントログとメモリダンプの相関分析による攻撃者活動の時系列化 – インシデントレスポンス & フォレンジック(DFIR)防御ガイド

タイムラインの空白を撃て:メモリとイベントログの相関分析が暴く侵入者の正体

インシデントレスポンスの現場で最も恐ろしいのは、攻撃を受けた事実そのものではない。「いつから入り込まれ、どこまで踏み荒らされたのか」という、タイムラインの巨大な空白だ。

EDRのアラートだけを信じてはいけない。高度な脅威グループ(APT)やランサムウェアのオペレーターは、初期潜入に成功した瞬間、真っ先に監査ログの改ざん、イベントログのクリア、あるいはロギングプロセスのサスペンドを行う。Event ID 4688(プロセスの作成)や4624(ログオン)だけを頼りにインシデントの全貌を明らかにしようとするアプローチは、敵の土俵で踊らされているに等しい。ログが消されている、あるいはローテートされて消失しているとき、アナリストに残された最後の真実は「物理メモリ」の中にしかない。

今回は、Windowsイベントログの断片と、Volatility 3等を用いたメモリダンプから得られる揮発性アーティファクトを緻密に突き合わせ、攻撃者の滞留時間(Dwell Time)とラテラルムーブメントの全軌跡をミリ秒単位で再構築する統合分析手法について、実戦的なノウハウを交えて解説する。

—

1. なぜイベントログ単体では敗北するのか?

現代の侵入者たちは、Windowsのセキュリティアーキテクチャの仕様の隙間を熟知している。彼らはLiving off the Land(LotL)戦術を好み、cmd.exe、powershell.exe、wmic.exe、schtasks.exeといった正規のシステム管理ツールを武器にする。

ここで問題になるのが、ログの「生成タイミング」と「取得コスト」のギャップだ。

  • ログの遅延と欠落: 負荷の高い環境では、LSASSのダンプや不審なプロセス生成に関するイベントがログバッファに溢れ、古いものから上書きされる。
  • 意図的なログの隠蔽: wevtutil cl によるログ消去や、イベントログサービス(EventLog)自体のプロセス停止。
  • コマンドライン引数の制限: 標準設定のEvent ID 4688では、コマンドラインの監査(Process Command Line 監査)が有効化されていない場合、親プロセスしか記録されず、何を実行されたのかが闇の中へ消える。

これに対し、メモリ(RAM)は「嘘をつかない」。プロセスが終了していなかろうと、親プロセスID(PPID)がスプーフィングされていなかろうと、プロセスの生成時にカーネルが割り当てた _EPROCESS 構造体やVAD(Virtual Address Descriptor)ツリー、そしてプロセス環境ブロック(PEB)には、生々しい実行の痕跡が刻まれている。

—

2. メモリダンプとイベントログを同期させるコアロジック

相関分析の基本思想はシンプルだ。「メモリから抽出したプロセスの『カーネル上の作成時刻(CreateTime)』を起点とし、その前後に発生したイベントログを逆引きする」。

Windowsのカーネルメモリにおいて、すべてのプロセスは _EPROCESS という巨大な構造体として管理されている。この中には、プロセスが生成された正確なUTCタイムスタンプ(CreateTime)が含まれている。これはユーザーランドのAPIやレジストリ、イベントログとは独立してカーネルが維持しているため、改ざんが極めて困難である。

分析のステップ

1. メモリからのプロセスリストの全抽出: Volatility 3等のフレームワークを使い、隠しプロセス(DKOMによるアンリンク手法など)も含めてすべてのプロセスを列挙する。
2. タイムスタンプの正規化: 抽出したプロセスの CreateTime をUNIXエポックまたはISO 8601形式に変換する。
3. イベントログとのクロスリファレンス: 当該時刻の前後数秒間におけるEvent ID(4688, 4624, 7045など)を照合し、「ログが存在するか」「ログの内容とメモリ上の実態に矛盾がないか」を検証する。

—

3. 実践:Volatility 3とPythonによる相関分析スクリプト

机上の空論を避けるため、現場で即座に使える実践的なアプローチを示そう。以下のPythonスクリプトは、メモリフォレンジックの結果(JSON形式等で出力されたプロセス情報)と、エクスポートしたWindowsイベントログ(EVTX)を突き合わせ、タイムラインの不一致やログの欠損(=攻撃者による隠蔽工作の可能性)を検出するための概念実証(PoC)コードである。

import json
from datetime import datetime, timezone
import xml.etree.ElementTree as ET

def parse_volatility_processes(json_path):
    """
    Volatility 3の出力(JSON)からプロセス名、PID、PPID、CreateTimeを抽出する
    """
    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    processes = []
    # Volatilityの出力構造に応じたパース処理
    for row in data:
        # カーネル構造体から得られた正確な生成時刻
        create_time_str = row.get('CreateTime')
        if not create_time_str:
            continue
        
        try:
            # タイムスタンプのパース(環境に合わせて調整)
            create_time = datetime.fromisoformat(create_time_str.replace('Z', '+00:00'))
        except ValueError:
            continue

        processes.append({
            'pid': row.get('PID'),
            'ppid': row.get('PPID'),
            'image': row.get('ImageFileName'),
            'create_time': create_time
        })
    return processes

def correlate_with_evtx(processes, evtx_logs_path):
    """
    メモリ上のプロセス生成時刻とイベントログ(Event ID 4688等)を突き合わせる
    """
    # イベントログのパース処理(実務ではEvtxParserライブラリ等を使用)
    # ここでは概念を示すため、イベントのリストが存在すると仮定
    print("[*] メモリ上のプロセス情報とイベントログの相関分析を開始します...")

    for proc in processes:
        p_time = proc['create_time']
        matched = False
        
        # 仮想的なイベントログ群との比較(実際には時間枠±2秒以内で検索)
        # 攻撃者はログを消している場合、メモリには存在するがイベントログには存在しない(幽霊プロセス)
        
        # ログが存在しない、あるいは親プロセスが偽装されているかの判定ロジック
        if proc['image'].lower() in ['cmd.exe', 'powershell.exe', 'rundll32.exe']:
            print(f"[!] 警戒対象プロセス検出: PID={proc['pid']}, Image={proc['image']}, 起動時刻={p_time}")
            # ここでイベントログ側の対応するレコードを検索する処理を記述
            # 見つからない場合は「ログ消去・イベント抑制の痕跡」と判定

if __name__ == "__main__":
    # 使用例のダミーパス
    vol_json_output = "vol3_pslist_output.json"
    evtx_path = "Security.evtx"
    
    # 実際のアナリストワークフローではここで関数を呼び出す
    # procs = parse_volatility_processes(vol_json_output)
    # correlate_with_evtx(procs, evtx_path)
    print("DFIRアナリスト向け相関分析エンジンのテンプレートがロードされました。")

—

4. 現場の盲点:プロセス・ホロウイングとPPIDスプーフィングの看破

メモリとイベントログの相関分析において、最もアナリストを悩ませるのが高度な回避技術(Evasion Techniques)だ。攻撃者はイベントログや単純なプロセスリストの監視を欺くため、以下の手法を多用する。

1. PPIDスプーフィング(親プロセスIDの詐称)

通常のプロセス生成では、explorer.exe が cmd.exe を起動すれば、親は explorer.exe になる。しかし、攻撃者はAPI(UpdateProcThreadAttributeなど)を悪用し、無害なプロセス(例えば svchost.exe)を親に見せかけて悪意あるプロセスを起動する。

  • イベントログの挙動: Event ID 4688には「svchost.exe が malware.exe を起動した」と記録されるため、SOCの自動アラートはこれをスルーしがちである。
  • メモリ上の真実: Volatilityの pslist や pstree を、カーネルオブジェクトの直接スキャン結果(psscan)と比較する。pslist(アクティブなリンクリストを辿る)と psscan(メモリプールを直接スキャンして構造体を探す)の差分を取ることで、アンリンクされた隠しプロセスや、親プロセスの不整合を暴くことができる。

2. プロセス・ホロウイング(Process Hollowing)

正規のプロセス(例: notepad.exe)をサスペンド状態で起動し、そのメモリ空間(VAD)の中身を丸ごと悪意あるシェルコードに書き換えてから再開させる手法。

  • イベントログの挙動: notepad.exe が正常に起動したという Event ID 4688 しか残らない。
  • メモリ上の真実: メモリダンプから抽出したプロセスのPEB(Process Environment Block)や、VADの保護属性(PAGE_EXECUTE_READWRITE に変更されたセクション)を精査する。イメージファイル名(notepad.exe)と、実際にマップされているメモリ領域のエントリポイント(EntryPoint)の不整合を突くことで、この偽装を完全に暴くことができる。

—

5. 結論:真のインシデントレスポンスとは

セキュリティ製品のダッシュボードに表示される綺麗なグラフやアラートリストは、あくまで「攻撃者がシステムに残すことを許した表面的な情報」に過ぎない。

真に高度なインシデントレスポンスを遂行するためには、ログが消されているという最悪のシナリオを常に想定し、OSのカーネル構造体(メモリ)と監査証跡(イベントログ)の間に生じる「わずかなズレや矛盾」を見逃さない執念が必要だ。

メモリとイベントログのクロスリファレンスは、攻撃者がどれほど巧妙に足跡を消そうとも、物理的な電子の動きとして刻まれた「真実のタイムライン」を浮かび上がらせる。この技術をマスターした者だけが、巧妙化するサイバー攻撃の深部を正確に切り裂くことができるのだ。

コメント

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