Inside Microsoft’s plan to kill PPLFault — Elastic Security Labs

渗透技巧 7个月前 admin
190 0 0

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

On September 1, 2023, Microsoft released a new build of Windows Insider Canary, version 25941. Insider builds are pre-release versions of Windows that include experimental features that may or may not ever reach General Availability (GA). Build 25941 includes improvements to the Code Integrity (CI) subsystem that mitigate a long-standing issue that enables attackers to load unsigned code into Protected Process Light (PPL) processes.
2023 年 9 月 1 日,Microsoft发布了 Windows 预览体验成员金丝雀的新版本,版本 25941。预览体验成员版本是 Windows 的预发布版本,其中包含可能达到也可能永远不会正式发布 (GA) 的实验性功能。内部版本 25941 包括对代码完整性 (CI) 子系统的改进,这些改进缓解了一个长期存在的问题,该问题使攻击者能够将未签名的代码加载到受保护的进程轻量级 (PPL) 进程中。

The PPL mechanism was introduced in Windows 8.1, enabling specially-signed programs to run in such a way that they are protected from tampering and termination, even by administrative processes. The goal was to keep malware from running amok — tampering with critical system processes and terminating anti-malware applications. There is a hierarchy of PPL “levels,” with higher-privilege ones immune from tampering by lower-privilege ones, but not vice-versa. Most PPL processes are managed by Microsoft but members of the Microsoft Virus Initiative are allowed to run their products at the less-trusted Anti-Malware PPL level.
PPL 机制是在 Windows 8.1 中引入的,它使经过特殊签名的程序能够以这样一种方式运行,即使通过管理进程,它们也不会被篡改和终止。目标是防止恶意软件肆无忌惮地运行 – 篡改关键系统进程并终止反恶意软件应用程序。PPL“级别”有一个层次结构,较高特权的级别不受较低特权的篡改,但反之则不然。大多数 PPL 进程由 Microsoft 管理,但允许Microsoft病毒计划的成员在不太受信任的反恶意软件 PPL 级别运行其产品。

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

A few core Windows components run at the highest level of PPL, called Windows Trusted Computing Base (WinTcb-Light). Because of the protection afforded to these components and their narrow scope of function, they are considered more trusted than most user mode code. Most of these processes (such as csrss.exe) and their complex kernel-mode counterparts (such as win32k.sys) were written decades ago under different assumptions when the kernel-user boundary was even weaker than it is today. Rather than rewrite all these components, Microsoft made these user mode processes WinTcb-Light, mitigating tampering and injection attacks. Alex Ionescu stated it clearly in 2013:
一些核心Windows组件在PPL的最高级别运行,称为Windows可信计算基础(WinTcb-Light)。由于为这些组件提供的保护及其狭窄的功能范围,它们被认为比大多数用户模式代码更受信任。这些进程(如csrss.exe)及其复杂的内核模式对应进程(如win32k.sys)中的大多数都是几十年前在不同的假设下编写的,当时内核-用户边界甚至比今天还要弱。Microsoft没有重写所有这些组件,而是使这些用户模式处理WinTcb-Light,从而减轻篡改和注入攻击。亚历克斯·约内斯库(Alex Ionescu)在2013年明确表示:

Because the Win32k.sys developers did not expect local code injection attacks to be an issue (they require Administrator rights, after all), many of these APIs didn’t even have SEH, or had other assumptions and bugs. Perhaps most famously, one of these, discovered by j00ru, and still unpatched, has been used as the sole basis of the Windows 8 RT jailbreak. In Windows 8.1 RT, this jailbreak is “fixed”, by virtue that code can no longer be injected into Csrss.exe for the attack. Similar Win32k.sys exploits that relied on Csrss.exe are also mitigated in this fashion.
由于 Win32k.sys开发人员并不认为本地代码注入攻击会成为一个问题(毕竟他们需要管理员权限),因此其中许多 API 甚至没有 SEH,或者有其他假设和错误。也许最著名的是,其中之一由j00ru发现,仍未修补,已被用作Windows 8 RT越狱的唯一基础。在Windows 8.1 RT中,这种越狱是“固定的”,因为代码不能再注入Csrss.exe用于攻击。依赖于 Csrss 的类似 Win32k.sys 漏洞.exe也以这种方式得到缓解。

To reduce the attack surface, Microsoft runs most of their PPL code with less privilege than WinTcb-Light:
为了减少攻击面,Microsoft以低于WinTcb-Light的权限运行其大部分PPL代码:

