This quick blog is the first in a two-part series discussing a userland Windows exploit initially disclosed by James Forshaw and Alex Ionescu. The exploit enables attackers to perform highly privileged actions that typically require a kernel driver. Protected process light Windows 8.1 introduced the concept of Protected Process Light (PPL), which enables specially-signed programs […]
This quick blog is the first in a two-part series discussing a userland Windows exploit initially disclosed by James Forshaw and Alex Ionescu. The exploit enables attackers to perform highly privileged actions that typically require a kernel driver.
Windows 8.1 introduced the concept of Protected Process Light (PPL), which enables specially-signed programs to run in such a way that they are immune from tampering and termination, even by administrative users. The goal is 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.
For more information on PPL processes, please see the following resources:
At a high level, the exploit is a cache poisoning attack where an attacker can add a DLL to the KnownDlls cache — a trusted list of Windows DLLs. KnownDlls is only writable by WinTcb processes, which is the highest form of PPL… but a bug in the implementation of the DefineDosDevice API allows attackers to trick CSRSS, a WinTcb process, into creating a cache entry on their behalf. KnownDlls is trusted by the Windows loader, so no additional security checks are performed as KnownDlls are loaded, even inside PPL processes. After poisoning the cache, the attacker launches a protected process which ends up loading their DLL and executing its payload.
Because this exploit enables attackers to inject a DLL of their choosing into a PPL process, they can perform any action with WinTcb privileges. Microsoft has indicated that they are not interested in servicing this vulnerability. It is confirmed to work on Windows 10 21H1 version 10.0.19043.985.
The first public exploit POC that we’re aware of is the recently-released PPLDump, a tool that can dump any PPL process, such as LSASS in RunAsPPL mode. A few weeks after PPLDump was released, Sealighter-TI came out, reusing the PPLDump exploit code to grant access to the Threat-Intelligence ETW feed, which is normally restricted to AntiMalware companies under NDA. The rapid turnaround of Sealighter-TI demonstrates how easy it is to repurpose the exploit code to execute a new payload.
With the exploit code public, we expect that offensive tools will quickly capitalize on it, running payloads as WinTcb PPL. This will enable them to:
Seeing this vulnerability with no public mitigation, we are releasing a tool called PPLGuard to close it. PPLGuard, which is based on the PPLDump code base with permission, uses the exploit to first elevate to WinTcb PPL, then applies a DACL making the KnownDlls object directory read-only. This blocks the exploit by preventing CSRSS from adding a new entry — a critical step in the exploit chain. This DACL exists in memory only, so it is erased upon reboot.
Since PPLGuard closes the vulnerability that the exploit relies upon, subsequent executions will fail.
C:gitPPLGuard>x64ReleasePPLGuard.exe [+] KnownDlls hardening successful! :) C:gitPPLGuard>x64ReleasePPLGuard.exe [-] DefineDosDevice failed with error code 5 - Access is denied.
The PPLGuard proof of concept tool can be found here.
In this blog, we covered a Windows privilege escalation exploit and provided an open source tool that mitigates the exploited vulnerability. In part 2 of this blog, we’ll cover how to hunt for these types of attacks using Elastic Security. Stay tuned.
Update 2021-06-03: After this blog was written, someone ported the PPLDump exploit to .NET to run Cobalt Strike beacon as WinTCB PPL.