Updated April 20, 2023
In February 2023, Kaspersky technologies detected a number of attempts to execute similar elevation-of-privilege exploits on Microsoft Windows servers belonging to small and medium-sized businesses in the Middle East, in North America, and previously in Asia regions. These exploits were very similar to already known Common Log File System (CLFS) driver exploits that we analyzed previously, but we decided to double check and it was worth it – one of the exploits turned out to be a zero-day, supporting different versions and builds of Windows, including Windows 11. The exploit was highly obfuscated with more than 80% of the its code being “junk” elegantly compiled into the binary, but we quickly fully reverse-engineered it and reported our findings to Microsoft. Microsoft assigned CVE-2023-28252 to the Common Log File System elevation-of-privilege vulnerability, and a patch was released on April 11, 2023, as part of April Patch Tuesday.
While the majority of zero-days that we’ve discovered in the past were used by APTs, this particular zero-day was used by a sophisticated cybercrime group that carries out ransomware attacks. This group is notable for its use of a large number of similar but unique Common Log File System (CLFS) driver exploits that were likely developed by the same exploit author. Since at least June 2022, we’ve identified five different exploits used in attacks on retail & wholesale, energy, manufacturing, healthcare, software development and other industries. Using the CVE-2023-28252 zero-day, this group attempted to deploy the Nokoyawa ransomware as a final payload.
Nokoyawa ransom note
The attacker must be authenticated with user access and have the ability to run code on the target system to launch the elevation-of-privilege exploit.
CLFS is a log file subsystem that was first introduced in Microsoft Windows Server 2003 R2 / Microsoft Vista and is implemented in the clfs.sys driver. This file system can be used by any application and Microsoft provides an API for it. Logs are created using the CreateLogFile function – a log is made up of a base log file (.blf file name extension) that is a master file containing metadata, and a number of containers that hold the actual data. Containers are created using the AddLogContainer and AddLogContainerSet functions. As you may already guess, the base log files are the most interesting to look at. But while Microsoft provides an API for working with them, their file format is undocumented, and developers should interact with them only through the CLFS API. The file structure of base log files, when viewed briefly in a hex editor, does not seem very complicated, and Microsoft provides debug symbols for clfs.sys, so with a sufficient level of enthusiasm this format can be reverse engineered (already done by Alex Ionescu). A glance at the structure of base log files instantly raises a red flag – the file consists of kernel structures as it is, and there are even fields for storing memory pointers! Combine that with the fact that, according to the API documentation, this technology is quite complicated, plus it was developed a long time ago, and we have a large number of vulnerabilities as a result. Searching for “Windows Common Log File System Driver Elevation Of Privilege Vulnerability” shows that there have been at least thirty-two such vulnerabilities (not counting CVE-2023-28252) discovered since 2018, where three of them were detected in the wild as zero-days (CVE-2022-24521, CVE-2022-37969, CVE-2023-23376).
CVE-2023-28252 is an out-of-bounds write (increment) vulnerability that can be exploited when the system attempts to extend a metadata block. The vulnerability is triggered by manipulating a base log file. At this time, we will not share the names of the fields or exact values that should be written to the file in order to trigger the vulnerability, as that information could facilitate further exploitation. This is to ensure that everyone has enough time to patch their systems before other actors develop their own exploits for CVE-2023-28252. Instead, we will share some general information about the vulnerability and the way of exploiting it.
The vulnerability is triggered in the CClfsBaseFilePersisted::ExtendMetadataBlock function when this function is executed with a call to the AddLogContainer API function. There is a condition for CClfsBaseFilePersisted::ExtendMetadataBlock function to be executed, and the base log file needs to be modified for that to happen. Besides, various fields in the CONTROL and CONTROL_SHADOW metadata blocks need to be patched. The exploit modifies LogBlockHeader->ValidSectorCount and various fields in LogBlockHeader->Record for both the CONTROL and CONTROL_SHADOW metadata blocks. As a result of these changes, the CClfsBaseFilePersisted::ExtendMetadataBlock function performs out-of-bounds access to the m_rgBlocks array, which contains only six elements. After that, the CClfsBaseFilePersisted::WriteMetadataBlock function will proceed to use the retrieved value from the m_rgBlocks array as a pointer to the _CLFS_LOG_BLOCK_HEADER structure to increment LogBlockHeader->Record->DumpCount and LogBlockHeader->Usn. This can be used to corrupt a kernel object in the memory and obtain kernel read/write privileges if the address of the desired victim object is sprayed in the right location in the memory.
The discovered exploit uses the vulnerability to corrupt another specially crafted base log file object in a way that a fake element of the base log file gets treated as a real one. _CLFS_CONTAINER_CONTEXT is an example of the structure that gets stored in base log files, but contains a field for storing a kernel pointer. Of course, the value of this field is ignored when the structure is read from the base log file on disk, but changing in memory the offset pointing to the valid _CLFS_CONTAINER_CONTEXT structure into an offset pointing to a specially crafted malicious _CLFS_CONTAINER_CONTEXT structure makes it possible to provide a pointer to a controlled memory in a user level and obtain kernel read/write privileges with it.
The exploit leaks the addresses of kernel objects to achieve stable exploitation. This is done using the NtQuerySystemInformation function – a technique that we previously saw in other zero-days (e.g. PuzzleMaker, MysterySnail APT cases). The information classes used by the exploit require Medium IL to work.
We believe that CVE-2023-28252 could have been easily discovered with the help of fuzzing. But there are already so many vulnerabilities found in this component, so if it’s discoverable by fuzzing, why has it not been found before? We have a possible explanation. Examining the clfs.sys driver code in disassembler shows extensive use of try/catch blocks to catch exceptions. In many parts of the code when an exception occurs it gets masked by an exception handler and the code continues its normal execution like nothing happened. We verified that with CVE-2023-28252 a possible access violation that follows after triggering the vulnerability is masked by an exception handler. This makes us think that previously fuzzers were actually hitting this vulnerability, but because there was no crash it continued to be undiscovered. For effective fuzzing, it’s necessary to keep in mind the possibility of such a scenario and to take steps to prevent it.
Post exploitation and malware
We see that the main purpose of using elevation-of-privilege exploits was to dump the contents of the HKEY_LOCAL_MACHINE\SAM registry hive.
As for the malware, attackers use Cobalt Strike BEACON as their main tool. It’s launched with a variety of custom loaders aimed to prevent AV detection.
In some of the other attacks that we attribute to the same actor, we also observed that, prior to exploiting the CLFS elevation-of-privilege vulnerability, the victim’s machines were infected with a custom modular backdoor named “Pipemagic” that gets launched via an MSBuild script. At the end of last year, we published a private report about this malware for customers of the Kaspersky Intelligence Reporting service.
In attacks using the CVE-2023-28252 zero-day, this group attempted to deploy Nokoyawa ransomware as a final payload. Yearly variants of Nokoyawa were just “rebranded” variants of JSWorm ransomware, which we wrote about previously. In this attack, cybercriminals used a newer version of Nokoyawa that is quite distinct from the JSWorm codebase. It’s written in C and has encrypted strings. It was launched with an encrypted json config provided with a “–config” command line argument.
Decrypted and formatted config of Nokoyawa ransomware
We see a significantly increasing level of sophistication among cybercriminal groups. We don’t often see APTs using zero-day exploits in their attacks, and now there are financially motivated cybercriminal groups that have the resources to acquire exploits for unknown vulnerabilities and routinely use them in attacks. Moreover, there are developers willing to help cybercriminal groups and to produce one exploit after another.
We detect the CVE-2023-28252 exploit and related malware with the verdicts:
Kaspersky products detected these attacks with the help of the Behavioral Detection Engine and the Exploit Prevention component. CVE-2023-28252 is the latest addition to the long list of zero-days discovered in the wild with the help of our technologies. We will continue to improve defenses for our users by enhancing technologies and working with third-party vendors to patch vulnerabilities, making the internet more secure for everyone.
More information about this and related attacks is available to customers of the Kaspersky Intelligence Reporting service. Contact: firstname.lastname@example.org.
Kaspersky would like to thank Microsoft for their prompt analysis of the report and patches.
Indicators of compromise
After finishing, the exploit leaves files used for exploitation at the hard-coded path in the “C:\Users\Public\” folder. Companies can check if the exploit was launched on their servers or employees’ machines by looking for the presence of the “C:\Users\Public\.container*”, “C:\Users\Public\MyLog*.blf”, and “C:\Users\Public\p_*” files.