APPL processes in Windows 11 22H2, as seen in Process Explorer

Microsoft does not consider PPL to be a security boundary, meaning they won’t prioritize security patches for code-execution vulnerabilities discovered therein, but they have historically addressed some such vulnerabilities on a less-urgent basis.
Microsoft不认为PPL是安全边界,这意味着他们不会为其中发现的代码执行漏洞确定安全补丁的优先级,但他们历来在不太紧急的基础上解决了一些此类漏洞。

Loading code into PPL processes
将代码加载到 PPL 进程中

To load code into a PPL process, it must be signed by special certificates. This applies to both executables (process creation) and libraries (DLLs loads). For the sake of simplicity, we’ll focus on DLL loading, but the CI validation process is very similar for both. This article is focused on PPL, so we will not discuss kernel mode code integrity.
若要将代码加载到 PPL 进程中,必须由特殊证书对其进行签名。这适用于可执行文件(进程创建)和库(DLL 加载)。为简单起见,我们将重点介绍 DLL 加载,但两者的 CI 验证过程非常相似。本文重点介绍 PPL,因此我们不会讨论内核模式代码完整性。

Portable Executable (PE) files come in many extensions, including EXE, DLL, SYS, OCX, CPL, and SCR. While the extension may vary, they’re all quite similar at a binary level. For a PPL process to load and execute a DLL, a few steps must be taken. Note that these steps are simplified, but should be sufficient for this article:
可移植可执行 (PE) 文件有许多扩展名,包括 EXE、DLL、SYS、OCX、CPL 和 SCR。虽然扩展可能会有所不同,但它们在二进制级别上都非常相似。要使 PPL 进程加载和执行 DLL,必须执行几个步骤。请注意,这些步骤已简化,但对于本文来说应该足够了:

  1. An application calls LoadLibrary, passing the path to the DLL to be loaded.
    应用程序调用 LoadLibrary,将路径传递给要加载的 DLL。
  2. LoadLibrary calls into the loader within NTDLL (e.g. ntdll!LdrLoadDll), which opens a handle to the file using an API such as NtCreateFile.
    加载库调用 NTDLL 中的加载程序(例如 ntdll!LdrLoadDll),它使用 API 如 NtCreateFile 打开文件的句柄。
  3. The loader then passes this file handle to NtCreateSection, asking the kernel memory manager to create a section object which describes how the file is to be mapped into memory. A section object is also known as a file mapping object in higher abstraction layers (such as Win32), but since we’re focused on the kernel, we’ll keep calling them section objects. The Windows loader always uses a specific type of section called an executable image (aka SEC_IMAGE), which can only be created from PE files.
    然后,加载程序将此文件句柄传递给 NtCreateSection,要求内核内存管理器创建一个 section 对象,该对象描述如何将文件映射到内存中。节对象在高级抽象层(如 Win32)中也称为文件映射对象,但由于我们专注于内核,我们将继续称它们为节对象。Windows 加载程序始终使用称为可执行映像(又名 SEC_IMAGE)的特定类型的部分,该部分只能从 PE 文件创建。
  4. Before returning the section object to user mode, the memory manager checks the digital signature on the file to ensure it meets the requirements for the given level of PPL. The internal memory manager function MiValidateSectionCreate relies on the Code Integrity module ci.dll to handle the requisite cryptography and PKI policy.
    在将节对象返回到用户模式之前,内存管理器会检查文件上的数字签名,以确保它满足给定 PPL 级别的要求。内部内存管理器函数 MiValidateSectionCreate 依赖于代码完整性模块 ci.dll 来处理必要的加密和 PKI 策略。
  5. The memory manager restructures the PE so that it can be mapped into memory and executed. This step involves creating multiple subsections, one for each of the different portions of the PE file that must be mapped differently. For example, global variables may be read-write, whereas the code may be execute-read. To achieve this granularity, the resulting regions of memory must have distinct page table entries with different page permissions. Other changes may be applied here, such as applying relocations, but they are out of scope for this research publication.
    内存管理器重构 PE,以便可以将其映射到内存中并执行。此步骤涉及创建多个子节,每个子节用于必须以不同方式映射的 PE 文件的每个不同部分。例如,全局变量可以是读写的,而代码可以是执行-读取的。若要实现此粒度,生成的内存区域必须具有具有不同页面权限的不同页表条目。此处可能应用其他更改,例如应用重新定位,但它们超出了本研究出版物的范围。
  6. The kernel returns the new section handle to the loader in NTDLL.
    内核将新的节句柄返回到 NTDLL 中的加载程序。
  7. The NTDLL loader then asks the kernel memory manager to map a view of the section into the process address space via the NtMapViewOfSection syscall. The memory manager complies.
    然后,NTDLL 加载程序要求内核内存管理器通过 NtMapViewOfSection 系统调用将该节的视图映射到进程地址空间。内存管理器符合要求。
  8. Once the view is mapped, the loader finishes the processing required to create a functional DLL in memory. The details of this are out of scope.
    映射视图后,加载程序将完成在内存中创建功能性 DLL 所需的处理。这方面的细节超出了范围。

