
Proof-of-concept exploit for CVE-2022-37969, a Windows Common Log File System driver local privilege escalation. Demonstrates heap spray, token stealing, and arbitrary kernel write to achieve SYSTEM privileges.
authors: Ricardo Narvaja & Daniel Kazimirow (Solid)
For demonstration purposes only. Complete exploit works on vulnerable Windows 11 21H2 systems.
Functional PoC based on previously published information by Zscaler
Checkout the writeup Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation.
Exploitation walkthrough:
The scenario used here was Windows 11 21H2 (OS Build 22000.918) clfs.sys v10.0.22000.918
The first step is to create a file named MyLog.blf in the public folder (%public%), by using the CreateLogFile() function:



Then it creates several log files with random names using a Loop.
And within the loop, it calls to our getBigPoolInfo() function:

It calls the NtQuerySystemInformation(), with 0x42 (66 decimal) as the first argument, it will return in v5 the information about the raids made in the bigpool, whose structure is of type SYSTEM_BIGPOOL_INFORMATION.

We have to call this function twice. The first one will return an error, but it will give us the correct size of the buffer to call the second time to obtain the desired information.

v5 will receive the information of the SYSTEM_BIG_POOL_INFORMATION structure.

The number of allocations in the bigpool, is stored in the first field called Count, in the second field there is an array of structures SYSTEM_BIGPOOL_ENTRY.

Then we’ll search through all the structures for the "Clfs" tag and the size 0x7a00.

It stores in an array called kernelAddrArray the VirtualAddress which is the first field of each structure that has CLFS tag and size 0x7a00. From now on, the pools that meet both conditions will be called: “right pools”.

In addition to store each right pool in the array, it stores the last right pool found in the content of a2 variable, which is used as argument of the function.

In this way a2 always points to the last right pool with CLFS tag and size 0x7a00 created.
The variable v26 always stores the previous right pool found since it is equal to v24 (v26=v24), before calling getBigPoolinfo(), but v24 is updated when leaving this call with the last right pool found, and v26 stays with de previous right pool found.

Then It subtracts both directions, and in case the result is negative, inverts the operands so that it is always positive.

In this way in v32 will stores the difference between the VirtualAddress of the last two right pool found.
Then it does something similar, in this case v23 is initially zero so it does v23=v32 the first time.

The next time in loop v23 it still has the same value and is not zero, so it breaks and goes here.

V32 has the last difference and v23 the previous one, if they are equal, it comes out and increments one, but resets the counter to zero.
The idea is to find 6 consecutive comparisons of CLFS tags and size 0x7a00 whose differences are equal, and that difference will be 0x11000. We will see when executing that when it finds 6 (since it starts from scratch) consecutive with equal distances it will give that value of difference between them.


There we see that he found 6 consecutive and left the loop of creating log files.
In the "public" folder we can see the files created

Our craftFile() function opens the original file (MyLog.blf) and modifies it to trigger the bug.

After modifying the file, it's necessary to change the CRC32, otherwise we'll get a corrupt file error
This value is located at offset 0x80C of the file.