Heap-based buffer overflow in Kernel Streaming WOW Thunk Service Driver – CVE-2025-53149
From time to time, while digging through internals during our research, we stumble upon quirks or vulnerabilities that, although not immediately useful for operations or exploitation, are still noteworthy. Rather than letting these findings fade away, we decided to responsibly disclose them to the vendor. One such case is CVE-2025-53149, a heap-based buffer overflow in the Kernel Streaming WOW Thunk Service Driver, which Microsoft patched on August 12, 2025.
The vulnerable component is the ksthunk.sys
driver, SHA-1 68B5B527550731DD657BF8F1E8FA31E895A7F176
.
Kernel Streaming
Kernel streaming, often abbreviated as KS, is a foundational technology within the Windows operating system for handling real-time data streams, particularly for multimedia applications. It provides a low-latency, high-performance architecture that allows devices and applications to efficiently process and transport large volumes of data, such as audio and video.
KSThunk, short for “Kernel Streaming WOW Thunk Service,” is a specific component within the Windows operating system that plays a crucial role in maintaining backwards compatibility for multimedia applications. It is a system driver file (ksthunk.sys
) that is primarily used on 64-bit versions of Windows. The core purpose of KSThunk is to act as a “thunk” layer: a small piece of code that translates requests between different environments. In this case, it bridges the gap between 32-bit user-mode applications and the 64-bit kernel-mode drivers that manage real-time media streams.
Static analysis
We discovered the vulnerability in the CKSAutomationThunk::HandleArrayProperty()
function of the ksthunk.sys
driver. Looking at the IOCTL dispatching code in the CKSThunkDevice::DispatchIoctl()
function, it can be noted that CKSAutomationThunk::ThunkPropertyIrp()
will be called when the calling process is usermode
and wow64
:
CKSAutomationThunk::ThunkPropertyIrp()
perform checks on the input buffer length and reads the KSPROPERTY.Flags
. If the two lowest bits are 0, then the function returns 1. But if the KSPROPERTY.Flags
has set KSPROPERTY_TYPE_SET
or KSPROPERTY_TYPE_GET
, then the request is going to be processed with an additional property set, as shown in the image below:
On line 41, a PropertySet
can be seen, which is an array of 6 KSPROPERTY_SET
structures:
In our context, the most important are KSPROPSETID_VPConfig
and KSPROPSETID_VPVBIConfig
. They have the same set of items:
The handler for KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE
(0xE
index) is CKSAutomationThunk::HandleArrayProperty()
, which is vulnerable.
This is the function prototype:
NTSTATUS CKSAutomationThunk::HandleArrayProperty(PIRP *Irp, PKSPROPERTY *SystemInputBuffer, unsigned int *SystemOutputBuffer);
It receives a pointer to IRP
, a pointer to KSPROPERTY
and a pointer to data; in this case, it is an array of numbers. The element in position 0 is the quantity of items in the array.
Important note here, CKSAutomationThunk::ThunkPropertyIrp()
works with input and output buffers from userspace. However, CKSAutomationThunk::HandleArrayProperty()
receives copies of the buffers from kernel space memory. This region is allocated in non-paged memory by the ks!KspPropertyHandler()
function. In fact, both pointers point to the same allocation, but at different offsets within it. SystemOutputBuffer
points to the beginning of the memory region while SystemInputBuffer
points to SystemOutputBuffer + aligned OutputBufferLength
.
Inside the CKSAutomationThunk::HandleArrayProperty()
function, there is code to both set
and get
properties. The vulnerability lies in the getter’s code. First call to KsSynchronousIoControlDevice()
checks how many bytes to read, allocates memory, and the second KsSynchronousIoControlDevice()
function call reads the array from the device. Next, it copies the array content into the memory pointed to by SystemOutputBuffer
. It is easy to note that OutputBufferLength
is not correctly checked: it is compared with 0, but not against the value (BytesReturned
) returned from the first KsSynchronousIoControlDevice()
call:
For this reason, in the cycle (lines 63 – 68), a non-paged heap overflow is possible.
Trigger
In order to trigger this vulnerability, the target system has to have a device with KSPROPSETID_VPConfig
or KSPROPSETID_VPVBIConfig
property set with KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE
item. Unfortunately, were unable to find such devices on our test systems.
Nevertheless, we can at least call this function to trigger the vulnerability. It’s enough to open any device and try to get this property:
KSPROPERTY KsProperty = { 0 }; KsProperty.Set = KSPROPSETID_VPConfig; KsProperty.Id = KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE; KsProperty.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_COPYPAYLOAD; char rx_buffer[0x100]; DeviceIoControl(hDevice, IOCTL_KS_PROPERTY, &KsProperty, sizeof(KSPROPERTY), rx_buffer, sizeof(rx_buffer), &temp, 0);
The stack trace will be the following:
Unfortunately, since there is no proper device in our system, the call to KsSynchronousIoControlDevice()
returns an error, and we cannot continue triggering the bug. However, if your system has such a device, it is vulnerable, and you can trigger this bug.
The patch
In the patched version, a check for OutputBufferLength
is added. If there is no enough space in the output buffer, the code leads into the RtlLogUnexpectedCodepath()
function.
Timeline
-
14.04.2025 – bug found;
-
18.04.2025 – bug reported;
-
20.05.2025 – bug confirmed;
-
04.06.2025 – bounty awarded;
-
05.08.2025 – CVE assigned, bounty rejected!?;
-
12.08.2025 – fix released;
Conclusion
Lesson learned: report bugs to Crowdfense, not to the vendor! 😉
References
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-53149