Exploiting a use-after-free in Windows Common Logging File System (CLFS)
A UAF in the Common Logging File System (CLFS). Some background is needed on how this custom filesystem works to provide context for the bug. All Base log files contain 3 different metadata blocks that are parsed when opening log files; Control records, which contain layout information and extended area info. Base records, which have symbol tables and other information like security context info. Finally, there’s truncate records, which contain info regarding sector changes for truncation ops. Each of these blocks also has a “shadow block” associated with it, where the metadata is essentially duplicated and backed up for restoration upon an event such as a torn write.
It’s also worth noting that it’s possible for blocks to be “extended” depending on how the control record is setup with it’s various sector offsets. The eExtendState
field is kept track of when operating on a log file.
The bug
Under normal circumstances, a stable logfile when being read from the disk will always have an extension state of ClfsExtendStateNone
or 0
. However, an attacker has full control over the metadata blocks, and can force them to be parsed as extended by manipulating the control record. Additionally, an attacker also has control over the index of the block to be extended or flushed via the extend context. By setting up a specially crafted file and getting ExtendMetadataBlockDescriptor()
called in the open path, it’s possible to reach a branch that will flush and free a targeted block’s pbImage
. Just after that free, the record will then be updated and refreshed with the contents from the that block’s mirroring shadow block. The problem is, the shadow block’s pbImage
points to the same memory that was just free’d, re-introducing a dangling reference.
This opens up the possibility to double free, which can be used to poison the pool allocator into granting a targeted use-after-free. In this case, they use the Windows Notification Facility (WNF) and the double free to overlap some state data objects, which they then use to get an out-of-bounds read/write to smash adjacent state data objects. This can be leveraged to change the size of an adjacent state data object in order to have it overlap with a token when free’d, which can be used to corrupt a process token to privilege escalate.