# CVE-2025-55680 — Windows Cloud Files Minifilter `cldflt.sys` TOCTOU Privilege Escalation

---

## Summary

| **Product**           | Microsoft Windows — `cldflt.sys` (Cloud Files Minifilter driver) |
|-----------------------|------------------------------------------------------------------|
| **Vendor**            | Microsoft Corporation |
| **Severity**          | Important (MSRC) — CVSS v3.1 **7.8 (High)**, temporal 6.8 |
| **CVSS Vector**       | `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C` ([MSRC](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-55680)) |
| **CVE Title**         | Windows Cloud Files Mini Filter Driver Elevation of Privilege Vulnerability (MSRC) |
| **Affected Versions** | Windows 10/11 and Server releases shipping `cldflt.sys` with the vulnerable `HsmpOpCreatePlaceholders` (bug present since at least the CVE-2020-17136 fix era) |
| **Tested Version**    | Windows 11 24H2 — cldflt.sys 10.0.26100.6725 (pre-patch) vs 10.0.26100.6899 (post-patch) |
| **Impact**            | Elevation of Privilege — arbitrary file/directory creation anywhere on the system with kernel (`OBJ_KERNEL_HANDLE`) privileges, i.e. effectively SYSTEM (writeup says "privilege escalation" without naming SYSTEM; SYSTEM-level effect inferred from the kernel-mode create — estimate) |
| **CVE ID**            | CVE-2025-55680 |
| **CWE**               | CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition |
| **PoC Available**     | Yes (trigger PoC below, reconstructed from the Exodus Intelligence writeup) |
| **Exploit Available** | No public full exploit; Exodus disclosed the complete technique. MSRC: not exploited, not publicly disclosed pre-patch; exploitability assessment "Exploitation More Likely" |
| **Patch Available**   | Yes |
| **Patch Date**        | October 14, 2025 — KB5066835 |
| **Discovered**        | March 2024, Michele Campa (Exodus Intelligence) |

---

## Root Cause

`HsmpOpCreatePlaceholders()` processes `CfCreatePlaceholders()` requests. The
placeholder payload — including the relative filename (`relName`) — lives in
a **userspace buffer owned by the calling process**. The driver maps that
buffer into kernel virtual address space with the standard MDL sequence:

```c
mdl = IoAllocateMdl(placeholderPayload, placeholderPayload_size, 0, 0, NULL);
ProbeForRead(placeholderPayload, placeholderPayload_size, 4);
MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
mapped = MmMapLockedPagesSpecifyCache(mdl, KernelMode, MmCached, NULL, FALSE, 0x40000010);
```

`MmMapLockedPagesSpecifyCache` does **not copy** — the kernel mapping and the
userspace buffer are backed by the **same physical pages**. Every read the
driver does through `mapped` can change underneath it at any time.

For each placeholder entry, the function then performs a classic
double-fetch:

```c
// [CHECK] — read #1 of the shared buffer: scan relName for '\' and ':'
for (i = 0; i < relName_len / 2; i++) {
    ch = *(WCHAR *)((char *)mapped + relName_offset + 2*i);
    if (ch == L'\\' || ch == L':')
        return 0xC000CF0B;                    // reject
}

// ... time window ...

// [USE] — read #2 of the shared buffer: ObjectName STILL points into `mapped`
name.Buffer = (WCHAR *)((char *)mapped + relName_offset);
name.Length = name.MaximumLength = relName_len;
ObjectAttributes.RootDirectory = dirHandle;   // BaseDirectoryPath
ObjectAttributes.Attributes  = OBJ_KERNEL_HANDLE | OBJ_INHERIT;   // 0x240
FltCreateFileEx2(..., 0x100180 /*DesiredAccess*/, &ObjectAttributes, ...,
                 CreateOptions /*0x208020 | dir bit*/, ..., 0x800 /*IO_IGNORE_SHARE_ACCESS_CHECK*/, ...);
```

