# CVE-2025-50170 — Windows Cloud Files Mini Filter Driver (`cldflt.sys`) EoP via IoReadAccess/Write Mismatch

---

## Summary

| **Product**           | Microsoft Windows — `cldflt.sys` (Cloud Files Mini Filter Driver) |
|-----------------------|-------------------------------------------------------------------|
| **Vendor**            | Microsoft Corporation |
| **Severity**          | Important (CVSS 7.8) |
| **Affected Versions** | Windows 10 21H2+, Windows 11 22H2/23H2/24H2, Windows Server 2022+ |
| **Tested Version**    | Windows 10.0.26100.4484 (pre-patch) vs 10.0.26100.4946 (post-patch) |
| **Impact**            | Elevation of Privilege — Arbitrary file corruption via kernel write |
| **CVE ID**            | CVE-2025-50170 |
| **CWE**               | CWE-280: Improper Handling of Insufficient Permissions or Privileges |
| **PoC Available**     | Yes (trigger PoC — demonstrates the IoReadAccess mismatch) |
| **Patch Available**   | Yes |
| **Patch Date**        | August 2025 — KB5063878 |
| **Exploitation Maturity** | Exploitation Less Likely |

---

## CVSS 3.1 Scoring

**Base Score:** 7.8 (HIGH)
**Vector String:** `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`

| **Metric** | **Value** | **Rationale** |
|---|---|---|
| **Attack Vector (AV)** | Local | Requires local authenticated session |
| **Attack Complexity (AC)** | Low | Single FSCTL call with crafted buffer |
| **Privileges Required (PR)** | Low | Standard user account |
| **User Interaction (UI)** | None | No user interaction needed |
| **Confidentiality (C)** | High | Can read contents of files without permission |
| **Integrity (I)** | High | Arbitrary file corruption through kernel write |
| **Availability (A)** | High | Can corrupt critical system files |

---

## Product Description

`cldflt.sys` is the Windows Cloud Files Mini Filter Driver (also known as the Cloud Sync Engine filter). It implements the Cloud Files API (`CfCreatePlaceholders`, `CfHydratePlaceholder`, etc.) used by cloud storage providers like OneDrive to create placeholder files that appear in the filesystem but whose content is stored in the cloud.

The driver registers as a filesystem minifilter and intercepts IRP_MJ_FILE_SYSTEM_CONTROL operations. The `HsmpOpCreatePlaceholders` function processes requests to create cloud placeholder files from a user-supplied buffer. The buffer contains an array of placeholder descriptors that specify file metadata, reparse point data, and file sizes. The kernel reads this buffer, creates the placeholder files, and writes back status results (timestamps, USN records) to the same buffer.

The critical issue: the pre-patch driver probes and locks the user buffer with `IoReadAccess` but later writes results back to it. This means a standard user can pass a read-only mapping of a protected file as the buffer. The kernel, having only checked for read access, happily writes placeholder metadata into the mapping — corrupting the target file.

---

## Prerequisites and Constraints

- Local authenticated session (standard user; no admin rights needed)
- The Cloud Files filter (`cldflt.sys`) must be loaded (loaded by default when OneDrive or any Cloud Files API consumer is active)
- Attacker must be able to create a read-only section mapping of the target file (requires read access to the file, which most system files allow)
- The write is not fully controlled — the kernel writes placeholder metadata structures (timestamps, USN, flags), not arbitrary data. However, this is sufficient to corrupt file contents
- Attack is a corruption primitive, not a direct code execution path — but corrupting the right files (e.g., DLLs, config files) can lead to code execution

---

## Vulnerability Details

### Call Chain (Ghidra MCP–Verified)

Complete call chain from userspace to the vulnerable write, verified via Ghidra MCP decompilation against the **pre-patch** binary (`cldflt.sys`, 10.0.26100.4484):

