深入解析 Windows 通知设施(WNF)代码完整性机制

本文详细介绍了Windows未公开的通知机制WNF及其在代码完整性管理中的应用,包括状态名称解析、LSASS保护机制及EDR工具的潜在利用方式,为安全研究人员提供新的防御视角。

介绍 Windows 通知设施(WNF)的代码完整性

WNF(Windows 通知设施)是一种未公开的通知机制,允许进程内部、进程之间或用户模式进程与内核驱动程序之间的通信。与其他通知机制(如 ETW(Windows 事件追踪)和 ALPC(高级本地过程调用)类似,WNF 通信通过不同的“通道”进行,每个通道代表一个唯一的提供者或信息类别。

攻击工程师已经发现了 WNF 的多种用途。Alex Ionescu 和 Gabrielle Viala 报告了信息泄露和拒绝服务漏洞,这些漏洞已被微软修复;@modexpblog 演示了通过 WNF 名称进行代码注入,这在几乎所有 EDR 产品中均未被检测到;NCC Group 的 Alex Plaskett 展示了攻击者如何利用 WNF 分配来喷洒内核池。

Windows 组件广泛使用 WNF 来发送或接收有关软件和硬件状态的信息。第三方应用程序可以以相同的方式使用它来了解系统状态、向 Windows 进程或驱动程序发送消息,或作为进程或驱动程序之间的内部通信通道(尽管 WNF 未公开,因此根本不建议第三方使用)。

读取和解释 WNF 状态名称

在 WNF 世界中,这些先前提到的“通道”称为状态名称。WNF 状态名称是 64 位数字,由以下部分组成:

  • 版本
  • 生命周期:
    • 已知,在系统中预定义
    • 永久,在注册表中跨启动会话持久存在
    • 持久,在内存中持久存在,但不跨启动会话
    • 临时,仅存在于进程上下文中,进程终止时消失
  • 范围:系统、会话、用户、进程或物理机器
  • 永久数据位
  • 唯一序列号

这些属性使用以下位布局组合到状态名称中:

1
2
3
4
5
6
7
typedef struct _WNF_STATE_NAME_INTERNAL {
    ULONG64 Version : 4;
    ULONG64 NameLifetime : 2;
    ULONG64 DataScope : 4;
    ULONG64 PermanentData : 1;
    ULONG64 Unique : 53;
} WNF_STATE_NAME_INTERNAL, * PWNF_STATE_NAME_INTERNAL;

直到最近,这种机制几乎专用于硬件组件,如电池、麦克风、摄像头和蓝牙,对防御工程师的兴趣很小。但随着内核代码完整性管理器最近添加了几个新的状态名称,这种情况开始发生变化,该管理器现在使用 WNF 来通知系统有关可能对安全工具有用的有趣代码完整性事件。

虽然仍然未公开且不推荐一般使用,但可能是时候让防御者开始进一步研究 WNF 及其潜在好处了。从 Windows 10 开始,WNF 现在提供了几个新增的已知状态名称,由内核代码完整性管理器(CI.dll)通知。该组件负责所有内核哈希、签名检查和代码完整性策略,这对所有安全产品来说都是丰富的信息。

我们如何找出这些名称?要转储机器上所有已知状态名称,您需要安装 Microsoft SDK,然后运行 WnfNameDumper 来检索 perf_nt_c.dll 中定义的所有 WNF 名称,并将其人类可读的名称、ID 和描述转储到文件中,如下所示:

1
2
3
4
{"WNF_CELL_UTK_PROACTIVE_CMD", 0xd8a0b2ea3bcf075},        // UICC toolkit proactive command notification for all slots. SDDL comes from ID_CAP_CELL_WNF_PII        // and UtkService in %SDXROOT%\src\net\Cellcore\packages\Cellcore\Cellcore.pkg.xml
{"WNF_CELL_UTK_SETUP_MENU_SLOT0", 0xd8a0b2ea3bce875},        // UICC toolkit setup menu notification for slot 0. SDDL comes from ID_CAP_CELL_WNF_PII        // and UtkService in %SDXROOT%\src\net\Cellcore\packages\Cellcore\Cellcore.pkg.xml
{"WNF_CELL_UTK_SETUP_MENU_SLOT1", 0xd8a0b2ea3bdd075},        // UICC toolkit setup menu notification for slot 1. SDDL comes from ID_CAP_CELL_WNF_PII        // and UtkService in %SDXROOT%\src\net\Cellcore\packages\Cellcore\Cellcore.pkg.xml
etc., etc., etc

在 Windows 版本 22H2 中,Windows SDK 包含略超过 1,400 个已知状态名称。其中许多名称可能具有揭示性,但现在我们将重点关注 WNF_CI(代码完整性)名称:

1
2
3
4
5
{"WNF_CI_APPLOCKERFLTR_START_REQUESTED", 0x41c6072ea3bc2875},        // This event signals that AppLockerFltr service should start.
{"WNF_CI_BLOCKED_DRIVER", 0x41c6072ea3bc1875},        // This event signals that an image has been blocked from loading by PNP
{"WNF_CI_CODEINTEGRITY_MODE_CHANGE", 0x41c6072ea3bc2075},        // This event signals that change of CodeIntegrity enforcement mode has occurred.
{"WNF_CI_HVCI_IMAGE_INCOMPATIBLE", 0x41c6072ea3bc1075},        // This event signals that an image has been blocked from loading as it is incompatible with HVCI.
{"WNF_CI_SMODE_CHANGE", 0x41c6072ea3bc0875},        // This event signals that change of S mode has occurred.

在这个版本中,我们可以看到五个带有 WNF_CI 前缀的状态名称,全部由代码完整性管理器生成,每个都有一个有用的描述,告诉我们它的用途。与大多数其他 WNF 名称不同,这里我们看到一些可能对防御工程师有帮助的事件:

  • WNF_CI_APPLOCKERFLTR_START_REQUESTED – 表示应启动 AppLockerFltr 服务
  • WNF_CI_BLOCKED_DRIVER – 表示驱动程序因在阻止列表中被发现而被 HVCI(虚拟机保护代码完整性)阻止加载
  • WNF_CI_CODEINTEGRITY_MODE_CHANGE – 表示代码完整性执行模式已发生变化
  • WNF_CI_HVCI_IMAGE_INCOMPATIBLE – 表示映像因与 HVCI 不兼容而被阻止加载,很可能是因为它具有既可写又可执行的区域,或从可执行非分页池分配内存
  • WNF_CI_SMODE_CHANGE – 表示 S 模式已发生变化

通常,传递到 WNF 状态名称的缓冲区是一个谜,其内容必须进行逆向工程。但在这种情况下,微软通过公共 Microsoft 符号服务器公开了传递到其中一个状态名称的数据,可通过 symchk.exe 和 symsrv.dll 访问:

1
2
3
4
5
6
7
typedef struct _WNF_CI_BLOCKED_DRIVER_CONTEXT
{
  /* 0x0000 */ struct _GUID Guid;
  /* 0x0010 */ unsigned long Policy;
  /* 0x0014 */ unsigned short ImagePathLength;
  /* 0x0016 */ wchar_t ImagePath[1];
} WNF_CI_BLOCKED_DRIVER_CONTEXT, *PWNF_CI_BLOCKED_DRIVER_CONTEXT;

我们可以从代码完整性管理器获取一些信息,这可能对 EDR 产品有用。其中一些信息也可以在 Microsoft-Windows-CodeIntegrity ETW(Windows 事件追踪)通道中找到,以及其他有趣的事件(值得单独写一篇文章)。尽管如此,这些 WNF 名称中的一些数据无法在任何其他数据源中找到。

现在,如果我们将 SDK 版本更新到预览版(在撰写本文时为 25336),我们可以看到一些尚未发布到常规版本的其他 WNF 状态名称:

1
2
3
4
5
6
7
{"WNF_CI_APPLOCKERFLTR_START_REQUESTED", 0x41c6072ea3bc2875},        // This event signals that AppLockerFltr service should start.
{"WNF_CI_BLOCKED_DRIVER", 0x41c6072ea3bc1875},        // This event signals that an image has been blocked from loading by PNP
{"WNF_CI_CODEINTEGRITY_MODE_CHANGE", 0x41c6072ea3bc2075},        // This event signals that change of CodeIntegrity enforcement mode has occurred.
{"WNF_CI_HVCI_IMAGE_INCOMPATIBLE", 0x41c6072ea3bc1075},        // This event signals that an image has been blocked from loading as it is incompatible with HVCI.
{"WNF_CI_LSAPPL_DLL_LOAD_FAILURE", 0x41c6072ea3bc3075},        // This event signals that a dll has been blocked from loading as it is incompatible with LSA running        // as a protected process.
{"WNF_CI_LSAPPL_DLL_LOAD_FAILURE_AUDIT_MODE", 0x41c6072ea3bc3875},        // This event signals that an unsigned dll load was noticed during LSA PPL audit mode.
{"WNF_CI_SMODE_CHANGE", 0x41c6072ea3bc0875},        // This event signals that change of S mode has occurred.

在这里,我们看到两个新的状态名称,添加了有关与 PPL 不兼容的 DLL 加载到本地安全机构子系统服务(LSASS)的信息。LSASS,操作系统身份验证管理器,作为 PPL(受保护进程轻量级)运行。这确保了进程不被篡改,并且仅运行使用正确签名级别签名的代码。

使用 WNF 调查 LSASS 保护

微软一直试图让 LSASS 作为 PPL 运行。但由于与需要完全访问 LSASS 的产品(包括注入不同插件)存在兼容性问题,它无法完全启用。然而,他们试图尽可能保护 LSASS 免受像 Mimikatz 这样的凭据窃取器的侵害,同时仍允许用户选择将 LSASS 恢复为常规进程。

自 Windows 8.1 以来,有一个选项可以在审计模式下将 LSASS 作为 PPL 运行。这意味着系统仍将其视为正常进程,但会记录任何在作为 PPL 运行时会被阻止的操作。在 Windows 11 中,它默认作为常规 PPL 运行,通过注册表和安全中心(在预览版中)暴露了一个在审计模式下运行的选项。

这就是我们的两个新状态名称的用武之地:

  • WNF_CI_LSAPPL_DLL_LOAD_FAILURE 在 LSASS 作为常规 PPL 运行时被通知,并且未根据 PPL 要求签名的 DLL 被阻止加载到进程中。
  • WNF_CI_LSAPPL_DLL_LOAD_FAILURE_AUDIT_MODE 在 LSASS 在审计模式下作为 PPL 运行时被通知,并加载了一个在作为正常 PPL 运行时会被阻止的 DLL。

端点检测与响应(EDR)工具可以通过文档化的内核回调警报所有 DLL 加载。映像加载通知例程确实包括缓存的签名信息在 IMAGE_INFO 中的 ImageSignatureLevel 和 ImageSignatureType 字段中,然而这些信息可能并不总是可用,并且回调不会通知被阻止的 DLL 加载。被阻止的 DLL 加载很有趣,因为它们可能表明 exploitation 尝试(或组织试图将其 2003 年编写的插件加载到 LSASS 中)。

因此,虽然这些新状态名称都不包含对 EDR 特别感兴趣的信息,但它们确实有一些安全产品可能觉得有用的有趣数据,并且至少可以增加一些可见性或节省 EDR 的一些工作。

当然,已经有一些用户使用这些 WNF_CI 状态名称:Windows Defender 命令行工具 MpCmdRun.exe。MpSvc.dll,加载到 MpCmdRun.exe 中的 DLL 之一,订阅了两个 WNF 状态名称:WNF_CI_CODEINTEGRITY_MODE_CHANGE 和 WNF_CI_SMODE_CHANGE。每当它们被通知时,DLL 会查询它们以获取新值并相应地更新其内部配置。

系统的其他部分也订阅了这些状态名称。我使用 WinDbg 命令从自己的系统中提取了这个列表:

  • DcomLaunch 服务注册到 WNF_CI_SMODE_CHANGE、WNF_CI_BLOCKED_DRIVER 和 WNF_CI_APPLOCKERFLTR_START_REQUESTED
  • Utcsvc 服务(通过 utcsvc.dll)注册到 WNF_CI_SMODE_CHANGE
  • SecurityHealthService.exe 注册到 WNF_CI_SMODE_CHANGE
  • Msteams.exe 注册到 WNF_CI_SMODE_CHANGE
  • PcaSvc 服务(通过 PcaSvc.dll)注册到 WNF_CI_HVCI_IMAGE_INCOMPATIBLE 和 WNF_CI_BLOCKED_DRIVER – 这是负责在您最喜欢的易受攻击驱动程序在启用 HVCI 的系统上无法加载时显示弹出消息的服务。

目前,没有进程订阅新的 LSA(本地安全机构)状态名称(WNF_CI_LSAPPL_DLL_LOAD_FAILURE 和 WNF_CI_LSAPPL_DLL_LOAD_FAILURE_AUDIT_MODE),但由于这些仍处于预览阶段,这并不令人惊讶,我相信将来会看到一些订阅。

探索新 WNF 信息的可能性

Windows 通过 WNF 中新获得的信息赋予了安全爱好者在攻击和防御两方面的能力。通过扩展历史范围并向 WNF 添加状态名称,研究人员可以更透明地了解事物的运作方式。随着时间的推移,您可能会看到安全研究人员将这些信息与其他事件和进程相关联,以展示新颖的安全研究!

在这里,我们快速介绍了 WNF 及其新功能,以及一个简单的示例,说明如何使用它来调查 LSASS。如果您对 WNF 内部及其攻击能力的更多细节感兴趣,Alex Ionescu 和 Gabrielle Viala 在 BlackHat 2018 演讲中详细介绍了它。他们后来发布了一篇博客文章和一系列有用的脚本。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计