CVE-2022-24521 — CLFS CLIENT_CONTEXT/CONTAINER_CONTEXT Overlap → Arbitrary Decrement
Last updated: 2026-04-10
Component: clfs.sys
Bug Class: OOB write (structure overlap viacbSymbolZone) → controlled vtable → arbitrary decrement
Patch: April 2022 Patch Tuesday
Exploited ITW: Yes — April 2022 (Kaspersky + Microsoft attribution)
Exploit Author: Same threat actor as CVE-2022-37969, CVE-2023-23376, CVE-2023-28252
Related: Clfs, Cve 2022 37969, Cve 2023 28252, Primitives
Tags:clfs,oob-write,structure-overlap,arbitrary-decrement,previousmode,kernel-mode,lpe
Summary
CVE-2022-24521 is the first CLFS zero-day captured in the wild by Kaspersky GReAT in the sustained 2022–2023 CLFS ransomware campaign. Root cause: cbSymbolZone (the “next free slot” pointer in the General metadata block) is set to an offset that overlaps an existing CLFS_CLIENT_CONTEXT structure. When the exploit calls AddLogContainer(), a new CLFS_CONTAINER_CONTEXT symbol is written at cbSymbolZone, partially overwriting CLFS_CLIENT_CONTEXT fields. When FlushMetadata restores cached client values, the CClfsContainer kernel pointer in CLFS_CONTAINER_CONTEXT is overwritten with attacker-controlled data.
This is the foundational vulnerability in a 5-CVE series by the same exploit author.
Root Cause
Setup: Manipulating cbSymbolZone
The General metadata block header (CLFS_BASE_RECORD_HEADER) contains cbSymbolZone — the offset of the next free byte for new symbol allocations. Normally this points past all existing symbols.
The exploit patches cbSymbolZone (at file offset 0x1B98) to point into the middle of an existing CLFS_CLIENT_CONTEXT structure.
BLF patch sequence:
Offset 0x1B98 cbSymbolZone → set to overlap target CLFS_CLIENT_CONTEXT
Additional: "fake" CLFS_CONTAINER_CONTEXT structure built at the overlap position
Key requirement for the overlap to work:
CLFS_CLIENT_CONTEXT.llCreateTimemust be set to0x40000000- This value is read back as the
CClfsContainer*pointer when the structure overlap occurs 0x40000000is within a user-mode-accessible mapped region (the heap spray target)
- This value is read back as the
Structure Overlap Mechanics
- Open the crafted BLF → CLFS caches
CLFS_CLIENT_CONTEXTfields in memory (includingllCreateTime = 0x40000000) - Call
AddLogContainer()→CClfsBaseFilePersisted::AddSymbol → AllocSymbolwrites a newCLFS_CONTAINER_CONTEXTstarting atcbSymbolZone(which is inside the existingCLFS_CLIENT_CONTEXT) - Now
CLFS_CLIENT_CONTEXTandCLFS_CONTAINER_CONTEXToverlap in the block image - The
pContainerfield ofCLFS_CONTAINER_CONTEXToccupies the same bytes asllCreateTimeofCLFS_CLIENT_CONTEXT→pContainer = 0x40000000 CClfsLogFcbPhysical::FlushMetadatarestores cachedllCreateTimevalue into the block → overwritespContainerback to0x40000000(attacker-controlled)- When the container is closed/cleaned up →
CClfsContainer*is dereferenced → vtable dispatch to0x40000000
Exploit Primitive: Arbitrary Decrement via ObDereferenceObject
The controlled vtable at 0x40000000 is crafted to call ObDereferenceObject with an attacker-controlled argument:
// Heap spray at 0x40000000 — fake CClfsContainer object:
vtable_ptr = &fake_vtable; // fake_vtable+N → ObDereferenceObject gadget
// When vtable dispatch fires:
ObDereferenceObject(target_address);
ObDereferenceObject decrements the reference count field of any kernel object. Called on an attacker-specified address X:
- Decrements
*Xby1(at the reference count offset+0x18in theOBJECT_HEADER) - If
X = KTHREAD.PreviousMode_address - 0x18, thenKTHREAD.PreviousModeis decremented
PreviousMode Decrement → Arbitrary Kernel R/W
KTHREAD.PreviousMode at offset 0x232 (_KTHREAD.PreviousMode — validated via NtQuerySystemInformation(SystemExtendedHandleInformation, 0x40) to get the KTHREAD address):
- Locate current
KTHREADaddress viaNtQuerySystemInformation(0x40)→SYSTEM_HANDLE_INFORMATION_EX→ find current thread handle →Objectfield =ETHREAD* - Calculate
KTHREAD.PreviousMode - 0x18as the argument toObDereferenceObject ObDereferenceObjectdecrements1 → 0atPreviousMode→KernelMode- Now
NtReadVirtualMemory/NtWriteVirtualMemoryaccept kernel addresses directly - Walk
EPROCESS.ActiveProcessLinksto find SYSTEM process (PID 4), copyTokento current process
Key Data Structures (Exploit Offsets)
CLFS_CLIENT_CONTEXT key fields (at overlap target):
+0x00 cidNode.cType = 0x07 (CLFS_NODE_TYPE_CLIENT_CONTEXT)
+0x04 cidNode.cbNode = size
+0x08 cidClient USHORT
+0x0A fAttributes USHORT ← overlap with CONTAINER_CONTEXT header
...
+0x10 llCreateTime ULONGLONG = 0x40000000 ← becomes pContainer in overlap
CLFS_CONTAINER_CONTEXT fields when overlapped at cbSymbolZone:
+0x00 cidNode.cType = 0x09 (CLFS_NODE_TYPE_CONTAINER_CONTEXT)
+0x04 cidNode.cbNode
+0x08 cbContainer
+0x10 cidContainer/cidQueue
+0x18 pContainer → inherits llCreateTime value (0x40000000)
Exploit Flow
1. CreateLogFile("MyLog.blf") with patched cbSymbolZone → opens crafted BLF
→ CLFS caches CLIENT_CONTEXT fields (llCreateTime = 0x40000000)
2. Heap spray at 0x40000000:
→ fake CClfsContainer vtable
→ vtable[N] = gadget → ObDereferenceObject(KTHREAD.PreviousMode - 0x18)
3. AddLogContainer() → AllocSymbol writes CONTAINER_CONTEXT at cbSymbolZone
→ pContainer field overlaps with llCreateTime → pContainer = 0x40000000
4. FlushMetadata restores cached CLIENT_CONTEXT → llCreateTime copied back
→ CONTAINER_CONTEXT.pContainer confirmed = 0x40000000
5. Close container / trigger cleanup:
→ CClfsBaseFilePersisted::RemoveContainer
→ calls virtual function on fake CClfsContainer(0x40000000)
→ ObDereferenceObject(KTHREAD.PreviousMode - 0x18)
→ KTHREAD.PreviousMode: 1 → 0
6. Token steal via NtReadVirtualMemory / NtWriteVirtualMemory (PreviousMode=0)
→ SYSTEM privilege
Affected Versions
- Windows 10 (all builds before April 2022 patch)
- Windows 11 (builds before April 2022 patch)
Patch Analysis
The patch added validation in CClfsBaseFilePersisted::LoadContainerQ checking that cbSymbolZone + end_of_CLFS_BASE_RECORD_HEADER does not overlap with existing symbols or exceed valid bounds.
However, the same vulnerability pattern existed in adjacent code (CONTROL block instead of GENERAL block) → CVE-2023-23376.
CVE Series Context
This is Exploit #1 in the Kaspersky 5-CVE series (Boris Larin). The exploit author reused nearly identical techniques across all 5 CVEs:
- Exploit #1 (CVE-2022-24521): GENERAL block, llCreateTime=0x40000000, ObDereferenceObject decrement
- Exploit #2 (CVE-2022-37969): Different trigger for same pContainer corruption
- Exploit #3 (Oct 2022): cbSymbolZone manipulation (variant of Exploit #1)
- Exploit #4 (CVE-2023-23376): CONTROL block targeting
- Exploit #5 (CVE-2023-28252): ValidSectorCount=1 → shadow fallback
References
- Kaspersky GReAT / Boris Larin — “Windows CLFS and five exploits (Exploit #1 — CVE-2022-24521)” — securelist.com, 2023-12-21
- Microsoft MSRC — CVE-2022-24521 advisory — April 2022
