Preface
Recently, I analyzed some past security vulnerabilities in clfs.sys out of boredom. In the Windows operating system kernel, the Common Log File System (CLFS) provides a service for logging. Due to the complexity of CLFS and the design characteristics of its driver clfs.sys, security vulnerabilities have been found multiple times in history. This article will analyze the security vulnerability CVE-2022-35803 in CLFS in depth, which allows attackers to bypass Microsoft's previous repair for CVE-2022-24481 through a type confusion issue, and then achieve privilege escalation.
Firstly, let's start with the analysis of CVE-2022-24481, explaining its principles and Microsoft's repair measures, and then introduce how to bypass the repair through the technical means of type confusion and finally achieve privilege escalation. Through this process, we will delve into the working principle of CLFS and how to achieve attack objectives by utilizing specific data structures and kernel behaviors.

Without further ado, let's get straight to the point!
Analysis of the old vulnerability: CVE-2022-24481
In CLFS, the CLFS_BASE_RECORD_HEADER structure is used to represent the basic record header:
The fields rgClients and rgContainers in the structure are used to represent a 32-bit array, which stores the offset of each client context and container context. Users can modify them on the disk. The root cause of the vulnerability is the lack of effective validation of client offsets, which leads to overlap between client context and container context. As a result, modifying the client context by clfs.sys will simultaneously change the next container context.
The instance sample will trigger the function CClfsLogFcbPhysical::FlushMetadata when the log file is closed:
The CClfsLogFcbPhy variable pointer named in the above code is an object of type CClfsLogFcbPhysical, which is initialized in the CClfsLogFcbPhysical::Initialize function and is called when the log file is opened.
In the carefully constructed CLFS log file, the attacker overlaps the llCreateTime field of the client context with the pContainer field of the container context and sets the llCreateTime field to an address in user space. After calling the CClfsLogFcbPhysical::FlushMetadata function, the pContainer field of the container context (which stores a kernel pointer to the CClfsContainer object at runtime) will be modified.
After FlushMetadata ends, clfs.sys will call the CClfsLogFcbPhysical::CloseContainers function to close the container:
After [1], pContainer will point to the attacker-controlled memory space (in user space). When calling CClfsContainer::Close [2], the internal function ObfDereferenceObject will be triggered, causing arbitrary address decrement. This technique is used in the field samples to reduce PreviousMode to zero, which causes the calling thread to be set from user mode to kernel mode, and ultimately allows the user to read and write arbitrary addresses in the kernel space through NtWriteVirtualMemory / NtReadVirtualMemory. After that, the user can achieve privilege escalation by overwriting the token field in the current process's _EPROCESS object to the address of the token in the system process's _EPROCESS object (the samples obtain these addresses through NtQuerySystemInformation).
Patch for CVE-2022-24481
By analyzing the patch, it can be seen that the fix for the vulnerability adds a check for the offsets of rgClients and rgContainers in CClfsBaseFile::ValidateRgOffsets:
The patch for the vulnerability introduced an important check in [3]. It requires the interval between the container context and the next context to be at least 0x30 + 12 * 4 = 0x60 bytes, and the interval between the client context and the next context to be at least 0x30 + 34 * 4 = 0x88 = 0xb8 bytes. However, in the CClfsLogFcbPhysical::FlushMetadata function, we can only modify the field located at offset 0x78 bytes (ClfsClientContext->eState). Therefore, the vulnerability was fixed by the added check.
How to bypass
By analyzing the patch, we can see that the issue of directly modifying the client context offset has been fixed. However, are there other ways that can lead to field overlap and trigger vulnerabilities?
Through research and analysis, it was found that during the process from validating offsets in ValidateRgOffsets to modifying data in FlushMetadata, and finally closing containers in CloseContainers, there was no check on the validity of the client context field cidNode.cType (representing the context type). This may lead to type confusion issues: if we set the cidNode.cType of the client context to 0xC1FDF008, when ValidateRgOffsets calculates, the interval between the client context and the next context will be incorrectly limited to 0x60 bytes, which will cause the fields from 0x60 to 0x88 bytes of the client context to overlap with the fields from 0 to 0x28 bytes of the next context. This creates a new vulnerability.
I reviewed CClfsLogFcbPhysical::FlushMetadata again and determined that the pContainer in the next container context can be modified through ClfsClientContext->eState.
As the original pContainer has been aligned to 0x10 bytes, this will make the pContainer field point to an 8-byte offset from the original container object's location, where the size of the container file is stored. This is achieved through the parameter p when the AddLogContainer function is called by the user.

评论已关闭