```
User mode (attacker):
  CfCreatePlaceholders() / DeviceIoControl(FSCTL_HSM_CONTROL)
                                        ↓
Kernel mode (cldflt.sys):
  HsmFltPreFILE_SYSTEM_CONTROL()       [minifilter pre-op callback]
    → HsmFltProcessHSMControl()         [FSCTL dispatch]
      → HsmFltProcessCreatePlaceholders() [validates params, opens stream]
        → HsmpOpCreatePlaceholders()    [*** processes user buffer ***]
          → IoAllocateMdl(userBuffer, size)
          → ProbeForRead(userBuffer, size, 4)  ← READ only
          → MmProbeAndLockPages(MDL, UserMode, IoReadAccess=0)  ← BUG
          → MmMapLockedPagesSpecifyCache(MDL)  [maps buffer to kernel VA]
          → [loop] parse placeholder descriptors from buffer
            → FltCreateFileEx2() / FltCreateFileEx()  [create placeholder]
            → HsmpRpCreate()  [set reparse point]
            → FltSetInformationFile()  [set file info]
            → *** WRITES status back to user buffer ***  ← CORRUPTION
              pauVar12[1] = timestamps
              pauVar12[2] = sizes
              pauVar12[3] = flags
              pauVar12[4] = USN
```

### HsmpOpCreatePlaceholders — Vulnerable Path (Pre-Patch)

From the Ghidra decompilation at `0x1c005ec54` (cldflt.sys 10.0.26100.4484):

```c
// Pre-patch: IoAllocateMdl + ProbeForRead + MmProbeAndLockPages(IoReadAccess)
lVar10 = IoAllocateMdl(param_4, param_5, 0, 0);  // param_4=userBuffer, param_5=size
if (lVar10 != 0) {
    ProbeForRead(param_4, param_5);               // *** Only checks READ access ***
    MmProbeAndLockPages(lVar10, 1 /*UserMode*/, 0 /*IoReadAccess*/);  // *** BUG ***
    // ...
    local_1c0 = MmMapLockedPagesSpecifyCache(lVar10, 0, 1, 0);
```

**Disassembly confirming IoReadAccess=0 in R8:**

```asm
0x1c005edde: XOR R8D, R8D           ; R8 = 0 = IoReadAccess  ← BUG
0x1c005ede1: LEA R14D, [R8 + 0x1]   ; R14 = 1
0x1c005ede5: MOV DL, R14B           ; DL = 1 = UserMode
0x1c005edf0: MOV RCX, RDI           ; RCX = MDL
0x1c005edf3: CALL [MmProbeAndLockPages]
```

Later in the function, the kernel writes back results to the same buffer:

```c
// After successful placeholder creation, kernel WRITES to user buffer:
*(longlong ***)pauVar12[1] = local_a8;            // timestamps
*(undefined8 *)(pauVar12[1] + 8) = uStack_a0;
*(undefined8 *)pauVar12[2] = local_98;            // file sizes
*(undefined8 *)(pauVar12[2] + 8) = uStack_90;
*(uint *)pauVar12[3] = uRam0000000000000028;      // flags
*(undefined8 *)(pauVar12[4] + 8) = uRam0000000000000030;  // USN record
```

Where `pauVar12` is derived from the mapped user buffer (`local_1c0`). The kernel writes placeholder status (timestamps, sizes, flags, USN) back to the caller's buffer. Since the pages were only locked with `IoReadAccess`, the kernel bypasses the page-level write protection check.

### The Fix (Post-Patch)

The post-patch binary changes:

```c
// Post-patch: IoWriteAccess instead of IoReadAccess
ProbeForWrite(param_4, param_5);                    // Changed from ProbeForRead
MmProbeAndLockPages(lVar10, 1 /*UserMode*/, 1 /*IoWriteAccess*/);  // FIXED
```

With `IoWriteAccess`, `MmProbeAndLockPages` verifies that the caller has write access to the underlying pages. If the user mapped a read-only section (e.g., of a protected file), the call fails with `STATUS_ACCESS_VIOLATION`, preventing the kernel from writing to pages the user cannot write to.

The fix is gated behind WIL CFR flag `Feature_2594491707`.

### HsmFltProcessCreatePlaceholders (Caller)

```c
// Validates input size, opens stream, calls the vulnerable function
ulonglong HsmFltProcessCreatePlaceholders(...)
{
    if ((param_10 < 0x20) || (*(uint *)(param_9 + 0x10) < 0x50)) {
        return 0xc000cf0b;  // STATUS_CLOUD_FILE_INVALID_REQUEST
    }
    // Opens the target stream
    uVar2 = HsmpRelativeStreamOpen(param_2, param_3, ...);
    // Prepares management operation
    uVar2 = HsmpPrepareForMgmtOperation(param_2, param_6, 8, '\0');
    // Calls vulnerable function with user buffer pointer + size from param_9
    puVar5 = HsmpOpCreatePlaceholders(
        param_2, param_7, uVar3,
        *(param_9 + 0x18),    // user buffer pointer
        *(param_9 + 0x10),    // user buffer size
        &local_res8);         // output count
}
```

---

## Exploitation Scenario

### Step 1 — Identify Target File

The attacker selects a target file they want to corrupt (e.g., a DLL in `C:\Windows\System32\` or a config file). The file must be readable by the attacker (most system files have read access for all users).

### Step 2 — Create Read-Only Section Mapping

```c
// Open target file with READ access only
HANDLE hFile = CreateFileW(L"C:\\Windows\\System32\\target.dll",
    GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    OPEN_EXISTING, 0, NULL);

// Create a section (file mapping) — this gives us a read-only view
HANDLE hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);

