本系列预计有三节,分别记录关于WMI
的一些基础知识,WMI
的永久订阅事件,WMI
常见的攻防对抗手段
WMI
的全称是 Windows Management Instrumentation
,即 Windows
管理规范,在 Windows
操作系统中,随着 WMI
技术的引入并在之后随着时间的推移而过时,它作为一项功能强大的技术,从 Windows NT 4.0
和 Windows 95
开始,始终保持其一致性。它出现在所有的 Windows
操作系统中,并由一组强大的工具集合组成,用于管理本地或远程的 Windows
系统。虽然WMI已经被大众熟知,并且从其创始以来,已经被系统管理员大量使用,但随着WMI
技术的不断演变以及在恶意攻击中的使用,它逐渐成为恶意攻击者的利器.在攻击活动中的作用一般有系统侦察获取系统信息,反病毒和虚拟机的检测,横向移动,权限持久化以及数据窃取等作用.
随着越来越多的攻击者利用WMI
进行攻击,他将会是安全维护人员,事件响应人员,取证分析师必须掌握的一项重要技能,并且要明白如何发挥它的优势。
WMI ( Windows Management Instrumentation )
管理规范是微软实现的由分布式管理任务组(DMTF)
发布的基于Web
的企业管理(WBEM
)和公共信息模型(CIM
)标准,是内置在 Windows 2000、Windows XP
和 Windows Server 2003
系列操作系统中核心的管理支持技术,是一种规范和基础结构,通过它可以访问、配置、管理和监视所有的几乎所有的 Windows
资源。在 WMI
之前,能够以编程方式访问 Windows
资源的惟一方法就是通过 Win32 API
。这种情况使 Windows
系统管理员无法通过一种简便的方法利用常见的脚本语言来自动化常用的系统管理任务,因为大多数脚本语言都不能直接调用 Win32 API
。WMI
是架构在组件对象模型COM(Component Object Model COM)
技术之上的,是微软的一套软件组件的二进制接口标准。这使得跨编程语言的进程间通信、动态对象创建成为可能。
上边已经提到过,WMI
是微软实现的由分布式管理任务组(DMTF)
发布的基于 Web
的企业管理(WBEM)
和公共信息模型(CIM)
标准。
WMI的基础结构,引用微软提供的结构图如下:
Fireeye
公布白皮书中关于WMI
的架构如下:
WMI 提供程序是一个COM
对象,用于监视WMI
的一个或多个托管对象.托管对象是逻辑或物理企业组件,例如硬盘驱动器、网络适配器、数据库系统、操作系统、进程或服务。
与驱动程序类似,提供程序为WMI
提供托管对象中的数据,并将来自WMI
的消息处理到托管对象。WMI
提供程序由DLL
文件和 托管对象格式 (MOF
) 文件组成,该文件定义提供程序返回数据的类并执行操作。 提供程序(如 WMI C++
应用程序)使用 适用于WMI
的COM API
.
WMI MOF
和DLL
文件位于%WINDIR%\System32\Wbem
中,包括WMI Command-Line
工具,例如Winmgmt.exe
和 Mofcomp.exe
。 提供程序类(如 Win32_LogicalDisk
)在MOF
文件中定义,然后在系统启动时编译到 WMI
存储库中。
总结来讲:WMI Providers
是整个WMI
体系的最底层,它对所有的”提供者(Provider)
”提供了封装和抽象。从文件的角度来说,WMI
提供者是由一个实现逻辑的DLL和承载着描述数据和操作的类的托管对象格式MOF(Managed Object Format)
文件组成。这个两个文件连同WMI
命令行工具都保存在%Windir%\System32\Wbem
目录下。
WMI
基础结构是Windows
操作系统组件,称为WMI服务 (winmgmt)
。WMI
基础结构有两个组件:WMI核心和 WMI 存储库
。(关于这块有个小疑问,微软的资料里边没有明说WMI
服务和WMI Core
的关系是什么,但是其它资料里边直接将二者等价了,看到有这样的描述方式:
WMI基础结构是Windows系统的系统组件。它包含两个模块:WMI Core的WMI Service(WMI服务)(Winmgmt) -
CIM Object Manager;WMI Repository(WMI存储库) - WMI namespaces(WMI命名空间)
组成)
WMI
存储库由WMI命名空间
组织。 WMI服务
在系统启动时创建一些命名空间,例如root\default、root\cimv2
和 root\subscription
,并预安装一组默认类定义,包括Win32
类、WMI
系统类等。 系统上找到的其余命名空间由操作系统或产品的其他部分的提供程序创建。
WMI服务
充当提供程序、管理应用程序和WMI存储库
之间的中介。只有有关对象的静态数据存储在存储库中,例如提供程序定义的类。当客户端请求数据时,WMI会从提供程序动态获取大部分数据。
WMI
使用者是与WMI
基础结构交互的管理应用程序或脚本。 管理应用程序可以通过调用适用于WMI
的COM API
或WMI脚本API
来查询、枚举数据、运行提供程序方法或订阅事件。 唯一可用于托管对象(例如磁盘驱动器或服务)的数据或操作是提供程序提供的数据或操作。
WMI
服务是操作系统组件,充当管理应用程序(management applications 或脚本)
和WMI
数据提供程序(WMI data providers)
之间的中介。 WMI
存储库是WMI
相关静态数据的存储区域。它是通过一个共享的服务进程SVCHOST
来实施工作的。当第一个管理应用向WMI
命名空间发起连接时,WMI
服务将会启动。当管理应用不再调用WMI
时,WMI
服务将会关闭或者进入低内存状态。WMI
服务和上层应用之间是通过COM
接口来实现的。
托管对象格式Managed Object Format (MOF)
是WMI
数据库中类和类实例的原始保存形式,是用于描述通用信息模型(CIM)
类的语言(CIM
用于描述如何表示真实托管对象的模型)。MOF
文件是一个文本文件,包含了指定的可被查询的事物的语句,如该事物的名称,复杂类的字段类型,对象组相关的权限。语言的结构类似于Java
,相当于受限的Java
接口声明。WMI提供程序(Provider)
实现新WMI
类的推荐方法是在MOF
文件中,该文件使用Mofcomp.exe
编译到WMI存储库(WMI Repository)
中。也可以使用WMI
的COM API
创建和操作CIM
类和实例。
WMI 提供程序(Provider)
通常是由提供的MOF
文件定义的,它定义了数据和事件类和提供数据的COM DLL
文件。
WMI
提供程序通常包括一个MOF
文件和一个DLL
文件,该文件定义了提供程序为其返回数据的数据和事件类,而DLL
文件则包含提供数据的代码。WMI
客户端脚本和应用程序(scripts and applications
)可以查询提供程序MOF
类(provider MOF classes
)的实例或订阅以接收事件通知。Windows 管理规范 (WMI)
提供了以下三种方法编译到WMI
存储库的托管对象格式(MOF)
文件:
使用Mofcomp.exe
使用 IMofCompiler 接口和$CompileFile方法
拖放到%SystemRoot%\System32\Wbem\MOF文件夹的 MOF 文件
MOF 是一种面向对象的语言,它由以下部分组成:
命名空间
类
属性
方法
限定符
实例
引用
注释
要在MOF
中声明一个CIM
命名空间,可以使用 #pragma namespace (\\computername\path)
指令。这个指令通常处于文件最开始的位置,同时这个声明语句的作用域包含整个文件.MOF
语言允许通过声明父命名空间并定义一个 __namespaceclass
的新实例来创建新的命名空间。示例代码如下:
#pragma namespace('\\\\.\\ROOT\\default')
instance of _namespace
{
Name=NewNS
}
WMI
的CIM
储存库实现了MOF
文件的事务缓存式的插入,以确保数据库不会被破坏。如果在插入的时候系统发生崩溃或停止,MOF
文件可以被注册为后续自动恢复。若要启用此功能,可以在MOF
文件顶部使用 #pragma autorecover
语句。这时,WMI
服务将会把MOF
文件的完整路径添加到MOF
文件自动恢复列表中,此列表存储在以下注册表项中:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\CIMOM\Autorecover MOFs
从另一个角度讲,一个WMI的管理组件可以是一个进程,一个注册表的键,一个安装的服务或一个文件信息,等等。WBEM
和CID
标准用来沟通确定实现者应该使用什么方法来query
(查询),populate
(填充),structure
(构造),transmit
(传输),perform actions on
(执行操作)和consume data
(处理数据)。(下边这一段转自利用WMI构建一个持久化的异步的无文件后门)
管理组件即WMI
的对象,是代表着高度结构化的操作系统数据的Class Instances
(类实例)。Microsoft
提供了非常多的WMI
对象来提供有关系统的信息,比如Win32_Process,Win32_Service,AntiVirusProduct
,Win32_StartupCommand
等。
Microsoft
提供了一些用来处理WMI数据和执行WMI
命令的方法。例如,PowerShell
提供给了我们一个非常简单的与PowerShell
交互的方式。
所有的WMI
对象可以通过一个叫WQL
的查询语言来查询,这种语言与SQL
相似,能够让我们精细地控制返回给用户的WMI
对象。
当用户请求一个WMI
对象时,WMI
服务(Winmgmt
)需要知道请求对象的数据填充方式。这个功能是通过WMI
Providers
(WMI提供者)来完成的。一个WMI
提供者就是一个在注册表中拥有相关GUID
的注册表键。WMI提供者在数据填充时,做了大量的动作,比如查询所有进程,枚举注册表键等。
当WMI
服务填充一个WMI
对象时,会有两种类实例:Dynamic Object
(动态对象)和Persistent Object
(永久化对象)。
动态对象是在进行查询时生成的,例如,Win32_Process
就是一个动态对象。永久化对象是存储在CIM Repository(CIM库)
中的,默认放在%SystemRoot%\System32\wbem\Repository\OBJECTS.DATA
中。
WMI
对象大部分的结构是通过Managed Object Format (MOF)
(管理对象格式)文件中描述的。MOF
文件使用类似C++
的语法来描述WMI
对象。
当WMI
提供者生成原始数据时,MOF
文件对提供了这些数据的构造结构。从防御者的角度看,值得注意的是,WMI
对象的定义可以不通过MOF
文件,攻击者可以通过在CIM
库中插入.Net
代码来定义。
Microsoft
提供了两种用于远程传输WMI数据的方法:DCOM和Windows Remote Management (WinRM)
。
一些WMI
对象包含一些可执行的方法/函数。例如,Win32_Process
类的静态函数Create
就经常被黑客用来做内网中的横向移动。WMI
还提供了一个Eventing System
(事件系统),用户可以注册在WMI
对象生成,修改或删除时执行的事件处理程序。
WMI
的命名空间创建了一个层次结构,有点类似于我们的目录文件结构。
root
-作为所有其他名字的占位符;root\default
-与注册表操作有关的类;root\security
-与系统安全有关的类;root\cimv2
-从CIM派生的类,代表我们最常用的工作环境。ROOT\CIMV2
作为默认的命名空间。在下面的注册表项中包含所有WMI
设置,也包括已定义的默认命名空间:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM
WMI提供了一种非常直观的语法用来查询WMI
对象的实例,类和命名空间,即WQL
。WQL
查询通常可以分为以下几类:
1.实例查询(Instance Queries
) - 用于查询 WMI
类的实例
2.事件查询(Event Queries
) - 用于一个 WMI
事件注册机制(event registration mechanism
),例如 WMI
对象的创建、 删除或修改
3.元查询(Meta Queries
) - 用于查询 WMI
类架构(WMI class schemas
)
WQL
就是WMI
中的查询语言。有如下特点:
每个WQL语句必须以 SELECT 开始;
SELECT 后添加需要查询的属性名;
FROM关键字;
要查询的类的名字;
另外,如果你想精确查询结果还可以加上WHERE条件从句。比如某个类有Enable属性,你可以在查询的时候加上WHERE ENABLE=true。
语法
SELECT properties[,properties] FROM class [where clause]
SELECT 必选项。代表WQL语句的开始,
properties 必选项。代表想查询的属性名字。可以是多个属性名,也可查询所有属性值,用*代替。
FROM 必选项。跟在properties的后面。
Class 必选项。代表想要查询的类的名称。
where clause 可选项。where 从句和相关条件语句,用来缩小查询范围。
Win + R -> wbemtest ( 系统自带的测试WMI语句的工具 )
root\cimv2 or ROOT\SecurityCenter
SELECT * FROM Win32_Product;
SELECT * FROM Win32_Process;
以下查询语句将返回Win32_Process
类的每个实例的所有属性的名称字段中包含字符串”Chrome
”的结果
SELECT [Class property name|*] FROM [CLASS NAME] <WHERE [CONSTRAINT]>
SELECT * FROM Win32_Process WHERE Name LIKE "%chrome%"
Win32_Process.Handle="5292"
Win32_Process.Handle="5364"
事件查询被用作一种消息机制来监听事件类的触发。通常用来在一个WMI对象实例创建/修改/删除的时候给用户发送一个消息。根据消息类型是intrinsic(系统自带的)还是extrinsic(第三方的)
,查询语句格式不同:
SELECT [Class property name | *] FROM [INTRINSIC CLASS NAME] WITHIN [POLLING INTERVAL] <WHERE [CONSTRAINT]>
SELECT [Class property name | *] FROM [EXTRINSIC CLASS NAME] <WHERE [CONSTRAINT]>
以下的查询语句将在用户登录的时候被执行:根据微软文档可知,交互式登录的LogonType值为 2。
SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERE TargetInstanceISA 'Win32_LogonSession' AND TargetInstance.LogonType=2
元查询用来查询WMI命名空间和类结构的信息。最常见的用法是用来列举WMI命名空间的类结构。元查询是实例查询的一个子集,但是与对象查询不同的是,我们查询的是类的实例的定义。格式如下:
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
。
微软和一些第三方软件开发者提供了许多能够与WMI交互的工具。下面是部分工具的一个不完全的列表:
powershell PowerShell是一个非常强大的脚本语言,其中包含很多能够与WMI进行交互的功能
wmic.exe wmic.exe是一款强大的可以与WMI交互的命令行工具.有很多且方便的WMI对象别名可使用,可以用来进行更 加复杂的查询。wmic.exe还能够执行WMI方法
wbemtest.exe wbemtest.ext是一款强大的图形化工具,是出于诊断工具来设计的。可以用来枚举对象实例,执行查询,注册事件,修改WMI对象和类,本地或远程执行
WMI Explorer WMI Explorer是Sapien公司开发的一款商业工具,用来查找WMI类,并且可以分层浏览WMI库。它不可以连接远程WMI库并执行查询。
CIM Studio CIM Studio微软提供的免费WMI交互工具,可以用它方便的浏览WMI库,查找WMI类
VBScript 微软提供的脚本语言,功能强大
JScript 微软提供的脚本语言,功能强大
.Net System.Management 类 System.Management 命名空间是 .NET 框架中的 WMI 命名空间
winrm.exe winrm.exe可以在本地或远程开启WinRM服务的机器上枚举WMI对象实例,调用方法,创建和删除对象实例
WMI的强大体现在通过远程操作的时候。目前,WMI
支持两种协议:DCOM
和WinRM
,使用这两种协议可以做任何事情,包括查询对象,注册事件和执行WMI
类的方法,等等。两种协议都对攻击者有利,因为防御者通常不会检查这两种协议的恶意流量。利用WMI所需的东西就是可用的有权限的用户凭证。在Linux
平台上的wmis-pth
工具中,只需要提供被攻击者的用户哈希即可。(之后可以看下这个工具)
DCOM
在引入WMI时,就被当做是默认处理协议。DCOM
通过135
端口建立TCP
连接,后续的数据交换则通过随机选择的TCP
端口传输。这个端口可以通过dcomcnfg.exe
进行配置和修改,其最终是改动如下注册表项:
HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\Internet - Ports (REG_MULTI_SZ)
所有的PowerShell
中内置的WMI
命令都使用DCOM
协议。
WinRM
目前已经被Windows
当作建议使用的协议。WinRM
基于Web Services-Management (WSMan)
规范,是一个SOAP-based
设备管理协议。另外,PowerShell Remoting
也是基于WinRM规范的,这使得我们能够通过PowerShell
在大规模Windows
企业环境中实现强大的远程管理功能。WinRM
同样支持WMI
,或者说CIM
的网络操作。
默认情况下,WinRM
服务开启并监听5985/tcp
端口,而且默认是加密的。还可以通过配置证书的方式在5986/tcp
端口实现HTTPS
支持。
https://learn.microsoft.com/zh-cn/windows/win32/wmisdk/wmi-architecture
https://learn.microsoft.com/zh-cn/windows/win32/wmisdk/managed-object-format–mof-
https://m0nst3r.me/pentest/
http://1sparrow.com/2019/12/10/Windows%20WMI%E6%8A%80%E6%9C%AF%E6%80%BB%E7%BB%93/