This post is also available in: 日本語 (Japanese)
Executive Summary
After seeing reports of two similar privilege escalation vulnerabilities in Microsoft Windows – CVE-2021-1732 and CVE-2022-21882 – we decided to analyze both to better understand the code involved in each. This is a continuation of Inside Win32k Exploitation, in which we discussed the Win32k internals and exploitation in general as background information to explore the issues surrounding CVE-2021-1732 and CVE-2022-21882.
Here, we will dig deeper into CVE-2021-1732 and CVE-2022-21882 and their related proof-of-concept (PoC) exploits. We’ll walk through an analysis of these two exploits, and thus see why the patch for CVE-2021-1732 was not sufficient to prevent CVE-2022-21882.
Both vulnerabilities discussed in this series are detected and blocked by the Cortex XDR Anti-LPE protection module. Both vulnerabilities are data-only exploits that copy the NT/Authority System privilege token to that of the current (exploit) process for privilege escalation. The XDR Anti-LPE modules monitor for this specific type of privilege escalation technique.
Related Unit 42 Topics | Microsoft Windows, CVE-2021-1732, CVE-2022-21882 |
Analysis of CVE-2021-1732 and CVE-2022-21882
In this section we’ll discuss two Win32k PoC exploits, CVE-2021-1732 and CVE-2022-21882. Both of these vulnerabilities abused xxxClientAllocWindowClassExtraBytes and NtUserConsoleControl to overwrite the tagWND.cbWndExtra data field of an adjacent window to a large value, allowing for an arbitrary write primitive. They each use this arbitrary write to create a fake spmenu in the adjacent window, and then use GetMenuBarInfo to create an arbitrary read primitive. The arbitrary read/write primitives are then used to copy the NT/AUTHORITY SYSTEM token to the current (exploited) process.
We analyze the CVE-2022-21882 PoC in detail, and we’ll discuss CVE-2021-1732 during relevant sections of this analysis to explain how it differs from CVE-2022-21882. Then we’ll discuss why the patch Microsoft issued for CVE-2021-1732 wasn’t sufficient to prevent CVE-2022-21882.
The reason we decided to spend more time discussing CVE-2022-21882 is because there are several blogs with a detailed analysis of CVE-2021-1732 by Google and DBAPPSecurity Threat Intelligence Center.
Both of these exploits are examples of data-only attacks, which means they only require a read/write primitive and do not execute any attacker controlled code. These types of exploits are becoming more common due to the increased difficulty of bypassing modern-day exploit mitigations being deployed within the latest operating systems.
Overview of CVE-2022-21882
This vulnerability was discovered by RyeLv (@b2ahex) for the Tianfu cup hacking competition in October 2021. Microsoft released a patch in January 2022. Based on how similar this was to CVE-2021-1732, it’s highly likely to have affected Windows 10 versions 1709 through 21H2 with a few modifications.
Microsoft did release a patch for Windows 11 for this vulnerability as well. The PoC we are analyzing here was tested on Windows 10 version 21H2.
Triggering the vulnerability
Historically, exploit authors have relied heavily on abusing tagWND or bitmap objects to implement read/write primitives. As we mentioned earlier, Microsoft has gone through great pains to make abusing these objects much more difficult. Specifically, as of Windows 10 version 1703, using SetWindowLong only changes the ExtraBytes field in the user-mode copy of the desktop heap and not the kernel desktop heap, except when operating on a console window.
To get past this limitation, both vulnerabilities rely on changing a window to a console window during a user-mode callback by calling NtUserConsoleControl at a time when the Windows operating system is not expecting it. As a result of converting the window to a console window, this function adds 0x800 to the tagWND.dwExtraFlag mask to indicate that the tagWND.pExtraBytes field is now an offset into the kernel rather than a user-mode pointer.
Because Windows did not have any checks in place to verify window types, when SetWindowLong is called on this window, it will now make changes to the kernel desktop heap just like it did before Windows 10 version 1703. Let’s take a look at how this is implemented by walking through a PoC for CVE-2022-21882.
Proof of Concept Walkthrough
We’ll be looking at the PoC. Here is a brief summary:
- Find HMValidateHandle
- Load NtUserConsoleControl, NtCallbackReturn
- Find KernelCallbackTable
- Store pointers to xxxClientAllocWindowClassExtraBytes and xxxClientFreeWindowClassExtraBytes
- Define a couple of window classes
- Groom the heap
- Create some windows
- Leak user-mode tagWND locations with HMValidateHandle
- Leak user-mode tagWND locations with HMValidateHandle
- Calculate offsets between windows
- Call NtUserConsoleControl on lowest window address
- Create a third (magic) window
- Hook xxxClientAllocWindowClassExtraBytes with a malicious version that calls NtUserConsoleControl and NtCallbackReturn, then returns to the real xxxClientAllocWindowClassExtraBytes
- Use NtUserMessageCall to trigger the hooked function on WndMagic
- Use SetWindowlongA to create an arbitrary write primitive
- Use SetWindowLongPtrA to leak Wnd1’s spmenu kernel address and replace it with a fake spmenu object
- Use arbitrary read/write to clone system token
- Create a new process with System privileges and fix up any changed kernel values
In the next section, we will begin to walk through this summary, starting with steps 1-5.
Continue Reading ➠ Section 2 – Detailed Analysis, Steps 1-5