CVE-2024-30090
Kernel Streaming WOW Thunk -- RequestorMode confusion via 32-to-64-bit IRP conversion
Summary
| Field | Value |
|---|---|
| Driver | ksthunk.sys |
| Vulnerability Class | Race Condition / Mode Confusion |
| Exploited ITW | No |
| CVSS | 7.0 |
Root Cause
When a 32-bit (WoW64) process on a 64-bit Windows system sends an IOCTL to a kernel streaming device, the request passes through ksthunk.sys, the Kernel Streaming WOW64 Thunk driver. This driver's job is to intercept 32-bit IRPs and convert them to the 64-bit format that the actual kernel streaming driver expects. The conversion involves allocating a new IRP, translating structure layouts (pointer sizes, alignment), and forwarding the converted request.
The vulnerability is in how the new IRP's RequestorMode is set during this conversion. The original IRP from the WoW64 process carries RequestorMode = UserMode (1), correctly reflecting that the request came from user space. When ksthunk.sys allocates the replacement 64-bit IRP, it sets the new IRP's RequestorMode to KernelMode (0) instead of preserving the original value.
This single field change has cascading consequences. Downstream kernel streaming drivers check RequestorMode to decide whether to trust buffer pointers. When RequestorMode is KernelMode, the driver assumes the caller is kernel code and skips user-mode buffer validation (no ProbeForRead, no ProbeForWrite, no address range checks). A WoW64 process can now pass kernel virtual addresses in its IOCTL buffers, and the downstream driver will dereference them without objection.
Discovered by Angelboy at DEVCORE and presented at HEXACON 2024 as part of a broader study of the kernel streaming attack surface.
Exploitation
The mode confusion converts any WoW64 process into a kernel-trusted IOCTL caller. The attacker runs a 32-bit process and sends crafted kernel streaming IOCTLs (such as IOCTL_KS_ENABLE_EVENT) with buffer pointers set to kernel-mode addresses. When ksthunk.sys converts the IRP, the downstream driver sees RequestorMode == KernelMode and processes the kernel addresses without validation.
This gives the attacker a kernel read/write primitive through the IOCTL interface. The specific primitive depends on which kernel streaming IOCTL is used: property get requests can read from arbitrary kernel addresses, and property set requests can write to them.
From kernel read/write, the exploitation follows the standard path: locate the current process's EPROCESS, copy the SYSTEM token, overwrite the current process's token pointer.
The Pwn2Own demonstration and HEXACON presentation showed this chained with other kernel streaming bugs for maximum reliability.
Patch Analysis
The fix preserves the original IRP's RequestorMode when constructing the converted 64-bit IRP in ksthunk.sys. The new IRP now carries RequestorMode = UserMode when the original request came from user space, ensuring downstream drivers apply proper buffer validation.
Broader Significance
CVE-2024-30090 highlights a systemic risk in translation layers. Any time one kernel component creates a new IRP on behalf of another, the security-relevant fields (RequestorMode, buffer pointers, access rights) must be faithfully preserved. ksthunk.sys exists precisely to translate between 32-bit and 64-bit worlds, but the translation silently upgraded the caller's trust level from user to kernel. This bug class is specific to WoW64 thunking, which means it only affects 32-bit processes on 64-bit systems. Testing with 32-bit callers is often an afterthought in driver development, making thunking layers a fruitful audit target.