【実務・中級編】 WindowsのPowerShell実行ポリシーの制限 – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

PowerShellは「管理者の福音」か「攻撃者の武器」か:ファイルレス攻撃を防ぐための要塞化術

現場でインシデント対応をしていると、決まって遭遇するのが「PowerShell」の悪用だ。正規の管理ツールを攻撃者が使いこなす「Living off the Land(環境寄生型)」攻撃において、PowerShellはまさに最強の武器となる。

「ExecutionPolicyを RemoteSigned にしてるから大丈夫」なんて考えていないだろうか? 結論から言えば、それは「玄関の鍵は閉めたが、窓は全開」と言っているに等しい。今日は、PowerShellの実行ポリシーを正しく理解し、攻撃者が好む「ファイルレス攻撃」の芽を現実的なレベルで摘み取るための防衛術を伝授しよう。

—

1. なぜ ExecutionPolicy だけでは不十分なのか

多くのエンジニアが誤解しているが、PowerShellの実行ポリシーは「セキュリティ境界」ではない。これは単なる「ユーザーの操作ミスによるスクリプト実行を防止する」ための、いわば安全装置に過ぎない。

攻撃者は、コマンドライン引数に -EncodedCommand や -NoProfile を指定し、メモリ上で難読化されたコードを直接実行する。これに対し、従来のポリシー設定は何の抵抗にもならない。我々が守るべきは、「悪意あるコードをいかにしてメモリ上で動かさないか」という一点に尽きる。

—

2. 現場で今すぐ打つべき「防御の三層構造」

設定一つで満足せず、以下の三層で防壁を構築せよ。

層一:グループポリシー(GPO)による構成管理

まずは基本の徹底だ。ドメイン環境であれば、以下のGPO設定を強制せよ。

  • コンピュータの構成 > 管理用テンプレート > Windows コンポーネント > Windows PowerShell
  • 「PowerShell スクリプトの実行を有効にする」: Allow local scripts and remote signed scripts (RemoteSigned) を指定。
  • 「PowerShell トランスクリプトの有効化」: これを必ずオンにせよ。全ての実行ログが指定のパスに保存される。インシデント発生時のフォレンジックで、これがないと詰む。

層二:Constrained Language Mode (CLM) の強制

これが今回最も伝えたい「要塞化」の核だ。Constrained Language Mode を有効にすると、PowerShellの強力な機能(Win32 APIの直接呼び出しや、.NET クラスへのアクセス)が制限される。攻撃者がメモリ上でシェルコードを注入しようとしても、このモードが弾いてくれる。

環境変数で強制的に設定するには、システム全体で以下を適用する。

# 管理者権限で実行:システム全体の環境変数を設定する例
[Environment]::SetEnvironmentVariable('__PSLockdownPolicy', '4', 'Machine')

層三:AppLocker または WDAC による実行制御

ポリシーで防げないなら、実行可能なバイナリ自体をホワイトリスト化する。AppLocker を使い、PowerShell.exe 自体の実行を特定の管理者グループのみに許可する設計が、最も堅牢な防御となる。

—

3. 実践:ログ監視による「異常検知」の自動化

防御を固めても、抜け道を探すのが攻撃者の性。最後に、攻撃の兆候を検知するための実装を紹介する。Webアプリ開発者が自身のサーバーを監視するための、Pythonによるログ監視の雛形だ。

ログ監視スクリプト(Python)

PowerShellのイベントログ(Microsoft-Windows-PowerShell/Operational)を監視し、不審な引数が含まれていたら即座に管理者に通知する。

import win32evtlog # pywin32ライブラリを使用

# 不審なコマンド引数のキーワードリスト
SUSPICIOUS_KEYWORDS = ["-EncodedCommand", "-Enc", "-W Hidden", "-NoP", "IEX", "DownloadString"]

def monitor_powershell_logs():
    server = 'localhost'
    log_type = 'Microsoft-Windows-PowerShell/Operational'
    hand = win32evtlog.OpenEventLog(server, log_type)
    
    while True:
        events = win32evtlog.ReadEventLog(hand, win32evtlog.EVENTLOG_FORWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ, 0)
        for event in events:
            if event.EventID == 4104: # ScriptBlock LoggingのID
                message = event.StringInserts[0]
                # 異常な文字列が含まれていないかチェック
                if any(keyword in message for keyword in SUSPICIOUS_KEYWORDS):
                    print(f"[ALERT] 不審なPowerShell実行を検知: {message}")
                    # ここにSlack通知やメール送信のロジックを入れる

if __name__ == "__main__":
    monitor_powershell_logs()

—

4. 最後に:インフラエンジニアとしての心構え

「設定したから終わり」ではない。攻撃手法は日々進化している。今日紹介した Constrained Language Mode やログ監視も、あくまで多層防御の一環に過ぎない。

一番のセキュリティは、「不必要な権限を与えないこと」だ。開発サーバーであれば、そもそも PowerShell をローカルで動かす必要はないはずだ。可能な限り SSH や Cloud Shell 等の制限されたインターフェースに移行し、PowerShellの存在そのものを排除していく姿勢こそが、最高峰のホワイトハッカーたる我々の目指すべき道である。

さあ、今すぐサーバーのポリシー設定を確認し、トランスクリプトログが正しく保存されているか確かめてほしい。それが、明日現場で君を助ける唯一の武器になるはずだ。

コメント

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