Page hashes 页面哈希

In the above steps, we can see that a PE’s digital signature is validated during section creation, but there is another way that code can be loaded into the address space of a PPL process – paging.
在上述步骤中,我们可以看到 PE 的数字签名在创建节期间得到验证,但还有另一种方法可以将代码加载到 PPL 进程的地址空间中 – 分页。

Unmodified pages belonging to file-backed sections (including SEC_IMAGE) can be quickly discarded whenever the system is low on memory because there’s a copy of that exact data on disk. If the page is later touched, the CPU will issue a page fault, and the memory manager’s page fault handler will re-read that data from disk. Because SEC_IMAGE sections can only be created from immutable file data, and the signature has already been verified, the data is considered trusted.
只要系统内存不足,属于文件支持部分(包括SEC_IMAGE)的未修改页面就可以快速丢弃,因为磁盘上有该确切数据的副本。如果稍后触摸该页面,CPU 将发出页面错误,内存管理器的页面错误处理程序将从磁盘重新读取该数据。由于SEC_IMAGE节只能从不可变的文件数据创建,并且签名已经过验证,因此数据被视为受信任。

PE files may be optionally built with the /INTEGRITYCHECK flag. This sets a flag in the PE header that, among other things, instructs the memory manager to create and store hashes of every page (aka “page hashes”) of that PE as sections are created from it. After reading a page from disk, the page fault handler calls MiValidateInPage to verify that the page hash hasn’t changed since the signature was initially verified. If the page hash has changed, the handler will raise an exception. This feature is useful for detecting bit rot in the page file and a few types of attacks. Beyond /INTEGRITYCHECK images, page hashes are also enabled for all modules loaded into full Protected Processes (not PPL), and drivers loaded into the kernel.
可以选择使用 /INTEGRITYCHECK 标志构建 PE 文件。这会在 PE 标头中设置一个标志,该标志指示内存管理器在从该 PE 创建部分时创建和存储该 PE 的每个页面的哈希(也称为“页面哈希”)。从磁盘读取页面后,页面错误处理程序将调用 MiValidateInPage 来验证自最初验证签名以来页面哈希是否未更改。如果页面哈希已更改,处理程序将引发异常。此功能对于检测页面文件中的位腐烂和几种类型的攻击非常有用。除了 /INTEGRITYCHECK 映像之外,还为加载到完全受保护的进程(不是 PPL)中的所有模块以及加载到内核中的驱动程序启用了页面哈希。

Note: It is possible to create a SEC_IMAGE section from a file with user-writable references, a tactic employed by techniques like Process Herpaderping. The existence of user-writable references means that a file could be modified after the image section is created. When a program attempts to use such a mutable file, the memory manager first copies the file’s contents to the page file, creating an immutable backing for the image section to prevent tampering. In this case, the section will not be backed by the original file, but instead by the page file. See this Microsoft article for more information about user-writable references.
注意:可以从具有用户可写引用的文件创建SEC_IMAGE部分,这是过程牧羊人等技术采用的一种策略。用户可写引用的存在意味着可以在创建图像部分后修改文件。当程序尝试使用此类可变文件时,内存管理器首先将文件的内容复制到页面文件中,为图像部分创建不可变的支持以防止篡改。在这种情况下,该节将不受原始文件的支持,而是由页面文件支持。有关用户可写引用的详细信息,请参阅此Microsoft文章。

Exploitation 开发

