Vulnerabilities

Inside Win32k Exploitation: Analysis of CVE-2022-21882 and CVE-2021-1732

Clock Icon 36 min read
Related Products

This post is also available in: 日本語 (Japanese)

Table of Contents

13. Use arbitrary read/write to clone the System token and elevate privileges

Table of Contents: Figures

Figure 47. Lines 355-359 of the PoC.
Figure 48. WinDBG dump of the leaked spmenu object.
Figure 49. WinDbg output for spmenu + 0x50.
Figure 50. WinDBG output for *spmenu + 0x50.
Figure 51. Lines 570-598 of the PoC.
Figure 52. THREADINFO structure.
Figure 53. WinDBG output for the ETHREAD structure.
Figure 54. WinDBG output of the KTHREAD + 0x220 showing the EPROCESS entry.
Figure 55. Lines 601-637 of the PoC.

13. Use arbitrary read/write to clone the System token and elevate privileges

At this point, we now have a pointer to the original spmenu object of Wnd1, which is also a kernel memory address. We also replaced the original spmenu pointer with a fake spmenu object that was stored in the spmenu entry of Wnd1’s parent tagWND structure.

As will be shown shortly, the spmenu object is used to retrieve information about a window’s menu bars. Because fake spmenu is now a user-mode address, we’ll be able to read directly from these addresses. If we can trick Windows into populating one or more of the fake spmenu members with kernel addresses, we’ll have a kernel arbitrary read primitive.

Unfortunately, due to Microsoft not supplying symbols for this structure, we need to do some analysis to determine what members this structure contains. We’ll cheat a bit and use the exploit PoC to help us out. We know, based on the allocation of g_pMem4 (lines 355 through 359), that the spmenu structure is likely 0xa0 bytes in size. This is shown in Figure 47, taken from lines 355 through 359 of the PoC.

Image 47 is a screenshot of lines 355 through 359 of the POC. Four lines start with QWORD and the last and fifth line starts with HLOCAL.
Figure 47. Lines 355-359 of the PoC.

If we dump the memory at the leaked address and look at the addresses up to offset 0xa0, we might find something interesting. A dump from WinDbg is shown in Figure 48.

Image 48 is a screenshot of the dump from WinDbg. It shows the leaked spmenu object.
Figure 48. WinDBG dump of the leaked spmenu object.

You can see the first entry likely contains an ID of some sort. This was the shared value in the parent and child tagWND structures.

The next two entries are not that interesting. The next three are more kernel addresses, so maybe we can dump those and see if they contain anything recognizable.

Offset 0x30 has the same value the user-mode safe spmenu object (Figure 44) had above at offset 0x98. We determined this was likely an offset from the desktop heap.

If we add this offset to the address of the kernel desktop heap, we get 0xffff8e8201000000 + 0x3a850 = 0xffff8e820103a850. This is the same value stored in spmenu + 0x28 in Figure 48 above. This result lends support to our offset theory.

Let’s assume we looked at the other two addresses and didn’t see anything obvious. If we dump the memory at offset spmenu + 0x50 we’d see what’s shown in Figure 49.

Image 49 is a screenshot of the WinDBG output for SP menu + 0×50.
Figure 49. WinDBG output for spmenu + 0x50.

From analysis, this address is familiar (rsi in Figure 40). It’s actually the parent tagWND address of Wnd1 shown in Figure 50.

Image 50 is a screenshot of the WinDbg output for *spmenu + 0×50.
Figure 50. WinDBG output for *spmenu + 0x50.

This means there is a way to go from an spmenu object to the parent tagWND object. If we look at line 507 in the PoC (shown in the first line of Figure 51), the leaked spmenu + 0x50 is being read using the read64 function. We’ll cover how this function works in the next section, however, for now just understand that it retrieves the kernel pointers of the supplied arguments. Therefore we can assume that qwFrist will contain the address of the parent tagWND structure.

Image 51 is a screenshot of lines 570 through 598 of the POC. It includes the function of that retrieve the kernel pointers of the supplied arguments.
Figure 51. Lines 570-598 of the PoC.

