This is part six 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 parts first if you haven’t already.
You can go to other parts using this table of contents:
April 2023 brought a patch for yet another CLFS zero-day – CVE-2023-28252. It’s the last one we are going to discuss in this study. It was captured in the wild by yours truly Boris Larin (oct0xor) with Kaspersky, Genwei Jiang with Mandiant and Quan Jin with DBAPPSecurity WeBin Lab. This patch was released exactly one year after the release of the patch for CVE-2022-24521 used in exploit #1.
On Patch Tuesday in April 2023, we published a brief report about Nokoyawa ransomware attacks using this zero-day, as well as details about the exploit itself. Eight days later we updated the post with details about the vulnerability, but we decided not to go into too much detail to avoid helping other attackers develop an exploit while everyone was updating. Now that a few months have passed since the patch was released, let’s take a closer look at the root cause of the vulnerability.
Exploit #5 (CVE-2023-28252) is very similar to exploit #4 (CVE-2023-23376). The new exploit also targets CLFS_CONTROL_RECORD, and it also aims to bypass iExtendBlock and iFlushBlock index verification. In fact, both exploits are almost identical, the only difference being the patches made to the BLF file. But although the exploits are almost identical, the root causes of both vulnerabilities are completely different. CVE-2023-28252 can also be considered a logical vulnerability, like all those previously discussed, but it is not similar to any of them because it does not involve overlapping any structures.
The exploit makes these patches to the BLF file:
To understand the vulnerability, let’s take a closer look at how blocks are read from disk. This is done by the ReadMetadataBlock function, which is quite large. It reads the requested block and its SHADOW version and decides which one to use. A simplified code for this decision process is shown in the image below.
Simplified code that decides whether to use a block or its SHADOW version
If both blocks are OK, the newest one is used (the one with the higher DumpCount). If one block is OK and the other is not, the valid one is used. If both blocks are not OK, the code returns an error.
The decision whether a block is OK or not is made by the ClfsDecodeBlock function. It’s shown in the image below.
ClfsDecodeBlock function
It checks whether the block has a valid checksum or is in an older format, but additional checks are performed in the ClfsDecodeBlockPrivate function.
ClfsDecodeBlockPrivate function
It has additional version checks, checks the TotalSectorCount, checks the flags and, if all is well, replaces the sector signatures with the original bytes.
Now let’s take a look at the ClfsEncodeBlock function, which is used when writing blocks to disk. The code for this function is shown in the image below.
ClfsEncodeBlock function
It doesn’t check anything, clears the checksum and proceeds to call ClfsEncodeBlockPrivate. This function performs some checks.
ClfsEncodeBlockPrivate function
What immediately catches the eye is the inconsistency of the checks in ClfsDecodeBlock(Private)/ClfsEncodeBlock(Private). The ClfsEncodeBlockPrivate function also checks the TotalSectorCount and the flags, but unlike ClfsDecodeBlockPrivate it also checks the ValidSectorCount. So if a block has an invalid ValidSectorCount, it will be decoded without problems, but the code will not be able to encode it later. The last piece of the puzzle becomes clear when we see how the ClfsEncodeBlock function is used in the WriteMetadataBlock function.
WriteMetadataBlock function
The WriteMetadataBlock function does not check the return value of the ClfsEncodeBlock function, so if it corrupts the block by clearing its checksum and returning an error due to an invalid ValidSectorCount value, the code will continue its normal execution. This leads to:
The rest of the exploitation process is exactly the same as exploit #4.
As expected, some of the vulnerabilities discussed in this study were actually variants of previously known issues and may not have existed if they had been properly patched in the first place.
As for the Common Log File System (CLFS), this is a good example of how not to design a file format. I’m actually surprised it still exists in its current form. After so many vulnerabilities and captured zero-days, is it now completely secure? Since the release of the patch for CVE-2023-28252 in April 2023, several other CLFS vulnerabilities have been patched.
At the same time, we are very grateful to Microsoft for their work in blocking the PreviousMode and NtQuerySystemInformation techniques. Over the last couple of years, we have seen a spate of zero-day exploits used by cybercriminals to escalate privileges from Medium IL to System IL, and blocking these techniques will make new versions of Windows 11 more resistant to such exploits.
In the meantime, we continue to closely monitor cybercriminal exploitation of vulnerabilities and hunt for actively exploited zero-days.