WMI 攻击手法研究 – 和 windows 注册表交互 (第三部分)
- 爱谁谁
- 2025-08-29
- 热度
释放双眼,带上耳机,听听看~!
文章目录[隐藏]
1 Windows 注册表是什么2 注册表 & WMI2.1 查询注册表2.2 修改注册表3 工具4 结论这是 WMI 攻击手法研究系列第三篇,本文将重点介绍与 Windows 注册表的交互。在开始之前需要了解的一件事情是:MITRE ATT&CK 对查询注册表 (Query Registry) 归类于 T1012 以及它的修改 (Modify Registry) 归类于 T1112。
1 Windows 注册表是什么简单来说,注册表是一个存储操作系统配置设置的数据库:内核、设备驱动程序、服务、SAM、用户界面和第三方应用程序都使用注册表,这使得注册表成为攻击者非常关注的一个点。
注册表由称为 hives 的部分组成,例如
HKEY_LOCAL_MACHINE、
HKEY_CURRENT_USER等。检查
regedit.exe中的注册表后,它们的排列方式似乎与文件系统类似,每个 hive 都有许多键,键可以有多个子键,键或子键用来存储值。注册表项由名称和值组成,成一对。2 注册表 & WMI
WMI 提供了一个名为
StdRegProv的类,用于与 Windows 注册表交互。有了这个,我们可以做很多事情,包括检索、创建、删除和修改键和值。这里需要注意的重要一点是,我们需要使用
root\DEFAULT命名空间来处理注册表。
让我们开始探索吧:
代码语言:javascript代码运行次数:0运行复制Get-WmiObject -Namespace root\default -Class StdRegProv -List | select -ExpandProperty methods
在上图中,我们可以看到一些与注册表交互的方法,比如
CreateKey、
DeleteKey、
EnumKey、
EnumValues,
DeleteValues等,这很有趣。
进入之前需要了解的两件重要事情:首先,WMI 使用常量数值来标识注册表中的不同配置单元。下表列出了访问注册表配置单元的常量:
Variable
Value
Hive
$HKCR
2147483648
HKEY_CLASSES_ROOT
$HKCU
2147483649
HKEY_CURRENT_USER
$HKLM
2147483650
HKEY_LOCAL_MACHINE
$HKUS
2147483651
HKEY_USERS
$HKCC
2147483653
HKEY_CURRENT_CONFIG
其次,注册表具有不同的数据类型,并且可以使用 WMI 中的特定方法访问每种数据类型。下表将常见数据类型与它们的方法的对应关系:
Method
Data Type
Type Value
Function
GetStringValue
REG_SZ
1
返回一个字符串
GetExpandedStringValue
REG_EXPAND_SZ
2
返回对 env 变量的扩展引用
GetBinaryValue
REG_BINARY
3
返回字节数组
GetDWORDValue
REG_DWORD
4
返回一个 32 位的数值
GetMultiStringValue
REG_MULTI_SZ
7
返回多个字符串值
GetQWORDValue
REG_QWORD
11
返回一个 64 位的数值
2.1 查询注册表枚举键
现在我们知道了常量,让我们尝试枚举一个众所周知的注册表路径
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion下的可用子项。把我们目前所知道的放在一起,可以使用以下这个命令来获取注册表项下的所有键:代码语言:javascript代码运行次数:0运行复制
Get-WmiObject -Namespace root\default -Class StdRegProv -List | select -ExpandProperty methods
注意:对于上层层次的注册表路径也可以这样做。如果不知道绝对路径,可以通过简单地替换上面命令中的路径来浏览注册表。例如,如果将上述命令中的路径
software\microsoft\
windows
nt\currentversion\schedule替换为
software,则输出将列出
HKEY_LOCAL_MACHINE\Software下的所有子项。这在探索注册表中的未知嵌套项时很有帮助。
枚举值
现在我们知道如何列出注册表项下可用的键,让我们枚举
Drivers32键下的值:代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name enumvalues @(2147483650, "software\microsoft\windows nt\currentversion\drivers32")
正如我们所见,输出包含
sNames下的子项名称和
Types属性下的关联数据类型。当然也可以使用 Powershell 的
select -ExpandProperty选项参数来扩展输出中返回的属性值。
读取值
现在让我们尝试读取子键的值,对于示例,将读取
Drivers32子键 (定义应用程序的 Windows NT DLL) 的值。过去曾观察到几个恶意软件变种使用此子键 (请参阅 Riern Trojan Family)。
以下命令读取
Drivers32项下子项
aux和
midi的值。请注意,传递给 cmdlet 的方法名称 (通过 -Name 选项参数) 将因注册表数据类型而异 (请参阅上面的数据类型表)。代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name GetStringValue @(2147483650, "software\microsoft\windows nt\currentversion\drivers32", "aux")代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name GetStringValue @(2147483650, "software\microsoft\windows nt\currentversion\drivers32", "midi") | select svalue
现在已经知道如何使用 WMI 从注册表中读取键值对,然而,到目前为止,这些并不需要管理权限 —— 创建、删除和更新键和值可能需要提升权限。
让我们尝试创建新的键和子键,但在此之前,我们需要检查是否可以访问特定的注册表项,还有一个常量定义了对键的访问级别,下表总结了具有关联常量的权限:
Method
Value
Function
KEY_QUERY_VALUE
1
查询注册表键的值
KEY_SET_VALUE
2
创建、删除或设置注册表值
KEY_CREATE_SUB_KEY
4
创建注册表项的子项
KEY_ENUMERATE_SUB_KEYS
8
枚举注册表项的子项
KEY_NOTIFY
16
注册表项或注册表项子项的更改通知
KEY_CREATE
32
创建注册表项
DELETE
65536
删除注册表项
READ_CONTROL
131072
结合 STANDARD_RIGHTS_READ、KEY_QUERY_VALUE、KEY_ENUMERATE_SUB_KEYS 和 KEY_NOTIFY 值
WRITE_DAC
262144
修改对象安全描述符中的 DACL
WRITE_OWNER
524288
更改对象安全描述符中的所有者
检查键的权限
对于我们的示例,首先选择配置单元
HKEY_CURRENT_USER下的
Run键,然后选择
HKEY_LOCAL_MACHINE,以下展示如何做:代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CheckAccess @(2147483649, "software\microsoft\windows\currentversion\run", 32)代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CheckAccess @(2147483650, "software\microsoft\windows\currentversion\run", 32)
上图中的
bGranted属性告诉我们是否可以访问注册表中的特定项目。从上面的例子中,可以清楚地看到用户当前可以访问
HKEY_CURRENT_USER下的
Run键,而不是
HKEY_LOCAL_MACHINE。
创建注册表项
现在我们知道对在
HKEY_CURRENT_USER下运行的注册表项有写访问权限,将计算器应用程序添加到注册表项中。这将导致每次系统启动时都会弹出一个计算器,这是恶意软件中常见的一种获得持久性的技术。代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name SetStringValue @(2147483649, "software\microsoft\windows\currentversion\run", "C:\Windows\System32\calc.exe", "Calculator")
Boom,我们的计算器应用程序实现了持久化。
注意:注册表项下的现有子项也可以使用上述方法进行更新。
删除注册表项
删除注册表子项不需要的值:
代码语言:javascript代码运行次数:0运行复制Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteValue @(2147483649, "software\microsoft\windows\currentversion\run", "Calculator")
创建键
在少数情况下,我们可能需要在主树层次结构下创建键。假设要在
HKEY_LOCAL_MACHINE\Software\OpenSSH注册表项下创建一个名为
CustomAgent的新键,这个过程看起来非常简单:代码语言:javascript代码运行次数:0运行复制
Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteValue @(2147483649, "software\microsoft\windows\currentversion\run", "Calculator")
删除键
删除键同样也很简单:
代码语言:javascript代码运行次数:0运行复制Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteKey @(2147483650, "software\openssh\CustomAgent")
在收集有用数据时,注册表是攻击者的宝库。此外,注册表还可用于存储 Payload,作为理想的无文件攻击和持久性机制。在本系列的后面部分,我们将了解如何仅使用 WMI 和注册表来创建整个 C2 基础设施。现在已经完成了基础知识,在下一篇文章中,将从 WMI 的基本侦察开始。
敬请期待,我的朋友!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。