現場の最前線でインシデントに立ち向かう君たちへ。
「アラートが鳴ったからログを見たが、何も異常はない」。そう報告してくるジュニアアナリストを、私は何度も現場から遠ざけてきた。ログなど、攻撃者が握っていればどうとでも書き換えられる。だが、メモリは嘘をつかない。
今日は、攻撃者が足跡を消すために多用する「親プロセス偽装(Parent PID Spoofing)」を、Volatility 3を使ってどう暴くか、そして我々エンジニアがその温床をどう塞ぐべきかについて、実務的な話をしよう。
—
1. 攻撃者の常套手段:プロセスツリーを「誤読」させる
攻撃者は、システム管理者を欺くために「親プロセス」を偽装する。本来、powershell.exeはexplorer.exeからではなく、services.exeやwmiprvse.exeから起動されるのが一般的だ。しかし、攻撃者はAPI(UpdateProcThreadAttributeなど)を悪用し、親プロセスをexplorer.exeに偽装させることで、あたかもユーザーが手動でシェルを開いたかのように見せかける。
Volatility 3のwindows.pstreeプラグインを使えば、この階層関係を可視化できる。
# メモリダンプからプロセスツリーを抽出
python3 vol.py -f memory.dmp windows.pstree
出力結果で注目すべきは、「不自然な親子の繋がり」だ。例えば、Webサーバーのプロセスであるw3wp.exeの直下に、身に覚えのないpowershell.exeがぶら下がっていれば、それは十中八九、Webアプリの脆弱性(RCE)を経由したバックドアの設置だ。
—
2. なぜ「Webアプリ」が入り口になるのか
多くのインシデントの起点には、不適切な入力処理がある。攻撃者がOSコマンドを実行できてしまう脆弱性があれば、彼らは迷わずpowershellや/bin/shを呼び出す。
これを防ぐための鉄則は「外部入力を直接コマンドラインに渡さない」ことだ。PHPで言えば、system()やexec()の使用は論外。どうしても外部コマンドが必要な場合でも、厳格なホワイトリスト管理が必須となる。
【対策例】Pythonによるコマンド実行のセキュアなカプセル化
サブプロセスを起動する際は、シェル経由ではなく、引数をリスト形式で渡すことでインジェクションを防ぐ。
import subprocess
import shlex
def secure_execute(user_input):
# ホワイトリストによる入力検証(ここが最も重要)
allowed_commands = ["status_check", "log_rotate"]
if user_input not in allowed_commands:
raise ValueError("不正なコマンドが要求されました。")
# shell=False にすることで、シェルインジェクションを物理的に遮断
# リスト形式で渡すことで、OSレベルでの引数解釈の曖昧さを排除
try:
result = subprocess.run(
["/usr/bin/python3", "/opt/scripts/internal_task.py", user_input],
capture_output=True,
text=True,
check=True
)
return result.stdout
except subprocess.CalledProcessError as e:
# エラー詳細をユーザーに返さない(情報の漏洩防止)
return "Internal process error."
—
3. インフラレイヤーでの防御:プロセスの「監視」と「制限」
たとえコードで防ぎきれなくても、OSレイヤーで「異常な親子関係」が生成された瞬間に叩き潰す設定が必要だ。Linux環境であればauditd、WindowsであればSysmonがその役割を担う。
特に、Webサーバー(www-dataやIIS AppPool)のような「特権を持つべきではないユーザー」が、シェルを起動すること自体を禁止するポリシーを適用しよう。
【設定例】Nginx + AppArmor(Linuxの場合)
Webサーバープロセスが意図しないバイナリを実行できないよう、AppArmorでプロファイルを定義する。
# /etc/apparmor.d/usr.sbin.nginx
# nginxが特定のディレクトリ以外で実行権限を持つことを禁止する
/usr/sbin/nginx {
# 必要なファイルへのアクセスのみ許可
/usr/sbin/nginx r,
/etc/nginx/** r,
/var/log/nginx/* w,
# 不審なバイナリの実行を拒否
deny /bin/sh x,
deny /bin/bash x,
deny /usr/bin/python* x,
}
—
4. 現場のエンジニアへのメッセージ
インシデントハンドリングは、パズルだ。Volatilityでプロセスツリーを眺めている時、君たちが目にしているのは「攻撃者が残した偽りの景色」かもしれない。
- 「なぜそのプロセスがそこにいるのか?」
- 「親プロセスは、本当にその処理を行う正当な権限を持っているのか?」
この疑念を常に持ち続けてほしい。もし君たちが書いたコードが、たった一つの$_GET変数をそのままshell_exec()に渡しているなら、そのコードは攻撃者にとっての「黄金の鍵」になっている。
今日紹介したpstreeでの可視化と、プロセス実行を制御するサンドボックス的な考え方。これらを日々の開発サイクルに組み込むだけで、攻撃者のコストは跳ね上がる。泥臭いが、これが「守る」ということの正体だ。
次は、メモリダンプから「隠蔽されたスレッド」を特定する手法について話すとしよう。準備はいいか?
コメント