メモリ上のレジストリを制する者が、インシデントの深淵を制する
「ディスクを調べればログは残っている」――そう思っているなら、今すぐその甘い考えを捨ててほしい。現代の高度な脅威アクターは、ファイルレス攻撃を好む。彼らはディスクに痕跡を残さず、メモリ上で完結するマルウェアや、レジストリの改ざんを駆使して永続化を図る。
インシデントレスポンスの現場において、メモリフォレンジックは「最後の砦」だ。今回は、メモリ上に展開されたレジストリハイブを抽出し、攻撃者の息遣いを読み解く手法を、実務的な視点で解説しよう。
—
なぜ「メモリ上のレジストリ」なのか?
Windowsのレジストリは、システム起動時に C:\Windows\System32\config から読み込まれるが、その実体はメモリ上の構造体として管理されている。攻撃者は、Run キーや Services キーを書き換えてバックドアを仕込む際、OSのAPIを通じてメモリを操作する。
ここで重要なのは、「メモリ上の状態とディスク上の状態は一致しないことがある」という事実だ。攻撃者がメモリ上でレジストリキーを動的に書き換え、ディスクへの書き込みを最小限に抑えていれば、従来のフォレンジックツールでディスクをスキャンしても何も出てこない。
攻撃手法の盲点:ファイルレス永続化のPoC
攻撃者はよく、PowerShellの Set-ItemProperty を使い、メモリ上でレジストリを操作する。
# 攻撃者がメモリ上でレジストリを操作し、永続化を図る例
# この操作はディスクのタイムスタンプを即座に更新しない場合がある
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name 'SysUpdate' -Value 'powershell.exe -WindowStyle Hidden -EncodedCommand <Base64文字列>'
このコマンドが実行された直後、メモリ内には「改ざんされたレジストリ構造」が存在する。これをVolatilityのようなツールで抽出・解析することで、攻撃者が注入した悪意あるコマンドを特定できる。
—
実践:メモリからハイブを抽出して解析する
Volatility 3を用いた調査プロセスは、現場のエンジニアが習得すべき基本スキルだ。
1. メモリダンプの取得: DumpIt 等でメモリを取得。
2. ハイブの特定: windows.registry.hivelist プラグインで、メモリ上のハイブのオフセットを特定。
3. 抽出: windows.registry.dumpfiles で抽出。
この後、抽出したハイブファイルを Registry Explorer 等で開けば、ディスク上のファイルとは異なる「メモリ内の生データ」として調査が可能だ。
—
防御:攻撃の芽を摘むセキュアな設計
レジストリの改ざんを検知し、未然に防ぐには「監視」と「権限の最小化」が鍵となる。OSのセキュリティ設定を堅牢化し、不審な変更をブロックする設定を適用しよう。
1. Nginx/WAFでの不審なリクエストの遮断
Webサーバー経由でPowerShellが実行されるような脆弱性(RCE)を許さないことが大前提だ。Nginxの mod_security やクラウドWAFで、危険な文字列をブロックする。
# /etc/nginx/conf.d/security.conf
# 悪意あるPowerShellコマンドの実行を試みるリクエストをブロックする例
location / {
# 'powershell' や 'EncodedCommand' を含むリクエストを拒否
if ($query_string ~* "powershell|EncodedCommand|Start-Process") {
return 403;
}
}
2. EDR/Sysmonによるレジストリ監視(設定サンプル)
レジストリの「自動実行キー」への書き込みをイベントログに残すことが重要だ。Sysmon を導入し、以下の構成で監視を行う。
<!-- sysmonconfig.xml の一部 -->
<RegistryEvent onmatch="include">
<!-- Runキーの変更を監視する設定 -->
<TargetObject condition="contains">\CurrentVersion\Run\</TargetObject>
<TargetObject condition="contains">\CurrentVersion\RunOnce\</TargetObject>
</RegistryEvent>
3. Pythonによるレジストリ改ざん検知の自動化(プロトタイプ)
監視エージェントが動作しない環境でも、定期的にレジストリの状態をチェックするスクリプトを運用することで、インシデントの早期発見が可能になる。
import winreg
def check_run_key():
"""
Runキーを監視し、不審なエントリがないか確認するスクリプト
"""
path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_READ)
for i in range(winreg.QueryInfoKey(key)[1]):
name, value, _ = winreg.EnumValue(key, i)
# 許可されていないパスやコマンドが含まれていないかチェック
if "powershell" in value.lower() or "temp" in value.lower():
print(f"[!] 警告: 不審な自動実行キーを発見: {name} -> {value}")
winreg.CloseKey(key)
except Exception as e:
print(f"エラーが発生しました: {e}")
if __name__ == "__main__":
check_run_key()
—
現場のエンジニアへ伝えたいこと
技術は進化し、攻撃手法は巧妙化する。しかし、「OSの挙動を深く理解する」という原則は変わらない。レジストリをただの設定値として見るのではなく、「OSの実行状態を示す動的なデータ構造」として捉えてほしい。
インシデントが発生した際、慌ててディスクを抜き出す前に、まずはメモリの揮発を恐れろ。メモリを制する者だけが、攻撃者の隠した尻尾を掴むことができる。明日の運用から、まずはSysmonの導入と、レジストリ監視のログ収集を徹底することから始めてみてほしい。それが、君のインフラを堅牢にする最初の一歩になるはずだ。
コメント