【実務・中級編】 ファイルレスマルウェアのメモリ内実行検知とペイロード抽出 – インシデントレスポンス & フォレンジック(DFIR)防御ガイド

現場の最前線で戦うエンジニア諸君、お疲れ様。今日もどこかのサーバーで、痕跡を残さない「幽霊」たちが暗躍している。

今日は、ディスク上に一切のファイルを作成せず、メモリ空間だけで悪意あるコードを完結させる「ファイルレスマルウェア」の正体と、その狩り方について話そう。教科書に載っている「ウイルス対策ソフトを入れろ」といった甘いアドバイスはここでは無用だ。攻撃者は、我々がOSのメモリ管理構造をどこまで深く理解しているかを試しているんだ。

1. 幽霊の正体:Reflective DLL Injection と Process Hollowing

ファイルレスマルウェアの恐ろしさは、ディスクI/Oを発生させないことにある。つまり、一般的なファイルスキャン型のセキュリティ製品(AV)は、そもそも「検査対象」を見つけられない。

彼らがよく使う手口は主に2つ。

  • Reflective DLL Injection: 標的プロセスを乗っ取り、自分自身をメモリ空間にロードする。Windowsのローダーを使わずに独自のロードロジックをメモリ上で実行する手法だ。
  • Process Hollowing: 正当なプロセス(例えば svchost.exe など)をサスペンド状態で起動し、そのコード領域を悪意あるコードで置き換えてから再開する。

これらを発見する唯一の鍵は、OSのメモリ構造、特に VAD (Virtual Address Descriptor) ツリーの解析にある。VADはプロセスがどのメモリ領域をどう使っているかを管理するツリー構造だが、攻撃者はここに「本来あり得ないはずのフラグ(PAGE_EXECUTE_READWRITEなど)」が立った領域を潜り込ませる。

2. 実務で使えるメモリフォレンジックの視点

インシデント発生時、君たちが真っ先に確認すべきは「不自然なメモリ保護属性」だ。

メモリフォレンジックツール(Volatilityなど)を用いる際、単にプロセス一覧を見るだけでは不十分だ。以下のポイントを注視してほしい。

  • メモリ保護属性の不一致: PAGE_EXECUTE_READWRITE (RWX) を持つ領域は非常に危険だ。本来、コード領域は Read/Execute であり、書き込み可能である必要はない。RWX領域は、インジェクションの温床だ。
  • ファイルにマッピングされていない実行領域: VADツリーを辿った際、どの実行ファイルにも紐付いていない(Mapped FileがNull)のに実行権限がある領域があれば、それは100%「幽霊」の住処だ。

3. 防御のための「泥臭い」実装と設定

「ファイルレス」を完全に防ぐのは難しいが、攻撃の難易度を跳ね上げることは可能だ。Webアプリ開発やインフラ構築の現場で、以下の対策を徹底してほしい。

3.1. EDR/ASRルールの適用(設定ファイル例)

Windows環境であれば、攻撃者がメモリインジェクションに使うAPI(VirtualAllocEx, WriteProcessMemoryなど)を監視する構成が必須だ。Microsoft DefenderのAttack Surface Reduction (ASR) ルールを以下の設定で強化する。

# PowerShellでASRルールを有効化する例
# 攻撃者がよく行うプロセスインジェクションをブロックするルール
Add-MpPreference -AttackSurfaceReductionRules_Ids "7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c" -AttackSurfaceReductionRules_Actions Enabled

3.2. Webアプリ層での防御(PHPのセキュア実装)

攻撃者の侵入口になりやすいのが、サーバーサイドの実行権限を悪用したコマンド実行だ。PHPで外部プロセスを呼び出す際は、exec() や system() を使うのではなく、サンドボックス化を意識すべきだ。

<?php
/**
 * 危険な関数を無効化し、最小限の権限で実行する
 * php.iniでdisable_functionsを設定するのが定石だが、
 * コードレベルでも入力のホワイトリスト化を徹底すること。
 */

function execute_safe_command($input) {
    // 許可されたコマンドのみをホワイトリストで管理
    $allowed_commands = ['/usr/bin/git', '/usr/bin/rsync'];
    
    // 入力値の検証(シェルインジェクション対策)
    if (!in_array($input, $allowed_commands)) {
        throw new Exception("許可されていないコマンドです。");
    }

    // 実行時はフルパス指定かつ引数をエスケープ
    $cmd = escapeshellcmd($input);
    return shell_exec($cmd . " --version");
}
?>

3.3. コンテナ環境でのメモリ保護(Docker/Kubernetes)

コンテナ環境では、seccomp プロファイルを使って、コンテナが実行できるシステムコールを制限するのが最も効果的な「ファイルレス対策」になる。

/* seccomp-profile.json の例 */
{
    "defaultAction": "SCMP_ACT_ERRNO",
    "syscalls": [
        {
            "names": ["read", "write", "exit", "execve"],
            "action": "SCMP_ACT_ALLOW"
        }
        /* 必要最低限のシステムコールのみ許可し、
           ptraceやprocess_vm_writevを拒否することで
           プロセスインジェクションを物理的に封じる */
    ]
}

最後に:エンジニアとしての心構え

「ファイルがないから安全だ」と考えるのは、セキュリティの素人だ。攻撃者は、君たちがOSのメモリの深淵を覗き込まないことを知っている。

インシデントレスポンスの現場では、ツールが吐き出した結果を鵜呑みにせず、「なぜこのプロセスがこのメモリ領域を確保しているのか?」という疑問を持ち続けること。その執念こそが、組織を守る最後の砦になる。

不明なプロセスを見つけたら、まずはVADツリーをダンプしろ。そして、そのメモリ領域のヘッダーに MZ (Windows PEのシグネチャ) が隠れていないか確認するんだ。君たちの健闘を祈る。

コメント

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