This is the second part of our study about the Common Log File System (CLFS) and five vulnerabilities in this Windows OS component that have been used in ransomware attacks throughout the year. Please read the previous part first if you haven’t already.
You can skip to the other parts using this table of contents or using the link at the end of this part.
Exploit #1 – CVE-2022-24521
The story that led to the creation of this research begins in April 2022 with the release of an update for CVE-2022-24521. This vulnerability was discovered as a zero-day exploited in the wild and was reported by the National Security Agency and Adam Podlosky and Amir Bazine of Crowdstrike. Unfortunately, we don’t have the details on how it was found or which threat actor used it, as we didn’t seen this vulnerability used in any attacks on our customers when it was a zero-day, and it appears that no details were published by those who found it.
Shortly after the fix was released, we saw advertisements on dark web forums selling a 1-day exploit for this vulnerability and we also started to see this exploit being used in attacks. The artifacts left in the discovered exploit allow us to conclude that it was developed as a 1-day exploit after the release of the patch.
The exploit also had a large number of debug messages, and the same debug messages were found in all the other exploits that we will discuss in this study. Based on these common strings and code similarities, we assume that all of these exploits were developed by the same author. It’s most likely that the exploit developer understood the nuances of CLFS while working on developing a 1-day exploit for it, perhaps came across other vulnerabilities in the process, and then began creating their own zero-day exploits for it.
The exploitation method used by the exploit that we found differs from the one described here. The exploit creates a new BLF file with the help of CreateLogFile and patches just five values in it. These patches are show in the image below.
Patches made to BLF file by exploit #1 (CVE-2022-24521)
The last patch modifies CLFS_BASE_RECORD_HEADER->rgClients[0], which should point to the CLFS_CLIENT_CONTEXT structure. The purpose of the other patches, and the possible root cause of the vulnerability, becomes clear after a new CLFS_CLIENT_CONTEXT structure is added to the structures already present in the BLF file.
Overlap of new CLFS_CLIENT_CONTEXT with existing CLFS_CONTAINER_CONTEXT
The patches build a new CLFS_CLIENT_CONTEXT structure with the valid cbSymName and cbOffset values of the CLFSHASHSYM structure that must precede it, cidClient is set to 0, llCreateTime is set to 0x40000000 and it overlaps the placeholder for the kernel pointer to the CClfsContainer class.
When opening or closing a BLF file, containers are always processed after the clients.
When opening a BLF file:
- The CClfsLogFcbPhysical::Initialize function will cache some values from CLFS_CLIENT_CONTEXT including the file creation date – 0x40000000.
- The LoadContainerQ function will overwrite 0x40000000 with a valid pointer to the CClfsContainer
When closing a BLF file:
- The CClfsLogFcbPhysical::FlushMetadata function will restore the cached file creation date 0x40000000 for the client, thereby making the pointer to the CClfsContainer class equal to 0x40000000!
- The code will call the CClfsLogFcbPhysical::CloseContainers function to close all containers.
- 0x40000000 will be passed as a pointer to the CClfsContainer::Close function.
CClfsContainer::Close function
Passing a controlled address to CClfsContainer::Close allows attackers to decrease an arbitrary QWORD in kernel memory with the help of the ObDereferenceObject function.
The ability to decrement arbitrary values in memory allows attackers to elevate their privileges with the powerful PreviousMode technique. The kernel KTHREAD structure, which is created for all threads, has a field called PreviousMode. It’s used by some kernel functions to check whether they were called directly from the kernel or using a system call from user-level code. For kernel threads this value is zero (False), for user-mode threads it is set to one (True).
MiReadWriteVirtualMemory function
The NtReadVirtualMemory and NtWriteVirtualMemory functions/syscalls check the PreviousMode flag to determine whether or not they can read and write kernel memory. Therefore, decreasing the PreviousMode flag from one to zero in the KTHREAD structure associated with the user-level thread of exploit will allow attackers to use these syscalls to read and write kernel memory.
We believe that this technique was first mentioned in the presentation “Modern Kernel Pool Exploitation: Attacks and Techniques” by Tarjei Mandt in 2011. However, the first time we saw it used in the wild was in 2018, in a zero-day exploit for CVE-2018-8611 (Kernel Transaction Manager EOP), which was covered in our presentation “Overview of the latest Windows OS kernel exploits found in the wild” at BlueHat Shanghai 2019. Currently, this method is widely known and used, so we’re glad Microsoft has finally taken action to block it.
To use the PreviousMode technique, attackers need to know the address of the KTHREAD structure for the current thread. The exploit obtains this address using a well-known function that reveals information about the kernel address space – NtQuerySystemInformation. The first argument of this function is the class of the requested system information. This function supports several classes of system information that are not mentioned in the documentation, and the exploit uses the SystemExtendedHandleInformation (0x40) class to obtain the desired address of the KTHREAD structure.
It is important to note that this NtQuerySystemInformation technique requires medium integrity level (Medium IL) to work. According to Microsoft, the availability of this information to Medium IL processes and users is part of the intended behavior. However, instances where the NtQuerySystemInformation API reveals kernel address space information for a Low IL process/user are considered a vulnerability and receive a CVE. An example of this is CVE-2021-31955 (SuperfetchPrivSourceQuery system information class) that was used in the PuzzleMaker APT Google Chrome attack chain. In our opinion, leaving this loophole open for Medium IL processes was a mistake, as it has been used in Medium IL -> System IL exploits for years. Therefore, we are very happy to see that this technique is finally blocked in new builds of Windows 11. However, we expect it to continue to be widely used in exploits for Windows 10 and Windows Server operating systems.
With these two techniques the whole exploitation process looks like this:
- The exploit uses the NtQuerySystemInformation technique to get the address of the PreviousMode flag for the current thread.
- Uses the same technique to get addresses of tokens for current and system processes.
- Uses the same technique to get the address of the ClfsSetEndOfLog It’s a “dummy” function that prevents an exception from being thrown further down the code.
- Allocates the buffer at address 0x40000000.
- Arranges the necessary data in the allocated buffer at the required offsets.
- Triggers the vulnerability and decrements the PreviousMode flag value from 1 to 0.
- Uses NtReadVirtualMemory/NtWriteVirtualMemory to overwrite the token and gain system privileges.
Use the following link to read the next part: