The sample most probably related to CVE-2022-24521 which is related to CLFS parsing bug.
The vulnerability is due to the parsing issue of the CLFS on specially crafted log file (.BLF / Base Log File) which allow user to alter the kthread.previous_mode
and enable write permission on kernel memory address, in this case is token replacement.
Please correct me if there is some misinformation in the post!
General exploitation flow:
- Create 2 buffer that contains the address to setup the gadget
ClfsSetEndofLog
andprevious mode
address - Create a new log file with a new container
- Modify the log file with specific value which in
ulAbove
_CLFSHASHSYM of the container context
- Zero out
CLFS_NODE_ID
of container context (0xC1FDF008, which is next to _CLFSHASHSYM)
- Changing
Reserved LSN 1 / CClfsContainer
in container context with hard coded address (0x40000000)
- Changing the first 4 bytes of Shared Security Descriptor Symbol Hash Table
- Re-calculating the crc32 hash of the log content
- Value of
previous mode
will be decrease from 1 to 0 viaObfDereferenceObject
which is located insideCClfsLogFcbPhysical::CloseContainers
->CClfsContainer::Close
- Using
NtWriteVirtualMemory
to replace the user token to system (PID 4) token - Set
Previous Mode
0 to 1 usingNtWriteVirtualMemory
- Spawn new process with the escalated privilege (The token is inherited from parent process)
Setting up for vulnerability
It first creates 2 virtual memory regions with fixed address which does the following:
- A modded memory buffer that will access by the CClfsContainer::Close
later. e.g. 0x40000000
- Contains address to gadget ClfsSetEndofLog
which is inside the modded memory buffer. e.g. 0x50000000 inside 0x40000000
Here you can see that there is a weird +0x30
in previous mode
address which you will see its purpose in ObfDereferenceObject
.
Before triggering the vulnerability, it creates a new container file using AddLogContainer
and then reopen the log file and modify them with some value which including the hard-coded virtual memory address. The crc32 hash will be calculated afterwards.
Triggering the vulnerability
The vulnerability triggers when the user open the modified log file and close it again after all required memory content has been modified. The vulnerability is trigger inside CClfsLogFcbPhysical::Initialize
(When open the log file) to load the modded container context buffer into kernel memory and CClfsLogFcbPhysical::CloseContainers
(When close the log file) where it parse and read the specially crafted memory region inside the modified log file.
First in CClfsLogFcbPhysical::Initialize
, CClfsBaseFile::AcquireClientContext
is crucial steps to setting up the vulnerability by modify the flow of the clfs code in order to load the modded buffer of the container context into kernel memory.
Inside CClfsBaseFile::GetSymbol
(one of the child function of CClfsBaseFile::AcquireClientContext
), it will read the first 4 bytes of ulAbove
and compare with first 4 bytes of Shared Security Descriptor Symbol Hash Table. If it is same, it will continue to fetch the container context (contains hard-coded address of 0x40000000) inside the kernel memory for later use.
* Where is the CClfsBaseFile::GetSymbol ?
CClfsLogFcbPhysical::Initialize -> CClfsBaseFile::AcquireClientContext -> CClfsBaseFile::GetSymbol
After finished running CClfsBaseFile::AcquireClientContext
, the container_context
variable (0xC1FDF008, _CLFS_NODE_ID
in exact) will be check whether it is empty. Since, the it has been modified in earlier stage, it will just pass and proceed to load more data into the temporary storage memory.
The data will load into a CClfsLogFcbPhysical
struct including the hard-coded 0x40000000 which will be read by CClfsLogFcbPhysical::CloseContainers
later.
After finishing the call of CClfsLogFcbPhysical::Initialize
, CClfsLogFcbPhysical::CloseContainers
will comes into the play to decrease the previous_mode
into zero.
The CClfsContainer::Close
(inside CClfsLogFcbPhysical::CloseContainers
) is the part where previous mode
decrease into 0 via ObfDereferenceObject
which is the main vulnerability triggered.
What is ObfDereferenceObject
actually?
This routine decrements the reference count of the specified object and does whatever cleanup there is if the count goes to zero.
In this case the 1 in the previous mode
will decrease to 0.
Figure below shows some of screenshot related to the deference of previous mode
Inside the ObfDereferenceObject
, it can see that the rsi
is actually the previous_mode+0x30
, you can verify with it also (shown in the left hand side of the screenshot below)
You can perform other check such as kthread structure via dt nt!_kthread <Addr of the kthread e.g. (Addr in 40000030/rsi) — 30 — 232>
After successfully to deference the previous mode
, it continue with CLFSSetEndOfLog
.
I guess the CLFSSetEndOfLog
just to prevent the execution of the CClfsLogFcbPhysical::Release
which will destroy the struct data of CClfsLogFcbPhysical
struct.
I will think like that because i didn’t see anything happens in CLFSSetEndOfLog
(Probably I’m just too lazy until this part of analysis 😪) as the code in IF statement will not be execute at last.
Then, it flows back to the exploit program and continue the overwriting of the low privilege token with high privilege token (PID: 4)
Finally, It will set the previous mode
back to 1 by calling NtWriteVirtualMemory
before spawn a new cmd.exe
process with privilege access.
Thoughts
It is quite interesting to perform some vulnerability analysis on the CLFS, even though it is quite difficult at first 😌 for a beginner like me. During the time of writing this blog, the publication of blog from zscaler really helps me a lot on understanding some things that I encountered in my analysis. Kudos to them!!!
Also, It is glad that I’m managed to analyze a windows exploit sample instead of just some day-to-day malware analysis. 🤪
I did skipped some details about how to get the correct token offset for different windows version, getting the previous mode
inside kthread
and getting _EPROCESS
for both system
and user
process using NtQuerySystemInformation (SystemExtendedHandleInformation).
References:
https://github.com/ionescu007/clfs-docs/blob/main/README.md
https://www.slideshare.net/PeterHlavaty/deathnote-of-microsoft-windows-kernel
http://blog.rewolf.pl/blog/?p=1683
https://www.nirsoft.net/kernel_struct/vista/KTHREAD.html
https://www.codewarrior.cn/ntdoc/wrk/ob/ObfDereferenceObject.htm