In September 2022, Gabriel Landau from Elastic Security filed VULN-074311 with MSRC, notifying them of two zero-day vulnerabilities in Windows: one admin-to-PPL and one PPL-to-kernel. Two exploits for these vulnerabilities were provided named PPLFault and GodFault, respectively, along with their source code. These exploits allow malware to bypass LSA protection, terminate or blind EDR software, and modify kernel memory to tamper with core OS behavior – all without the use of any vulnerable drivers. See this article for more details on their impact.
2022 年 9 月,Elastic Security 的 Gabriel Landau 向 MSRC 提交了 VULN-074311,通知他们 Windows 中存在两个零日漏洞:一个是管理员到 PPL 漏洞,另一个是 PPL 到内核漏洞。针对这些漏洞提供了两个漏洞,分别命名为PPLFault和GodFault,以及它们的源代码。这些漏洞允许恶意软件绕过 LSA 保护、终止或屏蔽 EDR 软件,并修改内核内存以篡改核心操作系统行为 – 所有这些都无需使用任何易受攻击的驱动程序。有关其影响的更多详细信息,请参阅本文。

The admin-to-PPL exploit PPLFault leverages the fact that page hashes are not validated for PPL and employs the Cloud Filter API to violate immutability assumptions of files backing SEC_IMAGE sections. PPLFault uses paging to inject code into a DLL loaded within a PPL process running as WinTcb-Light, the most privileged form of PPL. The PPL-to-kernel exploit GodFault first uses PPLFault to get WinTcb-Light code execution, then exploits the kernel’s trust of WinTcb-Light processes to modify kernel memory, granting itself full read-write access to physical memory.
管理员到 PPL 漏洞利用 PPLFault利用页面哈希未针对 PPL 进行验证的事实,并使用云筛选器 API 来违反支持SEC_IMAGE部分的文件的不可变性假设。PPLFault使用分页将代码注入到PPL进程中加载的DLL,该DLL以WinTcb-Light(PPL的最特权形式)运行。PPL 到内核漏洞利用 GodFault 首先使用 PPLFault获取 WinTcb-Light 代码执行,然后利用内核对 WinTcb-Light 进程的信任来修改内核内存,授予自己对物理内存的完全读写访问权限。

Though MSRC declined to take any action on these vulnerabilities, the Windows Defender team has shown interest. PPLFault and GodFault were released at Black Hat Asia in May 2023 alongside a mitigation to stop these exploits called NoFault.
尽管MSRC拒绝对这些漏洞采取任何行动,但Windows Defender团队表现出了兴趣。PPLFault和GodFault于2023年5月在Black Hat Asia上发布,同时发布了一种名为NoFault的缓解措施,以阻止这些漏洞利用。

Mitigation 缓解

On September 1, 2023, Microsoft released build 25941 of Windows Insider Canary. This build adds a new check to the memory manager function MiValidateSectionCreate which enables page hashes for all images that reside on remote devices. Comparing 25941 against its predecessor 25936, we can see the following two new basic blocks:
2023 年 9 月 1 日,Microsoft发布了 Windows 预览体验成员金丝雀的内部版本 25941。此版本向内存管理器函数 MiValidateSectionCreate 添加了新的检查,该函数为驻留在远程设备上的所有图像启用页面哈希。将 25941 与其前身 25936 进行比较,我们可以看到以下两个新的基本块:

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

Decompiled into C, the new code looks like this:
反编译为 C,新代码如下所示:

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

When PPLFault is run, Windows Error Reporting generates an event log indicating a failure during a paging operation:
运行 PPLFault(英语:PPLFault) 时,Windows 错误报告会生成一个事件日志,指示分页操作期间出现故障:

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

PPLFault requires its payload DLL to be loaded over the SMB network redirector to achieve the desired paging behavior. By forcing the use of page hashes for such network-hosted DLLs, the exploit can no longer inject its payload, so the vulnerability is fixed. The aforementioned NoFault mitigation released at Black Hat also targets network redirectors, blocking such DLL loads into PPL entirely. Elastic Defend 8.9.0 and later block PPLFault – please update if you haven’t already.
PPLFault要求通过SMB网络重定向程序加载其有效负载DLL,以实现所需的分页行为。通过强制对此类网络托管的 DLL 使用页面哈希,该漏洞无法再注入其有效负载,因此修复了该漏洞。黑帽发布的上述NoFault缓解措施也针对网络重定向器,完全阻止此类DLL加载到PPL中。Elastic Defend 8.9.0 及更高版本可阻止 PPLFault,如果您尚未进行更新,请进行更新。

Tracking down the exact point of failure in a kernel debugger, we can see the page fault handler invoking CI to validate page hashes, which fails with STATUS_INVALID_IMAGE_HASH (0xC0000428). This is later converted to STATUS_IN_PAGE_ERROR (0xC0000006).
在内核调试器中跟踪确切的故障点,我们可以看到页面错误处理程序调用 CI 来验证页面哈希,该处理程序失败并出现STATUS_INVALID_IMAGE_HASH (0xC0000428)。这后来被转换为STATUS_IN_PAGE_ERROR(0xC0000006)。

