# Root Cause Analysis — CVE-2023-29360

## Summary

| Field | Value |
|---|---|
| **CVE** | CVE-2023-29360 |
| **Binary** | mskssrv.sys (Microsoft Streaming Service Proxy Driver) |
| **Component** | FsAllocAndLockMdl — MDL allocation and page locking |
| **Bug Class** | Untrusted Pointer Dereference / Improper Access Control (CWE-822) |
| **Impact** | Elevation of Privilege → SYSTEM |
| **CVSS 3.1** | 8.4 (AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| **Exploited ITW** | Yes (Synacktiv at Pwn2Own 2023 Vancouver; Theori 1-day full chain) |
| **Patch** | June 2023 Patch Tuesday (KB5027231 Win11 22H2) |

## Vulnerability Overview

The Microsoft Streaming Service driver (mskssrv.sys) processes kernel streaming data for
devices such as cameras. The driver exposes a device interface that accepts IOCTLs from
user-mode. When processing IOCTL 0x2F0408 (PublishTx), the driver allocates an MDL (Memory
Descriptor List) using a user-supplied address and size, then calls `MmProbeAndLockPages`
with `AccessMode=KernelMode(0)`. This skips the user/kernel address boundary validation,
allowing a user-mode process to lock and subsequently map arbitrary kernel memory pages,
yielding a full kernel read/write primitive.

## Root Cause — Incorrect AccessMode in MmProbeAndLockPages

### The Vulnerable Code (pre-patch)

```c
__int64 FsAllocAndLockMdl(void *address, ULONG size, _MDL **mdl_object)
{
    if (!address || !size || !mdl_object)
        return 0xC000000D;  // STATUS_INVALID_PARAMETER

    // Allocate MDL with user-controlled address and size
    PMDL Alloc_Mdl = IoAllocateMdl(address, size, 0, 0, NULL);
    if (!Alloc_Mdl)
        return 0xC000009A;  // STATUS_INSUFFICIENT_RESOURCES

    // BUG: AccessMode = KernelMode(0) — skips address validation
    MmProbeAndLockPages(Alloc_Mdl, 0, IoWriteAccess);

    *mdl_object = Alloc_Mdl;
    return 0;
}
```

### The Address Validation Skip

Inside `MmProbeAndLockPages` → `MiProbeAndLockPages` → `MiProbeAndLockPrepare`:

```c
// Address validated ONLY when AccessMode == UserMode(1)
if (AccessMode) {
    if (address + size > 0x7FFFFFFF0000 || address >= address + size) {
        return STATUS_ACCESS_VIOLATION;
    }
}
// With AccessMode == KernelMode(0), this check is SKIPPED entirely
```

When `AccessMode` is `KernelMode(0)`, any address — including kernel space addresses above
`0xFFFF800000000000` — is accepted without validation. The MDL locks the physical pages
backing that kernel virtual address, and these pages can then be mapped into user space.

### Call Chain to Vulnerable Function

```
User-mode application
  → DeviceIoControl(hDevice, 0x2F0408, inputBuffer, ...)
    → SrvDispatchIoControl
      → FSRendezvousServer::PublishTx
        → FSStreamReg::PublishTx
          → FSFrameMdl::AllocateMdl  (copies user data, picks address/size)
            → FsAllocAndLockMdl  *** VULNERABLE ***
              → IoAllocateMdl(user_addr, user_size)
              → MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess)  *** BUG ***
```

### Attacker Control

| What | How |
|---|---|
| **MDL address** | `inputBuffer+0x48` (Addr1) and `inputBuffer+0x60` (Addr2) passed to FsAllocAndLockMdl |
| **MDL size** | `inputBuffer+0x5C` (Size1) and `inputBuffer+0x6C` (Size2) |
| **Map flag** | `inputBuffer+0x70` byte value controls which code path in FSFrameMdl::AllocateMdl (1, 4, or 8) |

## IOCTL State Machine

The vulnerability requires specific driver state setup via three preliminary IOCTLs:

### Step 1: IOCTL 0x2F0400 — FSInitializeContextRendezvous

Creates the `FSRendezvousServer` global object. Required once before any other operations.

### Step 2: IOCTL 0x2F0404 — InitializeStream (handle A)

Creates an `FSStreamReg` object and stores it in `FileObject->FsContext2`. Sets
`FsStreamReg+0x28 = 1`. Uses the "client" handle.

### Step 3: IOCTL 0x2F0420 — RegisterStream (handle B)

Must use a **different** handle (new `CreateFile` call) because `RegisterStream` checks
that `FileObject->FsContext2` is NULL (`[12]`). Sets `FsStreamReg+0x2C = 1`. Both flags
at +0x28 and +0x2C must be non-zero for `ConsumeTx` to proceed.

### Step 4: IOCTL 0x2F0408 — PublishTx (handle A) ← VULNERABILITY TRIGGER

Sends the crafted buffer with kernel address. `FsAllocAndLockMdl` locks the kernel pages
into an MDL, which is stored in the published list.

### Step 5: IOCTL 0x2F0410 — ConsumeTx (handle A) ← MAP KERNEL MEMORY

Takes the MDL from the published list, calls `FSFrameMdl::MapPages` to map it into the
calling process's address space. Returns the mapped user-mode address in the output buffer
at offset +0x48. The attacker now has direct read/write access to kernel memory.

## Exploitation Path

### From Arbitrary R/W to SYSTEM

1. **Leak kernel addresses**: `NtQuerySystemInformation(SystemHandleInformation)` leaks
   EPROCESS and token object addresses
2. **Lock+Map token pages**: Use the vulnerability to create an MDL over the current
   process token's physical pages
3. **Enable privileges**: Modify the `_SEP_TOKEN_PRIVILEGES` structure in the mapped token
   to enable `SE_DEBUG_PRIVILEGE` and other powerful privileges
4. **Process injection**: With `SE_DEBUG_PRIVILEGE`, open a SYSTEM process (e.g., winlogon.exe)
   and inject a DLL for code execution as SYSTEM

Alternative exploitation: directly overwrite the token pointer in EPROCESS for a full
token swap (similar to CVE-2024-21338).

## Patch Analysis

The patch is a single-byte change in `FsAllocAndLockMdl`:

```c
// Pre-patch:
MmProbeAndLockPages(Alloc_Mdl, 0, IoWriteAccess);  // KernelMode

// Post-patch:
MmProbeAndLockPages(Alloc_Mdl, 1, IoWriteAccess);  // UserMode
```

With `AccessMode=UserMode(1)`, `MmProbeAndLockPages` validates that the address falls
within user address space (< 0x7FFFFFFF0000). Kernel addresses are rejected with
`STATUS_ACCESS_VIOLATION`.

In BinDiff, `FsAllocAndLockMdl` shows a similarity of ~0.98 — the only change is the
immediate operand from 0 to 1 in the `MmProbeAndLockPages` call.

Patched binary versions (mskssrv.sys):
- Win10 19041: patched in build 19041.3086+
- Win10 19045 (22H2): patched in KB5027215
- Win11 22621 (22H2): patched in KB5027231

## Reachability

- **Attack vector**: Local — requires code execution on the target
- **Privileges required**: None (the device is accessible from medium integrity)
- **User interaction**: None
- **Prerequisites**:
  - mskssrv.sys driver must be loadable (present on all Windows 10/11 systems)
  - The device interface `{3c0d501a-140b-11d1-b40f-00a0c9223196}` must be present
  - Camera/streaming device subsystem registered

## Detection

### YARA — Exploit Artifacts

```yara
rule CVE_2023_29360_Exploit_Indicators
{
    meta:
        description = "Detects compiled exploit artifacts for CVE-2023-29360 mskssrv.sys"
        cve         = "CVE-2023-29360"
        author      = "OnlyFm252"

    strings:
        $device = "{3c0d501a-140b-11d1-b40f-00a0c9223196}" ascii wide nocase
        $device2 = "{96E080C7-143C-11D1-B40F-00A0C9223196}" ascii wide nocase
        $ioctl_publish = { 08 04 2F 00 }
        $ioctl_consume = { 10 04 2F 00 }
        $ioctl_init    = { 00 04 2F 00 }
        $ntqsi = "NtQuerySystemInformation" ascii

    condition:
        uint16(0) == 0x5A4D and
        ($device or $device2) and
        2 of ($ioctl_*) and
        $ntqsi
}
```

### YARA — Vulnerable mskssrv.sys Binary

```yara
rule CVE_2023_29360_Vulnerable_MSKSSRV
{
    meta:
        description = "Detects pre-patch mskssrv.sys with KernelMode AccessMode in FsAllocAndLockMdl"
        cve         = "CVE-2023-29360"
        author      = "OnlyFm252"

    strings:
        $func = "FsAllocAndLockMdl" ascii
        $driver = "mskssrv" ascii wide nocase

    condition:
        uint16(0) == 0x5A4D and
        filesize < 200KB and
        $func and $driver
}
```

### Sigma — Suspicious Streaming Service Driver Access

```yaml
title: CVE-2023-29360 MSKSSRV Streaming Driver Exploitation Indicators
id: b1c2d3e4-f5a6-7890-abcd-ef0123456789
status: experimental
description: >
    Detects potential exploitation of CVE-2023-29360 via suspicious access to the
    Microsoft Streaming Service driver device interface.
author: OnlyFm252
date: 2026/07/26
references:
    - https://theori.io/blog/chaining-n-days-to-compromise-all-part-3-windows-driver-lpe-medium-to-system
    - https://github.com/Nero22k/cve-2023-29360
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-29360
logsource:
    product: windows
    category: driver_load
detection:
    selection:
        ImageLoaded|endswith: '\mskssrv.sys'
    timeframe: 5m
    condition: selection | count() > 2
level: medium
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2023.29360
```

### Sysmon Configuration

```xml
<Sysmon schemaversion="4.90">
  <EventFiltering>
    <!-- Event 7: Detect mskssrv.sys driver load -->
    <DriverLoad onmatch="include">
      <ImageLoaded condition="end with">\mskssrv.sys</ImageLoaded>
    </DriverLoad>

    <!-- Event 1: Detect suspicious processes spawned after exploitation -->
    <ProcessCreate onmatch="include">
      <IntegrityLevel condition="is">System</IntegrityLevel>
      <ParentIntegrityLevel condition="is">Medium</ParentIntegrityLevel>
    </ProcessCreate>

    <!-- Event 10: Detect SYSTEM process access from medium-integrity (DLL injection) -->
    <ProcessAccess onmatch="include">
      <TargetImage condition="end with">\winlogon.exe</TargetImage>
      <GrantedAccess condition="is">0x1F0FFF</GrantedAccess>
    </ProcessAccess>
  </EventFiltering>
</Sysmon>
```

## References

- [Theori — Chaining N-days: Part 3 Windows Driver LPE](https://theori.io/blog/chaining-n-days-to-compromise-all-part-3-windows-driver-lpe-medium-to-system)
- [Nero22k — CVE-2023-29360 PoC](https://github.com/Nero22k/cve-2023-29360)
- [big5-sec — CVE-2023-29360 Analysis](https://big5-sec.github.io/posts/CVE-2023-29360-analysis/)
- [MSRC Advisory — CVE-2023-29360](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-29360)
- [BlackHat 2012 — Easy Local Windows Kernel Exploitation](https://media.blackhat.com/bh-us-12/Briefings/Cerrudo/BH_US_12_Cerrudo_Windows_Kernel_WP.pdf)