// Map the section into our address space — read-only view
PVOID pView = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
```

### Step 3 — Pass Mapping as Placeholder Buffer

The attacker crafts a placeholder descriptor array and passes the read-only mapping address as the output buffer to the Cloud Files FSCTL. The buffer is structured with valid placeholder headers pointing into the mapped region.

### Step 4 — Kernel Writes Through Read-Only Mapping

Because `MmProbeAndLockPages` only checks `IoReadAccess`, the kernel successfully locks the read-only pages and writes placeholder status data (timestamps, file sizes, flags, USN records) into them. This data goes through to the underlying file, corrupting its contents.

### Impact

Arbitrary file corruption as the kernel. The attacker can corrupt any file they can read. While the written data is not fully controlled (it's placeholder metadata), corrupting key structures in DLLs or config files can lead to code execution or denial of service.

---

## Patch Analysis

### Mechanism

The patch changes two calls in `HsmpOpCreatePlaceholders`:

| Call | Pre-Patch | Post-Patch |
|---|---|---|
| `ProbeForRead/Write` | `ProbeForRead(buffer, size, 4)` | `ProbeForWrite(buffer, size, 4)` |
| `MmProbeAndLockPages` | `MmProbeAndLockPages(MDL, UserMode, IoReadAccess)` | `MmProbeAndLockPages(MDL, UserMode, IoWriteAccess)` |

With `IoWriteAccess`, the kernel verifies that the caller's pages are writable before locking them. A read-only section mapping of a protected file will fail the probe, returning `STATUS_ACCESS_VIOLATION`.

### Feature Gating

The fix is gated behind WIL CFR flag `Feature_2594491707`.

### Files Changed

| Function | Change |
|---|---|
| `HsmpOpCreatePlaceholders` | `ProbeForRead` → `ProbeForWrite`; `MmProbeAndLockPages` 3rd arg 0→1 |
| `wil::details::FeatureImpl<Feature_2594491707>::__private_IsEnabled` | New WIL CFR accessor |

---

## Trigger PoC

A proof-of-concept is available at [`poc/poc_cve_2025_50170.c`](/data/patch_diffs/poc/poc_cve_2025_50170.c). It demonstrates:

1. Creating a test file with known content
2. Opening it read-only and creating a section mapping
3. Calling the Cloud Files API with the read-only mapping as the buffer
4. Checking whether the file was modified (proving the kernel wrote through the read-only mapping)

On a **pre-patch** system, the PoC will show that the kernel wrote through the read-only mapping. On a **post-patch** system, `MmProbeAndLockPages` fails with `STATUS_ACCESS_VIOLATION`.

> **Note:** This PoC is a **trigger/detector** only. It targets a test file created by the PoC, not system files.

---

## Detection Rules

### YARA Rule — Detecting PoC/Exploit Binaries

```yara
rule CVE_2025_50170_CldFlt_IoReadAccess_Exploit {
    meta:
        description = "Detects tools exploiting CVE-2025-50170 cldflt.sys IoReadAccess mismatch"
        author = "OnlyFm252"
        date = "2026-07-18"
        cve = "CVE-2025-50170"
        severity = "high"
        tlp = "white"

    strings:
        $api1 = "CfCreatePlaceholders" ascii wide
        $api2 = "CreateFileMappingW" ascii wide
        $api3 = "MapViewOfFile" ascii wide
        $api4 = "DeviceIoControl" ascii wide
        $fsctl1 = "FSCTL_HSM_CONTROL" ascii wide
        $fsctl2 = "HSM_CONTROL" ascii wide
        $cloud1 = "cldflt" ascii wide nocase
        $cloud2 = "CloudFiles" ascii wide nocase
        $cloud3 = "CF_PLACEHOLDER" ascii wide
        $s_readonly = "PAGE_READONLY" ascii wide
        $s_fileread = "GENERIC_READ" ascii wide

    condition:
        uint16(0) == 0x5A4D and
        filesize < 500KB and
        ($api1 or $fsctl1 or $fsctl2) and
        ($api2 or $api3) and
        ($s_readonly or $s_fileread)
}
```

### YARA Rule — Detecting Vulnerable cldflt.sys (Pre-Patch)

```yara
rule CVE_2025_50170_Vulnerable_CldFlt {
    meta:
        description = "Detects pre-patch cldflt.sys with IoReadAccess in HsmpOpCreatePlaceholders"
        author = "OnlyFm252"
        date = "2026-07-18"
        cve = "CVE-2025-50170"

    strings:
        // XOR R8D,R8D (45 31 C0) followed by LEA R14D,[R8+1] (45 8D 70 01)
        // This is the IoReadAccess=0 setup before MmProbeAndLockPages
        $vuln_pattern = { 45 31 C0 45 8D ?? ?? 01 }
        $driver_name = "cldflt" wide nocase
        $func_name = "HsmpOpCreatePlaceholders" ascii

    condition:
        uint16(0) == 0x5A4D and
        $driver_name and
        ($func_name or $vuln_pattern)
}
```

### Sigma Rule — Cloud Files API Abuse for File Corruption

```yaml
title: Suspicious Cloud Files Placeholder API Usage (CVE-2025-50170)
id: c3d4e5f6-7a8b-9c0d-1e2f-3a4b5c6d7e8f
status: experimental
description: >
    Detects processes loading cldapi.dll (Cloud Files API) that are not
    known cloud storage providers. Exploitation of CVE-2025-50170 requires
    calling CfCreatePlaceholders or sending FSCTL_HSM_CONTROL to cldflt.sys.
author: OnlyFm252
date: 2026/07/18
references:
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-50170
    - https://onlyfm252.starlabs.sg/patch-tuesday/2025-08/cve-2025-50170/
logsource:
    category: image_load
    product: windows
detection:
    selection_cldapi:
        ImageLoaded|endswith: '\cldapi.dll'
    filter_known_providers:
        Image|contains:
            - '\OneDrive'
            - '\Microsoft.SharePoint'
            - '\FileCoAuth'
            - '\iCloudDrive'
            - '\Dropbox'
            - '\GoogleDrive'
    filter_system:
        Image|startswith:
            - 'C:\Windows\System32\'
            - 'C:\Windows\SysWOW64\'
    condition: selection_cldapi and not filter_known_providers and not filter_system
falsepositives:
    - Third-party cloud storage providers using Cloud Files API
    - Development tools testing Cloud Files functionality
