エンコードされた PowerShell コマンドをデコードする方法
- アラート、プロセス作成イベント、EDR のコンソールからコマンドライン全体をコピーし、コマンドラインまたは Base64 に貼り付けます。Base64 を囲む引用符があっても構いません。
- デコーダーは、どの省略形(
-e、-ec、-encなど、-でも/でも)の-EncodedCommand引数も見つけてデコードします。 - ステータスに、どの文字コードを使ったかが表示されます。PowerShell が想定する UTF-16LE か、バイト列が UTF-16 に見えない場合は UTF-8 です。
- デコードされたスクリプト を読みます。
[Convert]::FromBase64String('…')のリテラルが含まれていれば、その下に検出した形式とサイズ付きで一覧表示されます。テキストのペイロードは出力欄で開き、圧縮されたもの(GzipStreamやDeflateStreamで使われる gzip、zlib、raw deflate)には展開ボタンが付き、それ以外のバイナリのペイロードはファイルとして保存できます。
無害な例:
powershell.exe -NoP -NonI -W Hidden -Enc VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAnAGgAZQBsAGwAbwAnAA==
これは Write-Output 'hello' にデコードされます。同じテキストを UTF-8 の Base64 にすると V3JpdGUtT3V0cHV0ICdoZWxsbyc= になり、PowerShell はこれを拒否するか誤って読みます。
ログの中でエンコードされたコマンドを見分ける
UTF-16LE のため、エンコードされたスクリプトの先頭は見分けのつく Base64 になります。検知ルールはこれにマッチさせます。
| Base64 の先頭 | スクリプトの先頭 |
|---|---|
JAB | $(変数への代入。たとえば JABzAD0A は $s=) |
SQBFAFgA | IEX |
aQBlAHgA | iex |
SQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuAA | Invoke-Expression |
SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0AA | Invoke-WebRequest |
TgBlAHcALQBPAGIAagBlAGMAdAA | New-Object |
WwBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcA | [Convert]::FromBase64String |
この形が成り立つのは先頭だけです。スクリプトの途中では、同じ単語でもバイトオフセットを 3 で割った余りによって 3 通りの Base64 の綴りがありうるので、ログを 1 つの綴りで検索すると残りの 2 つを見逃します。
怪しいコマンドを安全に解析する
エンコードされたコマンドは、プロセス一覧をざっと見ただけではスクリプトがわからないようにする常套手段です。アラートに現れたら:
- デコードだけにする。 このページはテキストを変換するだけで、Cloudflare のページビュー計測以外のネットワーク通信はできません。コマンドを PowerShell のウィンドウに貼り付けたり、デコードした出力を
iexに渡したりしないでください。 - 意図と痕跡を読み取る。 URL、ドメイン、IP アドレス、ファイルパス、レジストリキー、スケジュールタスク名を、インシデントのメモやブロックリスト用に控えておきます。
- さらに下の層を探す。 入れ子の
FromBase64String呼び出し、IO.Compression.DeflateStreamやGzipStream、文字コードの-join、文字列の反転は、よくあるラッパーです。各層を同じ方法でデコードしてください。 - 取り出したバイナリは検体として扱う。 入れ子の一覧から保存したペイロードはマルウェアかもしれません。ハッシュを取り、隔離された環境でだけ解析してください。
- すでに平文が記録されているログを確認する。 スクリプトブロックのログ記録が有効なら、Windows はデコードされたスクリプトを
Microsoft-Windows-PowerShell/Operationalのイベント 4104 として記録します。プロセス作成イベント(コマンドラインの監査を有効にしたセキュリティログの 4688、または Sysmon のイベント 1)には、エンコードされたコマンドラインそのものが記録されます。
正当な用途と「スクリプトをエンコード」タブ
管理者は、スクリプトが cmd.exe、スケジュールタスク、リモートシェル、構成管理ツールを経由するときの引用符の問題を避けるために -EncodedCommand を使います。スクリプトをエンコード でこの引数を作れます。スクリプトを入力し、コマンド の接頭辞(powershell -NoProfile -EncodedCommand、pwsh -NoProfile -EncodedCommand、powershell -enc、Base64 のみ)を選んでコピーします。結果が cmd.exe のコマンドラインの上限 8,191 文字を超えると警告が表示されます。
Python と PowerShell でのデコード
import base64
script = base64.b64decode(b64).decode("utf-16-le")
$script = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b64))
どちらもテキストを返すだけです。エンコードの側については、PowerShell の Base64 のページ と UTF-16 を Base64 に変換 をご覧ください。
よくある問題
- 出力が中国語の文字のように見える:UTF-8 の Base64 を UTF-16 としてデコードしています。バイトのパターンが UTF-16 に合わない場合、ツールは UTF-8 に切り替え、どの文字コードを使ったかをステータス行に表示します。
- 無効な Base64:ログのフィールドの長さ制限でコマンドが切れたか、複数行に折り返されています。断片をつなげ、Base64 の後ろにある、Base64 の一部でないものを取り除いてください。
- コマンドラインがまったくデコードされない:その Base64 は
-EncodedCommandの後ではなく、-Command "…FromBase64String('…')…"の文字列の中にあるのかもしれません。Base64 の文字列だけを貼り付けてください。UTF-16 のテキストでなければ、Base64 デコーダー か Base64 をファイルに変換 で中身がわかります。
よくある質問
powershell -enc は何をするのですか?
-enc は -EncodedCommand の短縮形です。PowerShell は Base64 の引数を UTF-16LE のテキストとしてデコードし、スクリプトとして実行します。-e や -ec など、ほかの短縮形も受け付けます。
悪意のある PowerShell コマンドをここでデコードしても安全ですか?
デコードはテキストの変換で、何も実行されません。さらにこのページの Content Security Policy は、Cloudflare のページビュー計測を除くすべてのネットワークリクエストをブロックしています。何をするか見るためにデコードしたスクリプトを実行するのは絶対にやめてください。保存したバイナリのペイロードは、隔離された解析環境の中でだけ扱ってください。
Base64 で 1 文字おきに A が現れるのはなぜですか?
PowerShell は UTF-16LE を想定していて、ASCII の各文字の後ろにゼロのバイトが続くからです。このゼロのバイトが、Write- を表す VwByAGkAdABlAC0A のような A の繰り返しパターンを生みます。
PowerShell で実行せずに -EncodedCommand をデコードするには?
[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b64)) を使えば、テキストを返すだけです。結果を Invoke-Expression や iex にパイプしないでください。