どこで使うの?
Windows資格情報を設定するバッチファイルを、どうしてもユーザーに配布して実行させる必要があるとします。この時、cmdkeyコマンド実行部分にてパスワードを平文で書いたりするのはナンセンスです。そこで、内容を難読化しておきます。
免責
この方法は、一般ユーザーがうっかりバッチファイルの中身を見てしまってもパスワードなどの認証情報が読めないようにするためです。この程度ではプロ相手には通用しませんので、本格的なセキュリティ対策として利用するのはお控えください。
スクリプトを用意
とりあえず、実行したいスクリプトを用意します。cmdkey /add:Altair /user:Vega /pass:Bengbu
のようなものを実行するわけですが、今回は動作確認をしやすくするために、文字列をechoするだけの簡単なスクリプトにします。
write-host hello-obfuscation
暗号化
上記の文字列を何かしらの方法で暗号化します。
[Convert]::ToBase64String( ([System.Text.Encoding]::Default).GetBytes("write-host hello-obfuscation"))
今回はBase64暗号を用いて、このような文字列になりました。
d3JpdGUtaG9zdCBoZWxsby1vYmZ1c2NhdGlvbg==
復号化
それではデコードしてみます。
[System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String("d3JpdGUtaG9zdCBoZWxsby1vYmZ1c2NhdGlvbg=="))
デコード出来ました。
write-host hello-obfuscation
Invoke-Expression
しかし、これでは文字列のままなので、コマンドとして実行できていません。
そこで、Invoke-Expressionコマンドを使用します。
先ほどのデコードした時のコマンドをInvoke-Expression
の引数として渡します。
Invoke-Expression -Command $([System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String("d3JpdGUtaG9zdCBoZWxsby1vYmZ1c2NhdGlvbg==")))
出力結果を見ると、もともとのWrite-Host
コマンドが実行できていることが分かります。
hello-obfuscation
Aliasと省略
Invoke-Expression
は長いので、省略します。また、-Command
も無くてもいいので省略します。
Invoke-Expression
と-Command
の代わりにiex
を使いましょう。
iex
がInvoke-Expression
と-Command
の代わりになることは、Get-Alias
コマンドで確認できます。
Get-Alias iex
CommandType Name Version Source
----------- ---- ------- ------
Alias iex -> Invoke-Expression
実際に省略したコマンドはこのようになっています。
iex $([System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String("d3JpdGUtaG9zdCBoZWxsby1vYmZ1c2NhdGlvbg==")))
出力結果から省略前と同様にWrite-Host
コマンドが実行できています。
hello-obfuscation
iexの秘匿
iex
という文字列がそのまま入っているスクリプトはセキュリティ対策ソフトで検知されることが多いです。そこで、文字列iex
を動的に生成し、これをコマンド化して使うことにしましょう。
まずは、iex
文字列でコマンドが実行できることを確認します。
& "iex" "write-host hello-obfuscation"
hello-obfuscation
このように、&
の後ろに書いた最初の文字列がコマンドとして認識され、その引数に2番目の文字列が利用されていることが分かります。
後は、iex
という文字列をどう生成するのかが分かれば良さそうです。
そこで利用するのは、確実に結果が分かっているコマンドです。そのコマンドの選定条件は下記です。
- 想定する環境での実行結果が常に同じであること
- 実行結果に同じ位置で
i
、e
、x
の3文字が出現すること
ここでは、こんなコマンドを利用してみましょう。
gcm cmd
CommandType Name Version Source
----------- ---- ------- ------
Application cmd.exe 10.0.1904… C:\WINDOWS\system32\cmd.exe
簡単にしたいので、Source
部分だけ取り出しましょう。
$(gcm cmd).Source
C:\WINDOWS\system32\cmd.exe
まずは、ここからi
を取り出してみます。
$(gcm cmd).Source[-23]
I
大文字ですね。Windowsでは大文字小文字は無視されるので、見なかったことにします。
次に、e
も取り出しましょう。
$(gcm cmd).Source[-23,-1]
I
e
最後に、x
です。
$(gcm cmd).Source[-23,-1,-2]
I
e
x
そして、配列に格納された3つの文字を連結して、文字列にします。
$(gcm cmd).Source[-23,-1,-2] -Join $Null
Iex
動的生成はできたようです。先ほどのコマンドと混ぜてみましょう。& "iex" "write-host hello-obfuscation"
でしたね。
& $($(gcm cmd).Source[-23,-1,-2] -Join $Null) "write-host hello-obfuscation"
hello-obfuscation
完璧です。
完成したスクリプト
最後に、先ほどの暗号化と混ぜてみましょう。
& $($(gcm cmd).Source[-23,-1,-2] -join $null) $([System.Text.Encoding]::Default.GetString([System.Convert]::FromBase64String("d3JpdGUtaG9zdCBoZWxsby1vYmZ1c2NhdGlvbg==")))
hello-obfuscation
Hello Obfuscation !
まとめ
Base64は簡単な可逆暗号なので、セキュリティ対策としては甘いです。
ソースに平文でBase64
って書いてあるので、
一般ユーザーの目は誤魔化せても、プロなら一瞬で解読されますね。
不可逆暗号を使ったほうが良いと思います。
ここでは、タイトルに銘打ったとおり基本なので割愛します。