level: medium
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2025.50170
```

### Sigma Rule — Read-Only File Mapping Followed by Cloud Files FSCTL

```yaml
title: Read-Only File Mapping with Cloud Files FSCTL (CVE-2025-50170)
id: d4e5f6a7-8b9c-0d1e-2f3a-4b5c6d7e8f9a
status: experimental
description: >
    Detects a process creating a read-only file mapping (NtCreateSection
    with SEC_COMMIT + PAGE_READONLY) followed by a filesystem control
    to cldflt.sys. This is the exploitation pattern for CVE-2025-50170.
author: OnlyFm252
date: 2026/07/18
logsource:
    category: driver_load
    product: windows
detection:
    selection_cldflt_load:
        ImageLoaded|endswith: '\cldflt.sys'
    selection_process:
        Image|endswith: '.exe'
    condition: selection_cldflt_load
falsepositives:
    - Normal cloud file sync operations
level: low
tags:
    - attack.privilege_escalation
    - cve.2025.50170
```

### Sysmon Configuration

```xml
<!-- Sysmon config addition for CVE-2025-50170 detection -->
<RuleGroup name="CVE-2025-50170" groupRelation="or">

  <!-- ImageLoad: cldapi.dll loaded by unusual process -->
  <ImageLoad onmatch="include">
    <Rule name="CldApi_Unusual_Load" groupRelation="and">
      <ImageLoaded condition="end with">cldapi.dll</ImageLoaded>
      <Image condition="excludes">OneDrive</Image>
      <Image condition="excludes">FileCoAuth</Image>
      <Image condition="excludes">explorer.exe</Image>
    </Rule>
  </ImageLoad>

  <!-- ProcessCreate: processes with cloud files API strings -->
  <ProcessCreate onmatch="include">
    <Rule name="CfCreatePlaceholders_Abuse" groupRelation="or">
      <CommandLine condition="contains">CfCreatePlaceholders</CommandLine>
      <CommandLine condition="contains">FSCTL_HSM_CONTROL</CommandLine>
      <CommandLine condition="contains">cldflt</CommandLine>
    </Rule>
  </ProcessCreate>

  <!-- FileCreate: unexpected placeholder creation outside sync roots -->
  <FileCreate onmatch="include">
    <Rule name="Placeholder_Outside_SyncRoot" groupRelation="and">
      <TargetFilename condition="excludes">\OneDrive\</TargetFilename>
      <TargetFilename condition="excludes">\OneDriveTemp\</TargetFilename>
      <TargetFilename condition="contains">~</TargetFilename>
    </Rule>
  </FileCreate>

</RuleGroup>
```

---

## Remediation

1. **Apply KB5063878** (August 2025 cumulative update) immediately
2. **Verify patch**: Check `cldflt.sys` version is ≥ 10.0.26100.4946
3. **Monitor**: Deploy the Sysmon and Sigma rules above
4. **Restrict**: If Cloud Files functionality is not needed, disable the `cldflt` minifilter: `fltmc unload cldflt` (requires admin)
5. **Audit**: Review for unusual cldapi.dll loads or FSCTL_HSM_CONTROL activity
6. **Hunt**: Check for processes creating file mappings of system DLLs followed by Cloud Files API calls

---

## Timeline

| Date | Event |
|---|---|
| 2025-08-12 | Microsoft releases August 2025 Patch Tuesday (KB5063878) |
| 2026-07-18 | This Ghidra MCP–verified analysis published |

---

## References

- [Microsoft Security Response Center — CVE-2025-50170](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-50170)
- [OnlyFm252 Diff Report](/data/patch_diffs/cldflt_sys-kb5063878.md)

---

<sub>Analysis: OnlyFm252 — Ghidra MCP–verified decompilation of pre-patch cldflt.sys 10.0.26100.4484.
Binary diff: ghidriff of cldflt-2025-07.sys (10.0.26100.4484, pre-patch) vs cldflt-2025-08.sys (10.0.26100.4946, post-patch).
[Download pre-patch](/data/patch_diffs/binaries/cldflt-2025-07.sys) / [Download post-patch](/data/patch_diffs/binaries/cldflt-2025-08.sys).</sub>
