This is part five 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 skip to the other parts using this table of contents or using the link at the end of this part.
The October changes complicated the exploitation of the GENERAL block, and the author of the previously discussed exploits switched to exploiting the CONTROL block. CVE-2023-23376 was discovered as a zero-day in the wild by the Microsoft Threat Intelligence Center (MSTIC) and the Microsoft Security Response Center (MSRC). It was fixed in February 2023.
To discuss this vulnerability, we need to take a closer look at the CLFS_CONTROL_RECORD structure. As mentioned in part one of our study that discussed CLFS internals, it is used to hold an array of CLFS_METADATA_BLOCK structures with information about all the blocks present in the file, and also contains additional fields used to change the size of blocks. We are interested in the fields associated with the block extension operation: eExtendState – state of operation (None (0) / Extending (1) / Flushing (2)); iExtendBlock – index of the block being extended; iFlushBlock – index of the block being written; cNewBlockSectors – size of the new block (in sectors); cExtendStartSectors – original block size; cExtendSectors – number of sectors added.
When the driver opens an existing BLF file, the CClfsBaseFilePersisted::OpenImage function checks whether the interrupted block expansion operation should continue.
CClfsBaseFilePersisted::OpenImage function
This function checks the iExtendBlock and iFlushBlock indexes – they should be less than six. Otherwise, the block pointer will be read outside the block map buffer m_rgBlocks in the ExtendMetadataBlock function.
It’s important to note that the ExtendMetadataBlock function does not check the iExtendBlock and iFlushBlock indexes. The indexes are only checked by the OpenImage function that calls ExtendMetadataBlock. However, the ExtendMetadataBlock function is called in other functions that do not check indexes. It is assumed that “bad” indexes can only be passed from a file on disk, and the checks in OpenImage should protect against this. Could anything go wrong? Yes. If code uses malicious CLFS_CONTROL_RECORD or “bad” indexes after the initial check in OpenImage, this can be exploited to pass an arbitrary address as a pointer to a block and use it to escalate privileges.
It’s also worth mentioning that exploitation of CLFS_CONTROL_RECORD is not entirely new. The same attack method was previously described in the Exodus Intelligence blog post dedicated to the exploitation of CVE-2021-36955/CVE-2021-36963/CVE-2021-38633. The author of the exploit most likely read that blog post and realized that the ExtendMetadataBlock function could be exploited again using the same tricks from the GENERAL block exploit.
The exploit patches many bytes in a freshly created BLF file:
Overlap of new signatures data array with existing block header
As a result of the changes made in steps 1 and 5, the record offset now overlaps the location of the original bytes for sector #0, and the sector #0 signature now partially overlaps CLFS_CONTROL_RECORD->DumpCount.
Overlap of the CLFS_CONTROL_RECORD->DumpCount field with the signature for sector #0
As you may have already guessed, the root cause of this vulnerability is almost identical to the root cause of the vulnerability from exploit #2. The main difference is that the exploit now targets CLFS_CONTROL_RECORD instead of CLFS_BASE_RECORD_HEADER. The RecordOffsets[0] and DumpCount fields are now connected by the signature of sector #0, resulting in the following:
As a result, the exploit manages to pass “bad” iExtendBlock and iFlushBlock indexes, forcing the code to use a pointer sprayed into memory as the pointer of the block. The WriteMetadataBlock function, called from the ExtendMetadataBlock function, uses the pointer of the block to increment the DumpCount field, allowing an arbitrary value to be incremented in memory. On operating systems that support the PreviousMode technique, it is exploited by corrupting another BLF file and then following the same exploitation process as all the other exploits described previously. On newer builds of Windows 11 that do not support the PreviousMode technique, it is exploited by corrupting pipe attribute fields and building an arbitrary read/write primitive via the NtFsControlFile API function.
Use the following link to read the next part: