CVE-2023-23376 — CLFS CONTROL Block OOB via DumpCount/Sector Signature Overlap
Last updated: 2026-04-10
Component: clfs.sys
Bug Class: OOB write — corrupt index bypass via CONTROL block signature overlap
Patch: February 2023 Patch Tuesday
Exploited ITW: Yes (discovered by Microsoft MSTIC/MSRC as zero-day)
Exploit Author: Same as CVE-2022-24521, CVE-2022-37969 (Exploit #3), CVE-2023-28252
Related: Clfs, Cve 2022 24521, Cve 2023 28252, Primitives
Tags:clfs,oob-write,control-block,iextendblock,iflushblock,kernel-mode,lpe
Summary
CVE-2023-23376 is Exploit #4 in the Kaspersky 5-CVE series. The October 2022 CLFS patch hardened validation of the GENERAL block, so the exploit author switched to the CONTROL block. Root cause: ExtendMetadataBlock does not validate iExtendBlock/iFlushBlock indexes — only OpenImage does, and only on initial open. A crafted BLF causes these indexes to become malicious after the initial check, resulting in OOB access into m_rgBlocks[] with a fully controlled pointer.
Background: CLFS_CONTROL_RECORD Fields
CLFS_CONTROL_RECORD key fields:
eExtendState ULONG // 0=None, 1=Extending, 2=Flushing
iExtendBlock USHORT // index of block being extended
iFlushBlock USHORT // index of block being flushed
cNewBlockSectors ULONG // new block size (sectors)
cExtendStartSectors ULONG // original block size
cExtendSectors ULONG // sectors to add
rgBlocks[6] CLFS_METADATA_BLOCK[] // all 6 block descriptors
ExtendMetadataBlock uses iExtendBlock and iFlushBlock as indexes into m_rgBlocks[6]. Without bounds checking, an index of 0x13 = 0x13 * sizeof(CLFS_METADATA_BLOCK) bytes past m_rgBlocks[0] → OOB read → controlled pointer.
Root Cause: Index Check Only in OpenImage
// CClfsBaseFilePersisted::OpenImage checks:
if (iExtendBlock >= 6 || iFlushBlock >= 6)
return error;
// ExtendMetadataBlock does NOT check:
block = m_rgBlocks[iExtendBlock]; // OOB if iExtendBlock > 5
Attack vector: Get malicious iExtendBlock/iFlushBlock values past the OpenImage check but before a second call to ExtendMetadataBlock. This is achieved by making RecordOffsets[0] and DumpCount alias the same bytes.
Exploit Mechanism: Sector Signature Overlap
Setup Patches (crafted BLF):
Move
CLFS_CONTROL_RECORDto offset0x1FFwithin the CONTROL block so that theDumpCountfield aligns with where the sector #0 signature (at0x1FE) will be written duringClfsDecodeBlockSet
eExtendState,iExtendBlock,iFlushBlockto triggerExtendMetadataBlockfromOpenImage(first call — malicious values blocked by index check, but legitimate values used)Build malicious
CLFS_CONTROL_RECORDat offset0x2FFwithiExtendBlock = iFlushBlock = 0x13(or another large OOB value)Patch
SignaturesOffset: Change from0x3F8to0x28— moves the signatures restoration array from the last sector to the block header itself (sector #0 signature will aliasCLFS_CONTROL_RECORD->DumpCount)Increase
cbSymbolZonein the GENERAL block (same as prior exploits) soExtendMetadataBlockis called again whenAddLogContaineris called
Execution Flow
1. OpenImage opens BLF:
→ ClfsDecodeBlock restores sector #0 signature bytes
→ Sector #0 signature (2 bytes at 0x1FE in block = DumpCount offset) gets value 0x1FF
→ OpenImage checks iExtendBlock/iFlushBlock → still valid → ExtendMetadataBlock runs
→ ExtendMetadataBlock increments DumpCount → word at 0x1FE becomes 0x2FF
→ FlushMetadata → WriteMetadataBlock → ClfsEncodeBlock
→ ClfsEncodeBlock copies updated sector #0 original bytes back to RecordOffsets[0]
→ RecordOffsets[0] (alias of sector #0 original byte at 0x50+0) = 0x2FF
2. AddLogContainer triggers cbSymbolZone extension:
→ ExtendMetadataBlock called again
→ GetControlRecord reads from RecordOffsets[0] = 0x2FF → malicious CLFS_CONTROL_RECORD
→ iExtendBlock = iFlushBlock = 0x13 — no check here!
→ WriteMetadataBlock uses m_rgBlocks[0x13] (OOB, attacker-controlled pointer)
→ DumpCount field of OOB block is incremented → arbitrary increment primitive
Post-Corruption Exploitation
Arbitrary increment primitive: m_rgBlocks[0x13].pbImage points to attacker spray. WriteMetadataBlock increments DumpCount at spray_address + DUMP_COUNT_OFFSET.
Win10 path: Use arbitrary increment to decrement KTHREAD.PreviousMode (1 → 0) → NtRead/WriteVirtualMemory bypass → token steal
Win11 path: Corrupt PipeAttribute structure (AttributeValueSize field) to build AAR/AAW primitive via NtFsControlFile(0x11003C/0x110038):
- Spray pipe attributes with known kernel address of
AttributeValueSize - Use increment to set
AttributeValueto point to target kernel address - Read/write kernel data via pipe attribute I/O
BLF Patches Required
| Location | Field | Change |
|---|---|---|
| CONTROL block +0x1FF | CLFS_CONTROL_RECORD moved here | Offset shift for DumpCount ↔ signature alias |
| CONTROL block +0x2FF | Malicious CLFS_CONTROL_RECORD | iExtendBlock = iFlushBlock = 0x13, forged pointer |
| CONTROL block header | SignaturesOffset | 0x3F8 → 0x28 (signatures alias block header) |
| GENERAL block +0x1B98 | cbSymbolZone | Large value to trigger second ExtendMetadataBlock |
| CONTROL/SHADOW | DumpCount | SHADOW lower than CONTROL (so CONTROL is selected initially) |
CVE Series Context
- The October 2022 patch added
CClfsBaseFile::Validate*functions for GENERAL block bounds checking - The exploit author simply switched to the CONTROL block (which lacks equivalent validation)
- CVE-2023-28252 (Exploit #5) uses a completely different trigger for the same ultimate goal of making
iExtendBlock/iFlushBlockOOB at the momentExtendMetadataBlockruns
References
- Kaspersky GReAT / Boris Larin — “Windows CLFS and five exploits (Exploit #4 — CVE-2023-23376)” — securelist.com, 2023-12-21
- Exodus Intelligence — “Exploiting CVE-2021-36955/36963/38633” — first description of CONTROL_RECORD targeting pattern, March 2022
