終わりのない「いたちごっこ」を終わらせる:WDACによるカーネルレベルの防御術
現場でインシデント対応をしていると、ふと虚しくなる瞬間がある。最新のEDRを入れた、WAFで攻撃を弾いた、パッチも当てた。それでも、ランサムウェアや標的型攻撃は「正規のツール」や「署名済みのバイナリ」を悪用して、いとも簡単に権限昇格し、カーネルに手を出す。
AppLockerを使っている? それは素晴らしい第一歩だが、正直に言おう。AppLockerはユーザーモードの防御に過ぎない。攻撃者がカーネルドライバをロードしたり、メモリを改ざんしたりすれば、その制御は容易にバイパスされる。
今回解説するのは、その一段上を行くWindows Defender Application Control (WDAC)だ。カーネルレベルで「許可されていないコードは1バイトたりとも実行させない」という、鉄の意志をOSに叩き込むためのアプローチを紐解いていく。
—
なぜAppLockerでは不十分なのか?
攻撃者の視点に立てば答えは明白だ。AppLockerは主に lsass.exe やユーザー空間のプロセスを監視するが、攻撃者は特権(SYSTEM権限)を奪取した後、脆弱性のある署名済みドライバをロードしてカーネルの防御を無効化する「Bring Your Own Vulnerable Driver (BYOVD)」という手法を用いる。
これに対し、WDACはカーネルレベルでコードの整合性を検証する。つまり、信頼された署名、あるいはハッシュ値を持つもの以外は、ドライバであれスクリプトであれ、実行の入り口で遮断される。これが「要塞化」の真髄だ。
—
実践:WDACポリシー作成の勘所
WDACの導入で最大の失敗は「厳しくしすぎて業務を止めること」だ。まずは「監査モード」で運用し、何がブロックされるかを確認するのが鉄則だ。
以下は、PowerShellを使って、現在動作している信頼されたアプリケーションをベースにポリシーを作成する基本ステップだ。
# 1. 監査モードで、現在の環境の信頼されたバイナリをスキャンしてポリシーの雛形を作成
New-CIPolicy -Level PcaCertificate -FilePath "C:\WDAC\InitialPolicy.xml" -UserPEs
# 2. ポリシーを変換して展開用バイナリにする
ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\InitialPolicy.xml" -BinaryFilePath "C:\WDAC\InitialPolicy.p7b"
# 3. 監査モードで適用(最初はこれで数週間様子を見るのが鉄則)
Set-RuleOption -FilePath "C:\WDAC\InitialPolicy.xml" -Option 3 # 監査モードを有効化
運用中に「なぜか動かない」という事象が発生した場合、イベントビューアーの Microsoft-Windows-CodeIntegrity/Operational を確認してほしい。ここには「実行が拒否された理由」がすべて記録されている。
—
開発現場の盲点:スクリプト実行制限と回避策
インフラがどれだけ強固でも、Webアプリケーションの脆弱性からサーバーへ侵入され、そこからPowerShellやJSのスクリプトを走らせる攻撃は後を絶たない。WDACは、powershell.exe の実行ポリシーよりも上位層で機能する。
例えば、攻撃者がよく使う Invoke-Expression によるメモリ上でのコード実行も、WDACが「Constrained Language Mode」を強制していれば、危険なAPI呼び出しが制限され、攻撃は不発に終わる。
セキュアな実装へのヒント:入力検証とコード実行の分離
開発者が意識すべきは、外部からの入力を「実行可能なコードのパーツ」として扱わせないことだ。以下に、PHPでの典型的な脆弱なパターンと、それを防ぐための「考え方」を示す。
// 【警告】絶対にやってはいけない実装(OSコマンドインジェクションのリスク)
// $user_input = $_GET['file'];
// system("cat " . $user_input);
// 【セキュアな設計】
// 1. ホワイトリストによる検証
$allowed_files = ['config.json', 'data.csv'];
$user_input = $_GET['file'];
if (!in_array($user_input, $allowed_files)) {
die("不正なアクセスです。");
}
// 2. 直接実行させず、読み込みのみに限定する
$content = file_get_contents('/var/www/data/' . $user_input);
echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
WDACを導入していても、アプリケーション層でこのように「実行の境界」を明確に引く必要がある。WDACは「何が実行できるか」を制限し、アプリケーションコードは「何を入力として受け取るか」を制限する。この二段構えが、真のゼロトラストだ。
—
最後に:完璧な防御は「運用」にある
WDACを導入したからといって、セキュリティ対策が完了するわけではない。攻撃者は常に「正規の証明書」を盗もうと画策するし、新しい脆弱性を探している。
- 定期的なポリシー更新: アプリケーションをアップデートしたら、WDACポリシーも更新しなければならない。CI/CDパイプラインに「署名プロセス」を組み込み、リリースされる全バイナリに正当な署名を付与する運用フローを構築することが、結局は一番の近道だ。
- ログの監視: イベントビューアーをSIEM(SplunkやMicrosoft Sentinelなど)に転送し、WDACによるブロック通知を即座に検知できるようにすること。
セキュリティは「製品」ではなく「規律」だ。WDACはその規律を強制するための強力な武器になる。今日からでも、テスト環境でポリシーの生成を試してみてほしい。自分の環境で何が「正規」で、何が「未知」なのかを知ることから、要塞化は始まる。
コメント