はじめに:なぜいま「Linuxのメモリフォレンジック」なのか
システムが侵害された際、多くのエンジニアはまず /var/log/secure や Nginx のアクセスログ、あるいは ps や netstat コマンドの結果を確認するはずです。しかし、高度な攻撃者や洗練されたカーネルルートキット(LKM: Loadable Kernel Module)が潜入している場合、ユーザーランドのコマンド群が返す情報そのものが改ざんされている可能性があります。
プロセス一覧に見えないバックドア、ネットワークソケットを隠蔽するカーネルフック、ディスク上に痕跡を残さないファイルレスマルウェア――これらを暴く唯一の手段がメモリフォレンジックです。
今回は、業界標準ツールである Volatility 3 を用い、Linux環境のメモリダンプから「隠蔽されたプロセス」や「不正なカーネルフック」を特定する実践的な解析手法と、それを未然に防ぐためのカーネル堅牢化設定を解説します。
—
1. Volatility 3 の構造と ISF(Intermediate Symbol File)の重要性
Volatility 2 ではカーネルプロファイル(System.map と module.dwarf をまとめた zip)を手動ビルドする必要がありましたが、Volatility 3 では ISF(Intermediate Symbol File) と呼ばれる JSON 形式のシンボル定義テーブルを使用します。
Linux カーネルの構造体(task_struct や super_block など)のオフセットは、カーネルのバージョンだけでなく、ビルド時のコンフィグ(CONFIG_*)によって動的に変化します。そのため、ダンプ対象のターゲット環境と完全に一致するデバッグ情報(DWARF)から ISF を生成しなければ、メモリ空間を正しくマッピングできません。
[ターゲット環境のデバッグ情報 (vmlinux)]
│
▼ (dwarf2json で変換)
[ISF JSON ファイル (.json.xz)]
│
▼ (配置: volatility3/symbols/linux/)
[Volatility 3 エンジン] ─── (解析) ───> [物理メモリダンプ (memory.raw)]
—
2. ターゲット環境に応じた ISF シンボルファイルの作成
解析を始める前に、ターゲットと同一カーネルバージョンのシンボルファイルを生成します。この作業はインシデント発生現場のサーバーではなく、同一 OS・同一カーネルを用意した解析用サンドボックス環境で実施してください。
ステップ 1: デバッグパッケージのインストールと dwarf2json の準備
#!/usr/bin/env bash
# ターゲット環境と同一のカーネルバージョン・デバッグシンボルを導入する手順(Ubuntu/Debian系を例とする)
set -euo pipefail
# 1. デバッグシンボルリポジトリの追加とインストール
TARGET_KERNEL=$(uname -r)
echo "対象カーネル: ${TARGET_KERNEL}"
sudo apt-get update
sudo apt-get install -y linux-image-${TARGET_KERNEL}-dbgsym dwarf2json git golang
# 2. dwarf2json ツールをビルド(未導入の場合)
if ! command -v dwarf2json &> /dev/null; then
echo "[*] dwarf2json をビルド中..."
git clone https://github.com/volatilityfoundation/dwarf2json.git
cd dwarf2json
go build
sudo mv dwarf2json /usr/local/bin/
cd ..
rm -rf dwarf2json
fi
ステップ 2: ISF (JSON) の生成と Volatility 3 への登録
# デバッグ情報を含む非圧縮 vmlinux の場所を特定
VMLINUX_DBG="/usr/lib/debug/boot/vmlinux-${TARGET_KERNEL}"
SYSTEM_MAP="/boot/System.map-${TARGET_KERNEL}"
# ISF JSONの生成
echo "[*] ISF ファイルを生成しています..."
dwarf2json linux --elf "${VMLINUX_DBG}" --system-map "${SYSTEM_MAP}" > "${TARGET_KERNEL}.json"
# 容量削減のため xz 圧縮
xz -z "${TARGET_KERNEL}.json"
# Volatility 3 のシンボルディレクトリへコピー
# (Volatility3 のリポジトリパスに合わせて調整してください)
VOLATILITY_SYMBOL_DIR="/opt/volatility3/volatility3/symbols/linux"
sudo mkdir -p "${VOLATILITY_SYMBOL_DIR}"
sudo cp "${TARGET_KERNEL}.json.xz" "${VOLATILITY_SYMBOL_DIR}/"
echo "[+] シンボルの配置が完了しました: ${VOLATILITY_SYMBOL_DIR}/${TARGET_KERNEL}.json.xz"
—
3. 実践:メモリダンプから隠蔽プロセス・フックを暴く
メモリダンプ(LiME やハイパーバイザ経由で取得した memory.raw)を対象に、Volatility 3 のプラグインを実行していきます。
① プロセス隠蔽の検出(pslist vs psscan)
古典的な Linux ルートキットは、プロセスを管理する二重リンクリスト(init_task から連なる tasks メンバ)から特定の task_struct を切り離す(DKOM: Direct Kernel Object Manipulation)ことで、/proc や ps コマンドから姿を消します。
linux.pslist: カーネルの二重リンクリストを辿る(ルートキットによって隠蔽されているプロセスは表示されない)linux.psscan: メモリ全体をスキャンしてtask_structのシグネチャを直接検出する(リストから外されたプロセスも浮き彫りになる)
# 1. リンクを辿った通常の一覧を出力
python3 /opt/volatility3/vol.py -f memory.raw linux.pslist > pslist.txt
# 2. メモリスキャンによる生オブジェクトの一覧を出力
python3 /opt/volatility3/vol.py -f memory.raw linux.psscan > psscan.txt
# 3. 差分を抽出して隠蔽されたプロセスを特定
diff -u <(awk '{print $1, $2, $3}' pslist.txt | sort) <(awk '{print $1, $2, $3}' psscan.txt | sort)
この差分比較で psscan 側にしか存在しない PID が見つかった場合、DKOM によるプロセス隠蔽が確定します。
② システムコールテーブルの改ざん検知(check_syscall)
カーネルルートキットは、sys_call_table を書き換えて特定の通信やファイルを隠蔽します。linux.check_syscall プラグインを実行すると、システムコールの関数ポインタが正規のカーネルシンボル範囲から外れていないかを即座に判定できます。
# システムコールテーブルの整合性チェック
python3 /opt/volatility3/vol.py -f memory.raw linux.check_syscall
【出力の着眼点】
Table Name Index Handler Address Symbol
sys_call_table 0 0xffffffff81001230 __x64_sys_read
sys_call_table 1 0xffffffff81001240 __x64_sys_write
...
sys_call_table 217 0xffffffffa03b5050 UNKNOWN (Hooked by Module!)
Handler Address がカーネル基本領域ではなく、ロードされた外部モジュール領域(0xffffffffa0... 等)を指し、シンボルが UNKNOWN となっている場合、そのシステムコール(例: 217番 getdents64)はディレクトリ一覧の改ざん目的でフックされています。
③ 隠蔽されたカーネルモジュールの検出(check_modules)
lsmod が参照する modules リストから自身をアンリンクしたステルスモジュールを検出します。
python3 /opt/volatility3/vol.py -f memory.raw linux.check_modules
—
4. 防御側の実装:カーネル空間への不正侵入を未然に防ぐ
フォレンジックで侵入を証明することも重要ですが、本番環境ではそもそも不正なカーネルモジュールを読み込ませないアーキテクチャを構築することが鉄則です。
1. カーネルモジュール署名の強制(Kernel Module Signing)
署名のない未承認カーネルモジュールのロードをカーネルレベルで拒否します。
# /etc/default/grub 内の GRUB_CMDLINE_LINUX に以下を追加
# 署名なしモジュールのロードを一切遮断する
GRUB_CMDLINE_LINUX="module.sig_enforce=1 lockdown=confidentiality"
設定後、sudo update-grub を実行して再起動します。lockdown=confidentiality を有効化することで、/dev/mem 経由の直接メモリアクセスや未署名モジュールのロード、kexec による改ざんカーネルの起動が完全にブロックされます。
2. Auditd によるモジュールロードのリアルタイム検知
万が一モジュールがロードされようとした際、即座にアラートを発報できるように Auditd の監査ルールを定義します。
# /etc/audit/rules.d/99-kernel-modules.rules に設定を追記
# init_module / finit_module システムコールの監視(モジュール追加)
-a always,exit -F arch=b64 -S init_module -S finit_module -k module_insertion
-a always,exit -F arch=b32 -S init_module -S finit_module -k module_insertion
# delete_module システムコールの監視(モジュール削除・隠蔽の試行)
-a always,exit -F arch=b64 -S delete_module -k module_deletion
-a always,exit -F arch=b32 -S delete_module -k module_deletion
# insmod / rmmod / modprobe コマンド実行自体のトリガー監視
-w /sbin/insmod -p x -k module_execution
-w /sbin/rmmod -p x -k module_execution
-w /sbin/modprobe -p x -k module_execution
# 監査ルールの再読み込みとステータス確認
sudo augenrules --load
sudo auditctl -l
3. モジュールロード機能自体の無効化(運用フェーズ)
コンテナホストなど、起動後に新しいドライバやモジュールを読み込む必要がないシステムでは、起動完了後にローダーを完全に封印するのが最も効果的です。
#!/usr/bin/env bash
# システム起動完了後(systemd サービス等)で実行する堅牢化スクリプト
# 新規カーネルモジュールのロードを禁止(再起動するまで解除不可)
echo 1 > /proc/sys/kernel/modules_disabled
# Sysctl パラメータによる永続化(次回以降の起動時に自動適用)
cat << 'EOF' > /etc/sysctl.d/99-disable-modules.conf
# カーネルモジュールの動的ロードを無効化
kernel.modules_disabled = 1
# kexec によるカーネル差し替えを無効化
kernel.kexec_load_disabled = 1
EOF
sysctl -p /etc/sysctl.d/99-disable-modules.conf
—
5. まとめ
| 調査フェーズ | 使用ツール / コマンド | 目的 |
| :— | :— | :— |
| 事前準備 | dwarf2json | 対象カーネルの ISF シンボルファイル生成 |
| プロセス解析 | linux.pslist vs linux.psscan | DKOM によるプロセス隠蔽の炙り出し |
| カーネル解析 | linux.check_syscall / check_modules | システムコールフックおよび隠蔽モジュールの検知 |
| 恒久防御 | lockdown=confidentiality / auditd | 未署名モジュールの遮断と即時検知 |
Linux のメモリフォレンジックは、「ログが消された」「コマンドの挙動がおかしい」という極限状態において真実を語る最後の砦です。
攻撃者は侵入後、真っ先に自身のフットプリントを隠そうとします。まずは開発・検証環境で自社システムの ISF を正しく生成できるようパイプラインを整え、万が一のインシデント時にも即座にメモリ解析を展開できる体制を整えておきましょう。
コメント