A second userspace thread that continuously rewrites the payload flips a
single character between check and use:

```
"JUSTASTRINGDnewfile.dll"   — passes the check (no backslash)
"JUSTASTRING\newfile.dll"   — what FltCreateFileEx2 actually sees
```

If `JUSTASTRING` is a **junction** the attacker planted inside their own
sync root pointing at a protected directory (e.g. `C:\Windows\System32`),
`FltCreateFileEx2` follows it — the minifilter passes no flag to fail on
reparse points — and creates `newfile.dll` there **as SYSTEM**. Writing a
payload into the new file and getting it side-loaded (e.g. via a privileged
service's DLL search path) completes the privesc.

### Why the check existed at all

The `\` / `:` scan was itself a security fix — added for **CVE-2020-17136**
to stop path traversal via `..` / absolute paths in placeholder names.
CVE-2025-55680 is the TOCTOU bypass of that very mitigation: the check is
correct, but it validates a buffer the attacker still owns.

### The patch (verified via GhidraMCP, 2026-07-20)

The post-patch build (cldflt.sys 10.0.26100.6899) adds a new WIL
Controlled-Feature-Rollout flag, `Feature_4257790267`, and behind it
**replaces the MDL shared mapping with a private pool snapshot** of the
entire placeholder payload — `HsmpOpCreatePlaceholders` @ `0x14005e954`
(pre-patch: `0x14005e934`):

```c
uVar7 = Feature_4257790267__private_IsEnabledDeviceUsageNoInline();
if (uVar7 == 0) {
    // legacy: IoAllocateMdl + ProbeForRead + MmProbeAndLockPages
    //         + MmMapLockedPagesSpecifyCache → shared pages (vulnerable)
} else {
    buf = ExAllocatePool2(NonPagedPoolNx, payload_size, 'HsSp');
    ProbeForWrite(payload, payload_size, 4);
    memcpy(buf, payload, payload_size);       // snapshot into private pool
}
// ... entry loop: the '\' / ':' scan AND ObjectName.Buffer both read `buf`
// on success: memcpy(payload, buf, payload_size) copies results back
```

Both the check and the use now dereference the same private snapshot, so the
double-fetch is eliminated at the root — mutating the userspace buffer
mid-flight changes nothing. The legacy MDL path remains compiled in behind
the flag (CFR kill-switch pattern, same as CVE-2026-42980), but unlike that
case the new branch is real new code, so a function-level diff does show
`HsmpOpCreatePlaceholders` as changed.

---

## Complete Call Flow (userspace → vulnerable code)

```
[userspace, any integrity level]
CfRegisterSyncRoot("C:\\Users\\<u>\\syncroot", ...)         cldapi.dll — one-time setup
CfCreatePlaceholders(BaseDirectoryPath, PlaceholderArray, 1, 0, &n)
  └─ cldapi.dll builds ioctl_0x903BC { Tag=0x9000001A, OpType=0xC0000001,
                                       size>=0x50, placeholder_payload* (USER VA) }
  └─ NtFsControlFile(hBaseDir, 0x903BC, inBuf, inLen)       inLen >= 0x20

[kernel — cldflt.sys, minifilter pre-op]
HsmFltPreFILE_SYSTEM_CONTROL(CallbackData w/ FSCTL 0x903BC)
  └─ HsmiOpPrepareOperation
       └─ HsmFltProcessCreatePlaceholders
            │  checks: nInBufferSize >= 0x20; ioctl_0x903BC.size >= 0x50
            ├─ HsmpRelativeStreamOpen(...)              // handle to BaseDirectoryPath
            └─ HsmpOpCreatePlaceholders(..., placeholder_payload, size)
                 ├─ IoAllocateMdl / ProbeForRead / MmProbeAndLockPages
                 ├─ mapped = MmMapLockedPagesSpecifyCache(...)   // shared pages!
                 └─ loop over entries:
                      ├─ copy fixed fields → placeholderPayload_stack
                      ├─ [CHECK] scan mapped->relName for '\' / ':'   ← read #1
                      ├─ build ObjectAttributes{ RootDirectory=dir,
                      │     ObjectName → mapped->relName }            ← read #2
                      └─ FltCreateFileEx2(...)                      // junction followed
```

### Relevant interfaces

| Layer | Interface |
|---|---|
| Win32 API | `CfRegisterSyncRoot`, `CfCreatePlaceholders` (cldapi.dll) |
| Native API | `NtFsControlFile` / `DeviceIoControl` on a directory inside the sync root |
| IOCTL | `0x903BC` with `Tag = 0x9000001A` (`IO_REPARSE_TAG_CLOUD`), `OpType = 0xC0000001` |
| Kernel entry | `cldflt!HsmFltPreFILE_SYSTEM_CONTROL` (minifilter pre-callback for `IRP_MJ_FILE_SYSTEM_CONTROL`) |
| Vulnerable sink | `cldflt!HsmpOpCreatePlaceholders` → `FltCreateFileEx2` |

`ioctl_0x903BC` input buffer layout (from the Exodus writeup):

| Offset | Size | Field |
|---|---|---|
| 0x00 | 4 | Tag = `0x9000001A` |
| 0x04 | 4 | OpType = `0xC0000001` |
| 0x0C | 4 | size (≥ 0x50) |
| 0x10 | 8 | placeholder_payload → `create_placeholder_t` |

`create_placeholder_t`:

| Offset | Size | Field |
|---|---|---|
| 0x08 | 2 | relativeName_offset |
| 0x0A | 2 | relativeName_len |
| 0x0C | 2 | fileidentity_offset |
| 0x0E | 2 | fileidentity_len |
| 0x2E | 4 | fileAttributes |
| 0x50 | var | relName (wide chars) |
| var | var | fileid |

---

## Exploitation Scenario (Exodus technique)

1. **Setup** — `CfRegisterSyncRoot()` on an attacker-owned directory; create
   `JUSTASTRING` inside it as a **junction → `C:\Windows\System32`**.
2. **Race** — three thread classes:
   - *Create threads*: loop `CfCreatePlaceholders` with
     `relName = L"JUSTASTRINGDnewfile.dll"`, `fileAttributes = FILE_ATTRIBUTE_NORMAL`.
   - *Changer threads*: flip character 8 `D ↔ \` in the payload buffer with
     a small delay.
   - *Monitor thread*: polls for `C:\Windows\System32\newfile.dll`; on
     success, stops the race and writes the DLL payload.
3. **Privesc** — DLL side-loading into a privileged process.
4. **Cleanup** — remove placeholder/junction artifacts.

Win condition: the flip to `\` lands after the check scan but before
`FltCreateFileEx2` reads the name. The window is wide (object-manager lookup
setup between the scan and the create), so a few thousand iterations
typically suffice.

---

## Detection & Hunting (blue team)

### High-signal telemetry

| Source | Indicator |
|---|---|
| Sysmon **Event 11** (FileCreate) | Files appearing in `C:\Windows\System32`, `C:\Windows\SysWOW64`, or program dirs whose creating process is a **non-admin user process** — especially `.dll`/`.exe` |
| Sysmon **Event 1** / Security 4688 | Processes calling `CfRegisterSyncRoot` (cldapi.dll loaded) that are **not** known sync engines (OneDrive.exe, etc.) |
| File system | Junctions/reparse points created **inside sync-root directories** pointing outside the sync root (audit `FSCTL_SET_REPARSE_POINT`) |
| ETW | Microsoft-Windows-Kernel-File / minifilter tracing: bursts of failed `CfCreatePlaceholders` (status `0xC000CF0B`) from one process = race attempts |

### Sigma rule (starter)

```yaml
title: CVE-2025-55680 Cloud Files Placeholder TOCTOU - Junction in Sync Root
id: 9e4f6f10-5568-4c2e-9a10-020255568000
status: experimental
logsource:
  product: windows
  category: file_event
detection:
  selection:
    TargetFilename|contains:
      - '\Windows\System32\'
      - '\Windows\SysWOW64\'
  filter_known_sync:
    Image|contains:
      - '\OneDrive'
      - '\Nextcloud'
      - '\Dropbox'
  condition: selection and not filter_known_sync
level: high
```

### YARA (PoC marker — payload constants)

```yara
rule CVE_2025_55680_PoC_marker {
    meta:
        description = "Detects artifacts of the cldflt.sys placeholder TOCTOU PoC"
        reference = "https://blog.exodusintel.com/2025/10/20/microsoft-windows-cloud-files-minifilter-toctou-privilege-escalation/"
    strings:
        $ioctl   = { 1A 00 00 90 01 00 00 C0 }          // Tag 0x9000001A + OpType 0xC0000001 (LE bytes in buffer ctor)
        $api1    = "CfCreatePlaceholders" ascii
        $api2    = "CfRegisterSyncRoot" ascii
        $marker  = "JUSTASTRING" wide
    condition:
        uint16(0) == 0x5A4D and 2 of ($api*) and ($ioctl or $marker)
}
```

### Sysmon config fragment

```xml
<RuleGroup name="cve-2025-55680">
  <FileCreate onmatch="include">
    <TargetFilename condition="begin with">C:\Windows\System32\</TargetFilename>
  </FileCreate>
</RuleGroup>
```

(Combine with the creating-process filter above — the creating process is
the race winner's user process, not a service.)

---

## Remediation

1. **Apply KB5066835** (October 2025) or later; verify
   `cldflt.sys ≥ 10.0.26100.6899`.
2. **Alert on sync-root registration by non-standard processes** — legitimate
   use is essentially OneDrive and installed sync clients.
3. **Hunt** for junctions under registered sync roots (registry:
   `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CloudFiles\SyncRoots`
   / per-user equivalent — **check on your build**: this path is not
   mentioned in the Exodus writeup or Microsoft Cloud Files API docs and
   could not be verified from public sources; estimate).

---

## Timeline

| Date | Event |
|---|---|
| 2024-03 | Exodus Intelligence discovers the race condition |
| 2025-10-14 | Microsoft October 2025 Patch Tuesday (KB5066835), CVE-2025-55680 assigned |
| 2025-10-20 | Exodus publishes full technical writeup |
| 2026-07-20 | This analysis: blue-team package derived from the Exodus writeup; fix **verified** via ghidriff + live GhidraMCP decompilation (pool snapshot behind `Feature_4257790267`) |

---

## References

- [Exodus Intelligence — Microsoft Windows Cloud Files Minifilter TOCTOU Privilege Escalation](https://blog.exodusintel.com/2025/10/20/microsoft-windows-cloud-files-minifilter-toctou-privilege-escalation/)
- [MSRC — CVE-2025-55680](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-55680)
- [Microsoft Docs — CfCreatePlaceholders](https://learn.microsoft.com/en-us/windows/win32/api/cfapi/nf-cfapi-cfcreateplaceholders)
- [OnlyFm252 diff report — cldflt_sys-kb5066835](/data/patch_diffs/cldflt_sys-kb5066835.md)

---

<sub>Analysis: derived from the Exodus Intelligence public writeup.
Local ghidriff diff of cldflt-10.0.26100.6725.sys vs 10.0.26100.6899.sys
(Windows 11 24H2) completed — report in `ghidriff/CVE-2025-55680/ghidriffs/`.
Fix verified by live GhidraMCP decompilation of both builds:
`HsmpOpCreatePlaceholders` @ 0x14005e934 (pre, double-fetch via
MmMapLockedPagesSpecifyCache) vs 0x14005e954 (post, pool snapshot behind
`Feature_4257790267__private_IsEnabledDeviceUsageNoInline`).</sub>