If we look at the contents of the tagWND structure again (shown in Figure 38) and understand a bit about how privilege escalation exploits work (this is a good discussion on token stealing), we can see at offset 0x10 there is a THREADINFO entry. A THREADINFO entry contains a W32THREAD entry that, in turn, points to the ETHREAD entry of the current thread in the kernel. The THREADINFO structure is shown in Figure 52.

Image 52 is a screenshot of the structure of THREADINFO.
Figure 52. THREADINFO structure.

ETHREAD + 0x00 (shown in Figure 53) is a pointer to the KTHREAD structure. This in turn has a pointer to the EPROCESS structure at offset 0x220.

Within the EPROCESS structure, a token field stores the process token that determines the privileges associated with each process. These are being retrieved in the qwfourth, qwfifth, and qwEprocess variable in the PoC, shown in Figure 52 above. WinDbg output for the ETHREAD contents is shown in Figure 53.

Image 53 is a screenshot of the WinDbg output for the ETHREAD structure. t nt! +exeee +ex438 +0<438 +ex448 +0<448 +ex45e +ex458 +ex46e +0<468 +0<488 +ex488 +8x4a8 +ex4be +ex4ce +ex4c8 +ex4de Tcb CreateTime ExitT ime KeyedWaitChain PostB10ckList ForwardLinkShadow : StartAddress TerminationPort ReaperLink KeyedWaitVa1ue KTHREAD LARGE INTEGER exe LARGE INTEGER exe _ LIST_ENTRY [ exeeeeøeee•eeøeeeee - _ LIST ENTRY [ exfffff807* 70e36f6e oxfffff8eT70e36f6e void • exffffd4e1* øfOf3688 Void : (null) (null) • (null) ActiveTimerListLock : Ox144decø1* møødeee ActiveTimerListHead . _LIST_ENTRY [ øxe1d81f9f' 9658137e oxeeeeeeee• eeeøe394 - exffffd4Ø1*0f0f3688 ] - exøeeøeeøø• eeee1ca8 ] Cid CLIENT ID KeyedWaitSemaphore : _ KSEMAP}ORE Alpcwaitsemaphore : KSEMAPHORE ClientSecurity ps CLIENT SECURITY CONTEXT IrpList _ LIST_ENTRY [ exffffd4Ff5d82b6e - TopLeve11rp DeviceToverify : (null) (null) Win32StartAddress . exffffc2øa• 89e9267e ]
Figure 53. WinDBG output for the ETHREAD structure.
WinDbg output showing offset KTHREAD + 0x220 contains a pointer to the EPROCESS structure as shown in Figure 54.

Image 54 is a screenshot of the KTHREAD + 0x220 showing the EPROCESS entry. It contains a pointer.
Figure 54. WinDBG output of the KTHREAD + 0x220 showing the EPROCESS entry.

Now that the EPROCESS of the current process is known, you can use the ActiveProcessLinks to search for the System process that is uniquely identified with a Process ID (PID) of 0x4. ActiveProcessLinks is a linked list of currently running processes also located in the EPROCESS structure.

Once the PID is found, the token can be found in the same manner as above and copied over the current process’ token to elevate privileges to that of System. This is what is being accomplished in the PoC via lines 601 through 637, shown in Figure 55.

Image 55 is a screenshot of line 601 through 637 of the POC. It is part of privilege elevation.
Figure 55. Lines 601-637 of the PoC.

Here are the steps to summarize the methodology to steal the system token:

  1. Save the KTHREAD.ApcState.Process, which is a pointer to the EPROCESS structure.
  2. Save a pointer to EPROCESS.ActiveProcessLinks.Flink, which is a linked list of the processes currently running on the system.
  3. Compare the PID of each process to 0x4 to find the System process.
  4. Once the PID is found, save the System process token.
  5. Replace the token of the current process with that of the System process.
  6. Spawn a new terminal process, which will inherit the System token privileges.

All of these structure members are read using the read64 function of the PoC. This function is taking advantage of the fake spmenu object and using the GetMenuBarInfo function to read/parse through the structures to traverse from spmenu to the token.

In our final section, we cover the final step in our analysis, analyze the read64 function and come to the conclusion.

Continue Reading ➠ Section 7 – Detailed Analysis: Step 14, Analysis of the read64 function and  the Conclusion

Back to Top

Enlarged Image