0: kd> g
Breakpoint 1 hit
CI!CiValidateImagePages+0x360:
0010:fffff805`725028b4 b8280400c0      mov     eax,0C0000428h
7: kd> k
 # Child-SP          RetAddr               Call Site
00 fffff508`1b4a6dc0 fffff805`72502487     CI!CiValidateImagePages+0x360
01 fffff508`1b4a6f90 fffff805`6f2f1bbd     CI!CiValidateImageData+0x27
02 fffff508`1b4a6fd0 fffff805`6ee35de5     nt!SeValidateImageData+0x2d
03 fffff508`1b4a7020 fffff805`6efa167b     nt!MiValidateInPage+0x305
04 fffff508`1b4a70d0 fffff805`6ef9fffe     nt!MiWaitForInPageComplete+0x31b
05 fffff508`1b4a71d0 fffff805`6ef68692     nt!MiIssueHardFault+0x3fe
06 fffff508`1b4a72e0 fffff805`6f0a784b     nt!MmAccessFault+0x3b2
07 fffff508`1b4a7460 00007fff`ccf71500     nt!KiPageFault+0x38b
08 000000b6`776bf1b8 00007fff`d5500ac0     0x00007fff`ccf71500
09 000000b6`776bf1c0 00000000`00000000     0x00007fff`d5500ac0
7: kd> !error C0000428
Error code: (NTSTATUS) 0xc0000428 (3221226536) - Windows cannot verify the 
 digital signature for this file. A recent hardware or software change 
 might have installed a file that is signed incorrectly or damaged, or 
 that might be malicious software from an unknown source.

Comparing behavior 比较行为

With the fix introduced in build 25941, the final vulnerable build is 25936. Running PPLFault in both builds under a kernel debugger, we can use the following WinDbg command to see the files for which CI is computing page hashes:
使用内部版本 25941 中引入的修补程序,最终易受攻击的版本是 25936。在内核调试器下的两个版本中运行 PPLFault,我们可以使用以下 WinDbg 命令来查看 CI 正在为其计算页面哈希的文件:

bp /w "&CI!CipValidatePageHash == @rcx" CI!CipValidateImageHash 
 "dt _FILE_OBJECT @r8 FileName; g"

This command generates the following WinDbg output for build 25936, before the fix:
此命令在修复之前为内部版本 25936 生成以下 WinDbg 输出:

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

Here is the WinDbg output for build 25941, which includes the fix:
下面是内部版本 25941 的 WinDbg 输出,其中包括修补程序:

Inside Microsoft's plan to kill PPLFault — Elastic Security Labs

Conclusion 结论

Despite taking longer than it perhaps should, it’s exciting to see Microsoft taking steps to defend PPL processes (including Anti-Malware) from malware running as admin, and users will benefit if this improvement reaches GA soon. Many features in Insider, even security features, are not available in (and may never reach) GA. Microsoft is very conservative when it comes to changes with potential stability, compatibility, or performance risk; memory manager changes are among the risker types. For example, the PreviousMode kernel exploit mitigation spotted in Insider last November still hasn’t reached GA, even after at least 10 months.
尽管花费的时间可能比应有的时间长,但令人兴奋的是看到Microsoft采取措施保护PPL进程(包括反恶意软件)免受以管理员身份运行的恶意软件的侵害,如果此改进很快达到GA,用户将受益。预览体验成员中的许多功能,甚至是安全功能,在 GA 中不可用(并且可能永远不会达到)。 Microsoft在涉及具有潜在稳定性、兼容性或性能风险的更改时非常保守;内存管理器更改属于风险较高的类型。例如,去年 11 月在 Insider 中发现的 PreviousMode 内核漏洞利用缓解措施仍然没有达到正式发布,即使至少在 10 个月后也是如此。

Special thanks to Grzegorz Tworek for his help reverse engineering some kernel functions.
特别感谢 Grzegorz Tworek 帮助对一些内核函数进行逆向工程。

原文始发于CSDN(0pr):Inside Microsoft’s plan to kill PPLFault — Elastic Security Labs

版权声明:admin 发表于 2023年9月21日 上午9:14。
转载请注明:Inside Microsoft’s plan to kill PPLFault — Elastic Security Labs | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...