绕过 Windows 内核缓解措施:第 0 部分 - 深入探究 KASLR 泄漏限制 (Ko)
绕过 Windows 内核缓解措施:第 1 部分 - 概述
https://hackyboiz.github.io/2024/12/08/l0ch/bypassing-kernel-mitigation-part1/eo/
绕过 Windows 内核缓解措施:第 2 部分 - CVE-2024-21338
https://hackyboiz.github.io/2025/01/12/l0ch/bypassing-kernel-mitigation-part2/eo/
大家好,我是 L0ch!
最初,我计划写一篇关于 I/O Ring 漏洞的文章,但最终我深入研究了第 1 部分中的一个主题,并决定将其创建为一种支线故事。这就是为什么我把这部分编号为 0 😄
在本文中,我们将仔细研究 Windows 11 和 Windows Server 24H2 中引入的与 KASLR 相关的新缓解措施,并探索一种绕过它的新方法。
在我们开始之前,我强烈建议阅读Windows 内核缓解措施第 1 部分,尤其是有关 kASLR(内核地址空间布局随机化)的部分。
KASLR绕过
在 24H2 版本之前,可以NtQuerySystemInformation从以中等完整性级别运行的进程调用并ntoskrnl.exe一次性获取各种内核对象地址,包括映像基址。这些细节对于内核利用非常有用。
通过利用这些泄露的地址,攻击者可以定位中的小工具ntoskrnl.exe,篡改PreviousMode或等字段SeDebugPrivilege,等等。
24H2 中的 KASLR 缓解措施分析
要利用NtQuerySystemInformation,通常需要加载ntdll.dll,使用检索函数的地址GetProcAddress,然后调用它。实际实现遵循以下调用链:
(ntdll) NtQuerySystemInformation
(ntoskrnl) NtQuerySystemInformation(EX)
(ntoskrnl) ExpQuerySystemInformation
最终,该ExpQuerySystemInformation函数接收一个枚举值,该值决定执行哪个内部子例程来返回所请求的系统信息。
当检查这些子例程的 xref 时,许多处理内核相关信息的子例程都会调用该ExIsRestrictedCaller函数。
让我们来看一下ExIsRestrictedCaller。我们可以看到对的调用Feature_RestrictKernelAddressLeaks_private_IsEnabledDeviceUsageNoInline(),这是 24H2 中引入的新功能标志。如果此标志返回真,函数将SeDebugPrivilege通过调用来检查调用者是否拥有SeSinglePrivilegeCheck(SeDebugPrivilege, a1)。如果不存在特权,ExIsRestrictedCaller 则返回 true,表明调用者受到限制。
下面的代码片段显示了当枚举值为时调用的子例程SystemModuleInformation。如果ExIsRestrictedCaller返回 true,子程序将跳过调用ExQueryModuleInformation并返回错误。
因此,在中等完整性级别运行的进程将无法再通过泄漏内核地址SeDebugPrivilege来检索任何有意义的结果。NtQuerySystemInformation
此时,人们可能会想:在开发 Windows 的 LPE 漏洞时,我们是否需要找到额外的信息泄露?幸运的是,仍然存在可行的基于侧通道的旁路技术。
EntryBleed(CVE-2022-4543)和预取侧通道
在深入研究绕过方法之前,我们需要了解 Linux 中使用的 KPTI(内核页表隔离)保护和 EntryBleed 漏洞(CVE-2022-4543)。
KPTI 从用户模式页表中删除了大多数内核内存映射,仅保留异常/信号/系统调用处理所需的最少虚拟内核内存。这可以防止用户模式了解内核地址映射。
这是为了应对 2018 年披露的臭名昭著的 Meltdown 和 Specter 攻击而推出的。由于这些漏洞导致 KASLR 无效,因此操作系统供应商在页表级别采用了更严格的内存隔离。
有趣的事实:当时人们普遍担心 CPU 供应商会倒闭。而且...英特尔目前的发展轨迹看起来也不太好。 😅
启用 KPTI 后,只有最少的内核映射(例如,系统调用和中断)保留在用户地址空间中。
来源:https ://en.wikipedia.org/wiki/Kernel_page-table_isolation
EntryBleed 漏洞利用预取侧通道来识别驻留在用户模式页表中的系统调用处理程序地址,从而绕过 KPTI。
即使启用了 KPTI,内核的 entry_SYSCALL_64 地址(在 64 位系统调用转换期间使用)仍然保持映射。攻击利用这一事实来推断内核基地址。
x86_64 架构具有 TLB(转换后备缓冲区)来缓存最近的虚拟到物理地址转换,并支持将数据加载到 CPU 缓存中的预取指令。
当预取指令针对 TLB 中已经存在的地址时,它会跳过页面遍历并执行得更快。
执行时间差异取决于页面是否缓存
来源:https://gruss.cc/files/prefetch.pdf
可以按如下方式利用此时间差异:
1.反复调用系统调用以确保 entry_SYSCALL_64 其被缓存在 TLB 中。
2.在潜在内核地址范围内迭代执行预取指令:
-
0xffffffff80000000 - 0xffffffffc0000000
3.如果执行缓慢→地址可能未被缓存→继续扫描。
4.如果执行速度很快→缓存 entry_SYSCALL_64 命中→通过已知偏移量计算内核基数。
利用预取指令的时间差异来泄露内核地址
来源:https://gruss.cc/files/prefetch.pdf
在 24H2 中绕过 KASLR 缓解措施
EntryBleed 的基于预取的侧通道技术也适用于 Windows!
Windows 有一个类似的受 KPTI 启发的缓解措施,称为KVA(内核虚拟地址)阴影。这是微软对Meltdown/Spectre的回应,在软件层面实现内核/用户地址空间分离。但是,最近的 Windows 版本默认禁用 KVA Shadowing。
我们可以说它被禁用了,因为KPROCESS.UserDirectoryTableBase它包含一个空值,如果 KVAS 处于活动状态,该空值将指向一个有效地址。由于现代 CPU 通常不受 Meltdown/Spectre 的影响,微软很可能选择默认禁用 KVAS 以避免性能下降。
这意味着:内核地址仍然映射在用户模式页表中——因此,基于预取的泄漏是可行的。
让我们从exploits-forsale分享的PoC来分析侧通道程序。
来源:https ://github.com/exploits-forsale/prefetch-tool/blob/main/prefetch_tool/prefetch_asm.asm
-
橙色框:接受中的第一个预取目标地址rcx。
-
红色框:用于prefetchnta 指定非时间预取并将 prefetcht2 操作数加载到 L2 缓存中。测量执行时间以推断 TLB 缓存。
-
蓝色框:使用lfence和mfence进行指令序列化,以确保准确的时间。
-
执行内存中所有先前加载的指令并输入
-
强制指令执行顺序,删除优化
在我的测试环境(第 13 代英特尔 CPU)中,我能够ntoskrnl.exe在几秒钟内解析基地址。
然而,有两个主要警告:
-
该技术仅在最新的英特尔处理器上可靠。在 AMD CPU 上,结果不一致。
-
与可以泄露各种内核对象(例如 KTHREAD、池)地址的传统NtQuerySystemInformation方法不同,此方法仅泄露内核映像基础 - 使其功能相对不那么强大。
最终,24H2 中添加的权限限制NtQuerySystemInformation对内核利用策略产生了重大影响。
看起来,理解 CPU 手册现在是内核工作的先决条件……
结论
在这篇文章中,我们研究了应用于的缓解补丁NtQuerySystemInformation,这是 Windows 内核利用中长期存在的主要问题。我们还探讨了这如何导致需要新的 KASLR 绕过技术,特别是通过基于侧通道的内核信息泄漏。
在我看来,可用性NtQuerySystemInformation之前曾阻碍了对新型 KASLR 绕过技术的研究。随着新的 24H2 缓解措施的实施,我们最终可能会看到内核利用领域出现新一波创新方法。
下篇文章再见——我们将再次讨论 I/O Ring 漏洞!
参考
https://windows-internals.com/kaslr-leaks-restriction/
https://exploits.forsale/24h2-nt-exploit/
https://github.com/exploits-forsale/prefetch-tool
原文始发于微信公众号(Ots安全):[研究] 绕过 Windows 内核缓解措施:第 0 部分 - 深入研究 KASLR 泄漏限制
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论