引入Windows通知设施(WNF)的代码完整性 - Trail of Bits博客
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位数字,由以下部分组成:
- 版本
- 生命周期:
- 众所周知的,系统中预定义的
- 永久的,在启动会话间持久存在于注册表中
- 持久的,在内存中持久存在,但不跨启动会话
- 临时的,仅存在于进程上下文中,进程终止时消失
- 范围:系统、会话、用户、进程或物理机器
- 永久数据位
- 唯一序列号
这些属性使用以下位布局组合到状态名称中:
|
|
直到最近,这种机制几乎专门用于硬件组件,如电池、麦克风、摄像头和蓝牙,对防御工程师的兴趣很小。但随着内核代码完整性管理器最近添加了几个新的状态名称,这种情况开始发生变化,该管理器现在使用WNF通知系统有关可能对安全工具有用的有趣代码完整性事件。
虽然仍然未公开记录且不建议一般使用,但可能是时候让防御者开始进一步研究WNF及其潜在好处了。从Windows 10开始,WNF现在提供了几个新增的众所周知的状态名称,由内核代码完整性管理器(CI.dll)通知。该组件负责所有内核哈希、签名检查和代码完整性策略,这对所有安全产品来说都是丰富的信息。
我们如何找出这些名称?要转储机器上所有众所周知的状态名称,您需要安装Microsoft SDK,然后运行WnfNameDumper来检索perf_nt_c.dll中定义的所有WNF名称,并将其人类可读的名称、ID和描述转储到文件中,如下所示:
|
|
在Windows版本22H2中,Windows SDK包含超过1,400个众所周知的状态名称。其中许多名称可能具有揭示性,但现在我们将专注于WNF_CI(代码完整性)名称:
|
|
在这个版本中,我们可以看到五个带有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访问:
|
|
我们可以从代码完整性管理器获取一些信息,这可能对EDR产品有用。其中一些信息也可以在Microsoft-Windows-CodeIntegrity ETW(Windows事件跟踪)通道中找到,以及其他有趣的事件(值得单独写一篇文章)。尽管如此,这些WNF名称中的一些数据无法在任何其他数据源中找到。
现在,如果我们将SDK版本更新到预览版(撰写本文时为25336),我们可以看到一些尚未发布到常规版本的其他WNF状态名称:
|
|
在这里,我们看到两个新的状态名称,添加了关于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演讲中详细介绍了它。他们后来发布了一篇博客文章和一系列有用的脚本。
如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News