Privilege escalation using the XAML diagnostics API (CVE-2023-36003)
This is a write-up of a vulnerability that I discovered in Windows. The vulnerability was patched in December’s Patch Tuesday, and the CVE assigned to it is CVE-2023-36003. The vulnerability allows a non-elevated process to inject a DLL into an elevated or otherwise inaccessible process, allowing for privilege escalation. The vulnerability is caused by a lack of security checks in the InitializeXamlDiagnosticsEx
API, which is used for inspecting applications that use Extensible Application Markup Language (XAML) for their UI. XAML is the recommended way to build user interfaces in new Windows applications, and is used by more and more built-in applications, including Task Manager and Windows Terminal.
Discovery
The discovery of this vulnerability was a pure accident. Around May-July I was developing UWPSpy, an inspection tool for UWP and WinUI 3 applications. Once v1.0 was completed, I did some sanity checks before publishing it. At some point, I tested it with Task Manager, which uses XAML for its UI in recent Windows 11 versions. Since Task Manager is an elevated process, I was wondering which error message will be displayed: element not found, permission error, or maybe UWPSpy will just crash if I missed some handling. To my surprise, the least expected happened: UWPSpy proceeded and inspection worked as usual. That meant that a non-elevated process successfully caused its DLL to be loaded by an elevated process. That’s a privilege escalation.
The vulnerability report
Below is the vulnerability report that was submitted to Microsoft right after the discovery.
Summary
The documented
InitializeXamlDiagnosticsEx
API allows to inject a DLL into another process for diagnostic purposes. This API lacks basic security checks, allowing a non-elevated process to inject a DLL into any other process supported by the API, including elevated processes and UIAccess applications.Exploitation
The simplest way to achieve privilege escalation with the
InitializeXamlDiagnosticsEx
API is to target a running elevated process which uses UWP. For example:
- Task Manager. Starting from Windows 11 22H2, Task Manager uses UWP for the UI and is prone to this attack. If auto-elevation is enabled, an attacker can just launch taskman.exe and use the attack. If not, the attacker can wait for Task Manager to be opened by the user, which is a common operation, and then target it for the attack.
- Windows Terminal. It’s installed by default in recent Windows versions, and can be installed manually in previous versions. It uses UWP and is prone to this attack. Since opening a terminal as administrator is a common operation, the attacker can wait for it and then target the elevated Windows Terminal process.
In addition, the API can be misused to easily bypass User Interface Privilege Isolation (UIPI) by targeting a UIAccess process. Running such a process doesn’t require UAC, so the attack can work without user interference. The attacker can run one of the available accessibility tools which use UWP, and use the attack to run code in UIAccess context and bypass UIPI. Target examples: Magnify.exe, VoiceAccess.exe, both tested on Windows 11 22H2.
Broader attack surface
The
InitializeXamlDiagnosticsEx
API uses message communication via undocumented API in CoreMessaging.dll for IPC communication with the target process. This IPC method is backed by ALPC, and has other uses, too, for example the Emoji input method (Win+.). It’s worth making sure that no other usages of CoreMessaging can be misused in a similar way. For example, a possible misuse that I didn’t research is using the Emoji input method messages to send arbitrary text to an elevated terminal window, allowing to type any command and gain elevated code execution.Affected Windows versions
The problem was observed in an up-to-date Windows 10, an up-to-date Windows 11, and in the latest Windows Insider build. I believe that the problem is relevant from Windows 10 1703, where the API was introduced according to the documentation.
POC
A simple POC (proof of concept) can be found here. A short video demonstrating the exploitation can be found here.
The fix
I used Ghidra with BinDiff to see how the fix was implemented, comparing these binaries:
From a quick diffing session, the following two changes are likely to implement the fix:
RegisterVisualDiagnosticsPort
A security descriptor based on the running process token is now used for creating the connection port.
DoesMsgSenderHaveEnoughPrivileges
in OnVisualDiagInit
OnVisualDiagInit
now calls the DoesMsgSenderHaveEnoughPrivileges
function to make sure that the sender is allowed to manipulate the target.
I’m not sure why both checks are needed. It’s also interesting to note that non-trivial checks had to be added to secure the connection. It means that it’s quite possible that there are other such vulnerabilities, or that similar vulnerabilities will be introduced in the future.
Timeline
- July 25 - The vulnerability was discovered and reported to Microsoft.
- August 8 - Microsoft acknowledged the vulnerability.
- September 26 - Microsoft confirmed that the vulnerability will be patched in December’s Patch Tuesday.
- December 12 - The patch became available as a part of Patch Tuesday.