# CVE-2025-53149 — Windows Kernel Streaming WOW Thunk `ksthunk.sys` Heap Overflow in `CKSAutomationThunk::HandleArrayProperty`

---

## Summary

| | |
|---|---|
| **Product** | Microsoft Windows — `ksthunk.sys` (Kernel Streaming WOW Thunk Service Driver) |
| **CVE ID** | CVE-2025-53149 |
| **Impact** | Elevation of Privilege |
| **MSRC severity** | Important |
| **CWE** | CWE-122: Heap-based Buffer Overflow (non-paged pool) |
| **Patch Date** | August 12, 2025 |
| **Pre-patch binary** | `ksthunk.sys` 10.0.26100.4768 (Jul 2025) — SHA256 `31248ae43f53ffb1446ec95a078f9e56e14ccc556654fcb72c93dc3cb7406088` |
| **Post-patch binary** | `ksthunk.sys` 10.0.26100.4946 (Aug 12 2025 fix) — SHA256 `d7eba221b250de0c08bb829212261ddc3126588e931ea2e226d97d13f37f930e` |
| **Feature flag** | `Feature_4034713912` — **the fix is CFR-gated** |

---

## Product Description

`ksthunk.sys` — the **Kernel Streaming WOW Thunk Service** — is the 64-bit
kernel driver that translates Kernel Streaming (KS) requests between **32-bit
(WOW64) user-mode applications** and 64-bit kernel media drivers. Its IOCTL path
`CKSThunkDevice::DispatchIoctl` routes `IOCTL_KS_PROPERTY` from a WOW64 caller
through `CKSAutomationThunk::ThunkPropertyIrp`, which dispatches KS property sets
including `KSPROPSETID_VPConfig` / `KSPROPSETID_VPVBIConfig`. The
`KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE` item (index `0xE`) is handled by
`CKSAutomationThunk::HandleArrayProperty`. Any 32-bit process can drive this path,
so a bug here is a local elevation-of-privilege primitive.

---

## Vulnerability Summary

`HandleArrayProperty` receives kernel copies of the input/output buffers
(allocated non-paged by `ks!KspPropertyHandler`). In the **getter** path it asks
the device how many bytes to return (first `KsSynchronousIoControlDevice`),
allocates, reads the array (second call), then copies the array into
`SystemOutputBuffer` — but **`OutputBufferLength` was only checked against 0, not
against the number of bytes actually returned**:

```c
// CKSAutomationThunk::HandleArrayProperty (getter) — PRE-PATCH (per Crowdfense)
KsSynchronousIoControlDevice(..., &BytesReturned);   // device says how many bytes
... allocate, second call reads the array ...
if (OutputBufferLength != 0) {
    for (i = 0; i < count; i++)                       // copies count*elem bytes
        SystemOutputBuffer[i] = array[i];             // *** OutputBufferLength not vs BytesReturned ***
}
```

When the device returns more elements than fit in `OutputBufferLength`, the copy
loop writes past the non-paged output allocation — a controlled non-paged-pool
heap overflow.

---

## Prerequisites and Constraints

- Local session running a **32-bit (WOW64)** process able to `DeviceIoControl`
  a KS device with `IOCTL_KS_PROPERTY`.
- The target must expose a device with the `KSPROPSETID_VPConfig` /
  `KSPROPSETID_VPVBIConfig` property set carrying the
  `KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE` item (legacy video-port); Crowdfense
  could reach the function but not complete the copy without such a device.
- Overflow is in non-paged pool; the copied bytes come from the device array, so
  exploitability depends on the present device.

---

## Vulnerability Details

### Call Chain

```
32-bit (WOW64) user process:
  DeviceIoControl(hDevice, IOCTL_KS_PROPERTY, KSPROPERTY{Set=VPConfig, Id=DDRAWSURFACEHANDLE, Flags=GET})
        ↓
ksthunk.sys:
  CKSThunkDevice::DispatchIoctl  (usermode && wow64)
    → CKSAutomationThunk::ThunkPropertyIrp
      → CKSAutomationThunk::HandleArrayProperty   [*** non-paged pool overflow (getter) ***]
```

### Root Cause

The getter trusts the device-returned element count for the copy but validates
`OutputBufferLength` only against zero — never against the `BytesReturned` /
`count * element_size` it is about to write. A device that returns more than the
caller's output buffer holds overflows the allocation.

### The patch (confirmed — diff, .4768 → .4946)

Gated behind `Feature_4034713912`, the getter now validates the required size
against `OutputBufferLength` before the copy and diverts to
`RtlLogUnexpectedCodepath` when it does not fit:

```c
// CKSAutomationThunk::HandleArrayProperty (10.0.26100.4946) — PATCHED
// uVar9 = element count; lVar5+8 = OutputBufferLength
if ((uint)*puVar3 <= uVar9) {
    uVar8 = (ulonglong)uVar9 << 2;                    // count * 4 bytes
    if ((uVar8 < 0x100000000) && ((uint)uVar8 <= *(uint *)(lVar5 + 8)))  // <= OutputBufferLength
        goto LAB_0;                                    // fits -> proceed
}
RtlLogUnexpectedCodepath(&local_50);                   // *** too small -> bail, no copy ***
```

`count * 4` (the bytes to be written) must be `<= OutputBufferLength`; otherwise
the routine logs the unexpected code path and does not copy — eliminating the
overflow.

### Patch Completeness Assessment

**The fix is CFR-gated behind `Feature_4034713912`.** The bounds check runs only
when the flag is enabled; disabled, the patched binary retains the original
unchecked copy. Patch state is not determined by file version alone — the same
runtime-gated pattern seen across this corpus.

---

## Detection Guidance

**Crash signature.** Non-paged-pool corruption bugchecks in
`ksthunk!CKSAutomationThunk::HandleArrayProperty`, from WOW64 processes issuing
`IOCTL_KS_PROPERTY` with `KSPROPSETID_VPConfig`/`VPVBIConfig`. Special Pool on
`ksthunk.sys` makes the overrun observable.

**Behavioural.** 32-bit processes driving KS video-port property GETs on devices
exposing `KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE` — an uncommon legacy path.

**Config.** The fix is CFR-gated: confirm `Feature_4034713912` is enabled to
verify the corrected path is live.

---

## References

- Crowdfense — *Heap-based buffer overflow in Kernel Streaming WOW Thunk Service
  Driver – CVE-2025-53149* (aleksandr.k, voidsec).
- MSRC advisory — CVE-2025-53149
- Full binary diff: `/data/patch_diffs/ksthunk_sys-cve-2025-53149-ghidriff.md`
