Windows 10静默漏洞缓解机制:NtLoadKey3系统调用解析

本文深入分析了Windows 10中未公开的NtLoadKey3系统调用,探讨其如何通过令牌模拟机制缓解注册表加载过程中的符号链接攻击,并对比了历史版本NtLoadKey系列API的演进与设计缺陷。

静默漏洞缓解机制:专为1%人群设计

随着Windows 10发布节奏的加快,新功能被频繁引入,尤其是那些用于缓解设计缺陷API或易滥用行为的特性。但问题在于,这些缓解措施大多未文档化,或至少未通过常规Win32 API公开。这意味着微软可以高枕无忧地保护自身代码安全,却让第三方开发者陷入困境。

这些静默缓解机制的典型案例包括OBJ_IGNORE_IMPERSONATED_DEVICEMAP和OBJ_DONT_REPARSE这两个OBJECT_ATTRIBUTE标志——它们最终被文档化,部分原因是我提出了建议。当然,从修复我报告的漏洞到文档化足足花了5年时间,在微软的世界里这或许算高效。需要注意的是,这些标志仅在使用系统调用API时有效,而这些API本身仅部分文档化。

在探究Windows 10 2004(这命名实在令人困惑)时,可能受Alex Ionescu的提醒,我注意到微软引入了另一个仅通过未文档化系统调用可用的缓解机制,未通过任何公开Win32 API暴露。因此我认为有必要将其文档化。

更新(2020-04-23):据@FireF0X透露,该机制已回溯移植到所有受支持的操作系统。这意味着这是一个足够重要的安全修复,但却未告知任何人——真是"太棒了"。

NtLoadKey3系统调用

所述系统调用是NtLoadKey3。根据j00ru的系统调用表,它最初出现在Windows 10 2004中,但至少也存在于Windows 10 1909中。顾名思义(至少对我而言),该调用用于将注册表配置单元加载到挂载点。此功能随时间不断扩展:最初只有NtLoadKey,随后在XP中引入NtLoadKey2以添加某些标志,接着NtLoadKeyEx加入显式可信配置单元支持以缓解跨配置单元符号链接攻击(这全要归功于j00ru和Gynvael)。现在最终出现了NtLoadKey3。我不明白为何版本号从2跳到Ex又回到3——或许是微软的新计数系统。NtLoadKeyEx通过Win32 API RegLoadKey和RegLoadAppKey部分公开,但它们仅暴露了系统调用功能的子集。

缓解的漏洞类型

NtLoadKey3旨在缓解哪类漏洞?加载完整注册表配置单元(而非每用户应用程序配置单元)的一个问题行为是:调用方有效令牌需具备SeRestorePrivilege权限。该权限仅授予管理员,因此要成功调用API,就不能模拟低权限用户。然而,API在加载配置单元文件时也会创建文件,包括配置单元文件本身及其恢复日志文件。

注意:无需关注RegLoadKey文档中关于还需SeBackupPrivilege的声称——可能曾经需要,但现已不再。

加载系统配置单元(如HKLM\SOFTWARE)时这不是问题,因为这些配置单元存储在仅管理员可访问的位置(如c:\windows\system32\config)。但有时配置单元会从用户可访问位置(如用户配置文件或为Desktop Bridge支持)加载。在用户可访问位置,可通过符号链接技巧强制将日志文件写入任意位置,更糟的是主配置单元文件的安全描述符会被复制到日志文件,导致后续可访问。此类漏洞的典型案例是Desktop Bridge中的问题1492(以及1554,因为他们未正确修复 (╯°□°)╯︵ ┻━┻)。

NtLoadKey3的改进机制

NtLoadKey3通过引入额外参数来指定创建文件时需模拟的访问令牌,从而修复此问题。这样,SeRestorePrivilege检查可使用调用方的访问令牌,而任何"危险"操作将使用用户令牌。当然,他们本可通过添加新标志来实现,就像对SeImpersonatePrivilege和SeAssignPrimaryTokenPrivilege那样检查调用方主令牌的权限——但我又能知道什么呢…

适当使用此机制应能完全缓解系统调用的设计缺陷。例如,用户配置文件服务现在从用户配置文件加载配置单元时使用NtLoadKey3。如何自行调用?显然我找不到任何文档,即使在常规位置(如OLE32的私有符号)中也未见结构数据,因此我基于以下内容做了最佳猜测:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
NTSTATUS NtLoadKey3(
    POBJECT_ATTRIBUTES TargetKey,
    POBJECT_ATTRIBUTES SourceFile,
    ULONG Flags,
    HANDLE TrustKey,
    HANDLE Event,
    ACCESS_MASK DesiredAccess,
    PHANDLE KeyHandle,
    PIO_STATUS_BLOCK IoStatusBlock
);

注意:来自NtLoadKeyEx的TrustKey和Event句柄也被折叠到句柄值列表中。或许有人不确定未来是否需扩展系统调用——是选择NtLoadKey4还是NtLoadKeyExEx——因此通过使系统调用更灵活来避免决策。此外,最后一个参数(在NtLoadKeyEx中也存在)似乎未使用,或者我无法追踪其引用时机。Process Hacker的头文件声称它用于IO_STATUS_BLOCK指针,但我未见证据支持此说法。

结论与呼吁

在这个崭新、共享与关怀的微软时代,若能更频繁地共享与关怀——尤其是对保护第三方应用安全至关重要的功能——那将非常棒。坦白说,我认为他们更专注于将Wayland引入WSL2或将新API集强塞给开发者,而非文档化此类内容。

发布信息
作者:tiraniddo
时间:16:59
标签:未文档化, Windows

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