PowerShell難読化の基礎 (2)
概要
前回の記事に引き続き、今回もPowerShellの難読化の手法について記述します。
ドット記号によるスクリプトの実行
前回の記事では、アンパサンド記号によりInvoke-Expressionを実行する手法を取り上げましたが、ドット記号もアンパサンド記号と同様の動作をします。よって、ドット記号もまたアンパサンド記号と同様に、難読化されたPowerShellスクリプトでInvoke-Expressionコマンドレットを実行するために用いられます。以下に実行例を示します。アンパサンド記号とドット記号のどちらによっても、変数comletに格納した「Get-Host」が、コマンドレットとして評価され実行されていることがわかります。
PS C:\> $comlet = "Get-Host" PS C:\> $comlet Get-Host PS C:\> & $comlet Name : ConsoleHost Version : 5.1.17134.228 InstanceId : d3911f54-88c4-4da0-a8fe-9a18dc6ae278 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : en-US CurrentUICulture : en-US PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy DebuggerEnabled : True IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace PS C:\> . $comlet Name : ConsoleHost Version : 5.1.17134.228 InstanceId : d3911f54-88c4-4da0-a8fe-9a18dc6ae278 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : en-US CurrentUICulture : en-US PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy DebuggerEnabled : True IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace PS C:\>
コマンドレットの実行結果の利用
PowerShellの難読化では、意図的に一つしか結果が返ってこないコマンドレットを実行することにより、難読化に必要な文字列を取得するという手法があります。これだけでは何を言っているかわかりにくいため、実際に例を示すことにより説明します。例として、Invoke-Expressionとそのエイリアスであるiexを、文字列として取得する場合を考えます。
文字列「Invoke-Expression」の取得例
まずはInvoke-Expressionを取得する場合を例として示します。「Invoke-Expression」という文字列が得られるコマンドレットであれば何でもよいのですが、ここではInvoke-Commandコマンドレットを利用する手法を紹介します。 Invoke-Commandコマンドレットは、PowerShellで実行可能なコマンドを取得するためのコマンドレットです。PowerShellで実行すると、様々なコマンドが一覧で出力されるでしょう。Invoke-Commandは、引数を与えることによりコマンドを検索することが可能です。例えば「Get-」で始まるコマンドレットを検索するには、以下のように実行します。アスタリスク記号はワイルドカード演算子であるため、文字列「Get-」で始まるコマンドが出力されます。
PS C:\> Get-Command Get-* CommandType Name Version Source ----------- ---- ------- ------ Alias Get-AdlAnalyticsAccount 4.1.1 AzureRM.DataLakeAnalytics Alias Get-AdlAnalyticsComputePolicy 4.1.1 AzureRM.DataLakeAnalytics Alias Get-AdlAnalyticsDataSource 4.1.1 AzureRM.DataLakeAnalytics Alias Get-AdlAnalyticsFirewallRule 4.1.1 AzureRM.DataLakeAnalytics (以下省略)
この手法を利用して、Invoke-Expressionを文字列として取得させることが可能です。例えば以下のように実行します。実行結果がInvoke-Expressionだけになることがわかります。
PS C:\> Get-Command "*ke-E*" CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Invoke-Expression 3.1.0.0 Microsoft.PowerShell.Utility PS C:\>
Get-Commandは文字列として長いため、難読化に使うには可読性が高いと感じる人もいるでしょう。Get-Commandはgcmにエイリアスされているため、代用することが可能です。
PS C:\> Get-Alias gcm CommandType Name Version Source ----------- ---- ------- ------ Alias gcm -> Get-Command PS C:\>
先ほどのGet-Hostコマンドレットを実行する例に適用すると、以下の通りです。
PS C:\> $comlet = "Get-Host" PS C:\> .(gcm "*ke-E*") $comlet Name : ConsoleHost Version : 5.1.17134.228 InstanceId : d3911f54-88c4-4da0-a8fe-9a18dc6ae278 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : en-US CurrentUICulture : en-US PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy DebuggerEnabled : True IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace PS C:\>
文字列「iex」の取得例
前回の記事では環境変数COMSPECから文字列「iex」を取得する手法を紹介しましたが、Get-Commandを用いた文字列「Invoke-Expression」の取得手法と組み合わせることが可能です。先ほどの例と少し変えて今回はGet-Variableコマンドレットを用います。Get-VariableはPowerShellで定義された変数を取得するためのコマンドレットであり、gvにエイリアスされています。
PS C:\> Get-Alias gv
CommandType Name Version Source
----------- ---- ------- ------
Alias gv -> Get-Variable
PS C:\> gv
Name Value
---- -----
$ gv
? True
^ Get-Alias
args {}
ConfirmPreference High
ConsoleFileName
(以下省略)
例えば、変数MaximumDriveCountはPowerShellにデフォルトで定義されている変数名であるため、以下のように文字列「iex」の生成に利用可能です。
PS C:\> $comlet = "Get-Host"
PS C:\> gv *umDri*
Name Value
---- -----
MaximumDriveCount 4096
PS C:\> (gv *umDri* | %{$_.Name})[9,11,2] -Join ''
iex
PS C:\> .((gv *umDri* | %{$_.Name})[9,11,2] -Join '') $comlet
Name : ConsoleHost
Version : 5.1.17134.228
InstanceId : d3911f54-88c4-4da0-a8fe-9a18dc6ae278
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : en-US
CurrentUICulture : en-US
PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
PS C:\>
評価されない文字の挿入
PowerShellには「コマンドレット等に挿入することは可能であるが評価されない文字列」があります。例えばバッククオート記号は、以下のエスケープシーケンスに一致しなければ、挿入しても文字列に影響を及ぼしません。
`0 NULL `a 警告音 `b バックスペース `f フォームフィード `n 改行 `r キャリッジリターン `t 水平タブ `v 垂直タブ
よって、「Get-Host」の場合は、以下のように表現することが可能です。
PS C:\> "`G`et-`H`o`st" Get-Host PS C:\> "`G`et-`H`o`st" | iex Name : ConsoleHost Version : 5.1.17134.228 InstanceId : d3911f54-88c4-4da0-a8fe-9a18dc6ae278 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : en-US CurrentUICulture : en-US PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy DebuggerEnabled : True IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace PS C:\>
まとめ
今回もPowerShellの難読化手法について取り上げました。次回も引き続き、PowerShellの難読化手法について取り上げます。次々回では難読化されたPowerShellの難読化解除の手法について取り上げる予定です。