|
这是 WMI 攻击手法研究系列第三篇,本文将重点介绍与 Windows 注册表的交互。在开始之前需要了解的一件事情是:MITRE ATT&CK 对查询注册表 (Query Registry) 归类于 T1012 以及它的修改 (Modify Registry) 归类于 T1112。
一、Windows 注册表是什么
简单来说,注册表是一个存储操作系统配置设置的数据库:内核、设备驱动程序、服务、SAM、用户界面和第三方应用程序都使用注册表,这使得注册表成为攻击者非常关注的一个点。
注册表由称为 hives 的部分组成,例如 HKEY_LOCAL_MACHINE、HKEY_CURRENT_USER 等。检查 regedit.exe 中的注册表后,它们的排列方式似乎与文件系统类似,每个 hive 都有许多键,键可以有多个子键,键或子键用来存储值。注册表项由名称和值组成,成一对。
二、注册表 & WMI
WMI 提供了一个名为 StdRegProv 的类,用于与 Windows 注册表交互。有了这个,我们可以做很多事情,包括检索、创建、删除和修改键和值。这里需要注意的重要一点是,我们需要使用 root\DEFAULT 命名空间来处理注册表。
让我们开始探索吧:
- 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 查询注册表
2.1.1 枚举键
现在我们知道了常量,让我们尝试枚举一个众所周知的注册表路径 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion 下的可用子项。把我们目前所知道的放在一起,可以使用以下这个命令来获取注册表项下的所有键:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name EnumKey @(2147483650, "software\microsoft\windows nt\currentversion") | select -ExpandProperty snames
复制代码
注意:对于上层层次的注册表路径也可以这样做。如果不知道绝对路径,可以通过简单地替换上面命令中的路径来浏览注册表。例如,如果将上述命令中的路径 software\microsoft\windows nt\currentversion\schedule 替换为 software,则输出将列出 HKEY_LOCAL_MACHINE\Software 下的所有子项。这在探索注册表中的未知嵌套项时很有帮助。
2.1.2 枚举值
现在我们知道如何列出注册表项下可用的键,让我们枚举 Drivers32 键下的值:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name enumvalues @(2147483650, "software\microsoft\windows nt\currentversion\drivers32")
复制代码
正如我们所见,输出包含 sNames 下的子项名称和 Types 属性下的关联数据类型。当然也可以使用 Powershell 的 select -ExpandProperty 选项参数来扩展输出中返回的属性值。
2.1.3 读取值
现在让我们尝试读取子键的值,对于示例,将读取 Drivers32 子键 (定义应用程序的 Windows NT DLL) 的值。过去曾观察到几个恶意软件变种使用此子键 (请参阅 Riern Trojan Family)。
以下命令读取 Drivers32 项下子项 aux 和 midi 的值。请注意,传递给 cmdlet 的方法名称 (通过 -Name 选项参数) 将因注册表数据类型而异 (请参阅上面的数据类型表)。
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name GetStringValue @(2147483650, "software\microsoft\windows nt\currentversion\drivers32", "aux")
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name GetStringValue @(2147483650, "software\microsoft\windows nt\currentversion\drivers32", "midi") | select svalue
复制代码
提示:这是一个很好的注册表中有趣位置的 备忘单,对攻击者很有用。
2.2 修改注册表
现在已经知道如何使用 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 | 更改对象安全描述符中的所有者 |
2.2.1 检查键的权限
对于我们的示例,首先选择配置单元 HKEY_CURRENT_USER 下的 Run 键,然后选择 HKEY_LOCAL_MACHINE,以下展示如何做:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CheckAccess @(2147483649, "software\microsoft\windows\currentversion\run", 32)
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CheckAccess @(2147483650, "software\microsoft\windows\currentversion\run", 32)
复制代码
上图中的 bGranted 属性告诉我们是否可以访问注册表中的特定项目。从上面的例子中,可以清楚地看到用户当前可以访问 HKEY_CURRENT_USER 下的 Run 键,而不是 HKEY_LOCAL_MACHINE。
2.2.2 创建注册表项
现在我们知道对在 HKEY_CURRENT_USER 下运行的注册表项有写访问权限,将计算器应用程序添加到注册表项中。这将导致每次系统启动时都会弹出一个计算器,这是恶意软件中常见的一种获得持久性的技术。
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name SetStringValue @(2147483649, "software\microsoft\windows\currentversion\run", "C:\Windows\System32\calc.exe", "Calculator")
复制代码
Boom,我们的计算器应用程序实现了持久化。
注意:注册表项下的现有子项也可以使用上述方法进行更新。
2.2.3 删除注册表项
删除注册表子项不需要的值:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteValue @(2147483649, "software\microsoft\windows\currentversion\run", "Calculator")
复制代码
2.2.4 创建键
在少数情况下,我们可能需要在主树层次结构下创建键。假设要在 HKEY_LOCAL_MACHINE\Software\OpenSSH 注册表项下创建一个名为 CustomAgent 的新键,这个过程看起来非常简单:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name CreateKey @(2147483650, "software\openssh\CustomAgent")
复制代码
2.2.5 删除键
删除键同样也很简单:
- Invoke-WmiMethod -Namespace root\default -Class stdregprov -Name DeleteKey @(2147483650, "software\openssh\CustomAgent")
复制代码
2.3 工具
三、结论
在收集有用数据时,注册表是攻击者的宝库。此外,注册表还可用于存储 Payload,作为理想的无文件攻击和持久性机制。在本系列的后面部分,我们将了解如何仅使用 WMI 和注册表来创建整个 C2 基础设施。现在已经完成了基础知识,在下一篇文章中,将从 WMI 的基本侦察开始。
敬请期待,我的朋友 \o/
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|