Windows Kernel Streaming — Attack Surface & Vulnerability Research

Last updated: 2026-04-19
Related: Architecture, Primitives, Race Conditions, Type Confusion, Cve 2023 36802, Cve 2024 35250, Cve 2024 30084, Cve 2024 30090, Cve 2024 38238, Cve 2024 38245
Tags: kernel-mode, race-condition, type-confusion, oob-write, aaw, driver, win32k

Summary

Windows Kernel Streaming (KS) is a multimedia framework operating entirely in kernel mode that handles audio/video data transfer between devices and applications. It provides low latency, excellent scalability, and a unified interface through the ks.sys library and ksthunk.sys thunk service. Between 2023 and 2025 this became a highly productive attack surface, yielding 20+ vulnerabilities. The dominant bug classes — “Proxying to Kernel” (access mode mismatch via IoBuildDeviceIoControlRequest), MDL misuse, and frame buffer misalignment — have been exploited in Pwn2Own Vancouver 2024 and represent an ongoing research frontier.

Key researchers: Angelboy (DEVCORE), chompie1337 (IBM X-Force)


Architecture Overview

User Application
       │
       │  DeviceIoControl (IOCTL_KS_PROPERTY, IOCTL_KS_READ_STREAM, ...)
       ▼
  ksthunk.sys  (Kernel Streaming WOW Thunk Service Driver)
       │  Converts 32-bit → 64-bit requests for WoW64 processes
       │  Pre-allocates MDLs for frame buffers under WoW64
       ▼
   ks.sys  (Kernel Connection and Streaming Architecture Library)
       │  Forwards IOCTL_KS_PROPERTY to correct handler
       │  Manages KS Filters, KS Pins, KS Events, KS Frames
       ▼
  Device driver (portcls.sys, AVStream driver, MSKSSRV, ...)
       │
       ▼
  Hardware device (webcam, audio device, ...)

Key Components

DriverSizeRole
ksthunk.sys~smallEntry point; WoW64 32→64-bit conversion; pre-allocates MDLs
ks.syslargeCore KS library; property/event routing; AVStream; frame management
portcls.sysmediumPort class for PCI/DMA audio devices (volume control, mic processing)
MSKSSRV.sys~72 KBMicrosoft Kernel Streaming Service; present by default in all environments
AVStream driversvariesVideo streaming (webcam, capture cards); USB video, HDMI audio

Multimedia Class Driver Models

  • Port Class (portcls.sys): PCI/DMA-based audio hardware. Volume control, microphone, audio mixing.
  • AVStream: Video streaming and integrated audio/video. Webcam, capture cards.
  • Stream class (legacy): Less common, not discussed.

KS Objects

  • KS Filter: Represents a device or specific function. Audio device → KS Filter with nodes processing data.
  • KS Pin: Data I/O endpoint on a filter. Opened via KsCreatePin; each pin has data format, direction.
  • KS Property: Configuration interface. Set via IOCTL_KS_PROPERTY with a GUID-based KSPROPERTY structure.
  • KS Event: Notification mechanism. Register via IOCTL_KS_ENABLE_EVENT; triggered by device state changes.
  • KS Frame: Kernel structure holding a single data frame (image or audio buffer) during streaming.

Interaction Model

Opening a Device

Devices use long PnP names (e.g., \\?\hdaudio#subfunc_01&...#{6994ad04-...}\ehdmiouttopo). Enumerate via SetupDiGetClassDevs with KSCATEGORY_AUDIO / KSCATEGORY_VIDEO_CAMERA. Open via CreateFile or KsOpenDefaultDevice.

IOCTL_KS_PROPERTY Flow

User → NtDeviceIoControlFile
  → ksthunk (WoW64: 32→64 conversion; else: pass-through)
  → ks.sys KspPropertyHandler
       → validates KSPROPERTY GUID → finds matching handler
       → calls device-specific property handler

Special bulk types (KSPROPERTY_TYPE_SERIALIZESET / UNSERIALIZESET) cause ks.sys to call KsSynchronousIoControlDevice internally to re-issue IOCTLs — this is the root of the Proxying to Kernel bug class.

IOCTL_KS_READ_STREAM Flow

User provides KSSTREAM_HEADER with Data (buffer pointer) and FrameExtent (buffer size):

  1. ks.sys parses KSSTREAM_HEADER, creates MDL from user buffer
  2. User-space buffer mapped to kernel-space via MDL (same physical pages, zero-copy)
  3. KS FRAME (_KSPFRAME_HEADER) allocated with MDL pointer, buffer pointer, sizes
  4. Frame placed in queue; worker thread dequeues, fills with device data
  5. Multiple KSSTREAM_HEADERs in one call → multiple MDLs and frames

Bug Class 1: Proxying to Kernel (Access Mode Mismatch)

Background

IoBuildDeviceIoControlRequest creates a DeviceIoControl IRP. Per MSDN: if RequestorMode is not explicitly set, it defaults to KernelMode(0). This means any driver calling KsSynchronousIoControlDevice sends a KernelMode IRP to the next handler, bypassing security checks that rely on Irp->RequestorMode.

This is a variant of the broader IO Manager access mode mismatch bug class documented by James Forshaw (Project Zero, 2019).

KsSynchronousIoControlDevice Bug Pattern

// ks.sys — all internal callers use KernelMode(0):
KsSynchronousIoControlDevice(
    FileObject,
    0,           // ← KernelMode — always!
    IoControlCode,
    InputBuffer,
    InputSize,
    OutputBuffer,
    OutputSize,
    &BytesReturned
);

Every function in ks.sys that calls KsSynchronousIoControlDevice passes 0 (KernelMode). If user input reaches InputBuffer/OutputBuffer AND the downstream handler checks Irp->RequestorMode before performing security-sensitive operations, privilege escalation is possible.

Pattern to hunt:

  1. Code path uses KsSynchronousIoControlDevice
  2. User-controlled InputBuffer / OutputBuffer
  3. Downstream handler checks RequestorMode == KernelMode to enable privileged operations

CVE-2024-35250 — KSPROPERTY_TYPE_UNSERIALIZESET (Pwn2Own 2024)

Location: ks.sys UnserializePropertySet
Bug class: Access mode mismatch + privileged code path in ksthunk

// ks.sys UnserializePropertySet:
New_KsProperty_req = ExAllocatePoolWithTag(...);
memmove(New_KsProperty_req, CurrentStackLocation->Type3InputBuffer, InSize); // [1] copy user data
status = KsSynchronousIoControlDevice(
    FileObject, 0 /*KernelMode*/,
    IoControlCode, New_KsProperty_req, InSize,
    OutBuffer, OutSize, &BytesReturned); // [2] KernelMode IOCTL

// ksthunk.sys CKSThunkDevice::CheckIrpForStackAdjustmentNative:
if (*Type3InputBuffer->Set == KSPROPSETID_DrmAudioStream
    && !type3inputbuf.Id && (type3inputbuf.Flags & 2)) {
    if (irp->RequestorMode) { // [3] ← KernelMode passes!
        return STATUS_INVALID_DEVICE_REQUEST; // user fails here
    }
    // [4] arbitrary call: Type3InputBuffer+0x38 called with controllable args!
    result = (*((PVOID**)(Type3InputBuffer + 0x38)))(
        *UserBuffer, 0, v19);
}

Impact: Arbitrary call with first parameter controlled. Requires KSPROPSETID_DrmAudioStream — available on any system with an audio device.

CFG bypass: Use RtlSetAllBits (exported from ntoskrnl.exe — valid CFG target):

struct _RTL_BITMAP { ULONG SizeOfBitMap; ULONG* Buffer; };
// Buffer → Token->Privileges; SizeOfBitMap large → sets all privilege bits

Severity: User → SYSTEM; Pwn2Own Vancouver 2024; existed since Windows 7 (~20 years).

CVE-2024-30084 — Double Fetch in UnserializePropertySet

Root cause: IOCTL_KS_PROPERTY uses Neither I/O, meaning Type3InputBuffer remains in user memory (not captured). KspPropertyHandler copies it once to validate the KSPROPERTY GUID, then UnserializePropertySet copies it again from the original user pointer.

Attack: Race the two copies:

  1. Send KSPROPSETID_Service property (MSKSSRV supports it) → passes GUID check in first copy
  2. Between checks and UnserializePropertySet, swap buffer to KSPROPSETID_DrmAudioStream
  3. UnserializePropertySet re-reads Type3InputBuffer → sees KSPROPSETID_DrmAudioStream → triggers CVE-2024-35250

Impact: Makes CVE-2024-35250 exploitable on Hyper-V (no audio device) via MSKSSRV. Combined exploit chains: CVE-2024-30084 + CVE-2024-35250.

CVE-2024-30090 — IOCTL_KS_ENABLE_EVENT Double Fetch (Part II)

Location: ksthunk.sys CKSAutomationThunk::ThunkEnableEventIrp
Trigger: WoW64 process; KSEVENT_TYPE_QUERYBUFFER flag

// ksthunk CKSAutomationThunk::ThunkEnableEventIrp:
if (Flags == KSEVENT_TYPE_QUERYBUFFER) {
    newinputbuf = ExAllocatePoolWithTag(..., inputbuflen + 8, 'bqSK');
    memcpy(newinputbuf, Type3InputBuffer, 0x28);  // [1] copy from user
    KsSynchronousIoControlDevice(FileObject, 0 /*KernelMode*/,
        IOCTL_KS_ENABLE_EVENT, newinputbuf, ...);  // [2] KernelMode
}

Also Neither I/O: Race KSEVENT_TYPE_QUERYBUFFER (checked) → KSEVENT_TYPE_ENABLE (used in new IOCTL).

Downstream impact: When called with KernelMode, ks.sys KspEnableEvent allows KSEVENTF_KSWORKITEM notification type — user passes a kernel address as a KSWORKITEM pointer.

Primitive: Arbitrary kernel address increment by 1 (via KsIncrementCountedWorker).

Novel EoP: Modify nt!SeDebugPrivilege global variable (in writable section!):

nt!SeDebugPrivilege = LUID {LowPart=0x14, HighPart=0}  (default)

Increment from 0x140x17 (SeChangeNotifyPrivilege). Now NtOpenProcess (via SeSinglePrivilegeCheck checking SeDebugPrivilege) uses 0x17 instead. Any user with SeChangeNotifyPrivilege (everyone) bypasses the check and gets PROCESS_ALL_ACCESS on any process except PPL.

nt!SeDebugPrivilege is at address in .data section (writable, even under KPP)
Default value: 0x0000000000000014 (LUID)
Target value:  0x0000000000000017 (SeChangeNotifyPrivilege LUID)
Single increment: 0x14 → 0x17 requires 3 increments (at the right byte)

Presented: HEXACON 2024.


Bug Class 2: MDL Mismatch in KS Frames

Background

When a WoW64 32-bit request arrives, ksthunk.sys pre-allocates MDLs for frames. Then ks.sys processes the same request, deciding whether to allocate MDLs based on the same OptionsFlags — but with opposite logic:

OptionsFlags bitksthunk actionks.sys action
KSSTREAM_HEADER_OPTIONSF_PERSIST_SAMPLE (0x8000) SETSkip MDL allocationAllocate new MDL
KSSTREAM_HEADER_OPTIONSF_PERSIST_SAMPLE CLEARAllocate MDLSkip (assumes ksthunk did it)

Attack

Submit two KSSTREAM_HEADERs in one IOCTL:

  • Frame 1: buffer size 0x1000, set cache flag (0x8000)
  • Frame 2: buffer size 0x20000, no cache flag

ksthunk: allocates MDL for Frame 2 (large), skips Frame 1.
ks.sys: allocates MDL for Frame 1 (via IRP MDL chain), skips Frame 2.

Result: KS FRAME for Frame 1 gets paired with Frame 2’s MDL (large buffer), but FrameExtent says 0x20000. Worker copies 0x20000 bytes into a 0x1000-byte buffer → heap overflow.

CVEs: CVE-2024-38237, CVE-2025-21375, and others.


Bug Class 3: Forgotten Lock in MDL (Uninitialized PFN Array)

Root Cause

IoAllocateMdl allocates the MDL structure and initializes metadata but does NOT initialize the PFN (Page Frame Number) array. Only MmProbeAndLockPages initializes PFNs. If MmMapLockedPagesSpecifyCache is called on an unlocked MDL, it uses the uninitialized PFN array — containing stale pool data.

CVE-2024-38238

Triggered via CKsMdlcache::MdlCacheHandleThunkBufferIrp:

  1. Submit Frame 1 (cache flag set) + Frame 2 (no cache flag)
  2. Frame 1: ks.sys allocates MDL via IoAllocateMdlno lock
  3. Frame 2: ks.sys calls KsProbeStreamIrp
  4. KsProbeStreamIrp checks only the first MDL in chain for lock status:
if ((MDL->MdlFlags & is_locked_and_nonpaged) != 0) {  // [only checks first MDL!]
    while (MDL) {
        MappedSystemVa = MmMapLockedPagesSpecifyCache(MDL, ...);  // maps ALL MDLs
        MDL = MDL->Next;
    }
}

Impact: MmMapLockedPagesSpecifyCache called on unlocked MDL with uninitialized PFN array.

Exploitation via Pool Spray

IoAllocateMdl allocates from NonPagedPoolNx with POOL_FLAG_UNINITIALIZED — no zero-init. The PFN array contains stale memory.

Pool spray technique: Use named pipes to spray NonPagedPoolNx with controlled data at the exact size matching the MDL allocation. When IoAllocateMdl reuses sprayed memory, the PFN array contains attacker-controlled values → arbitrary physical memory write when worker copies device data via those PFNs.

Controlled-data write: Use KSSTREAM_HEADER_OPTIONSF_BUFFEREDTRANSFER (buffered mode). KS allocates an intermediate buffer, copies device data into it, then copies intermediate buffer into frame buffer. The intermediate copy is at a physical address we control (via PFN spray), but we now control what goes there: the data from the intermediate buffer (which contains whatever the device wrote) is fully attacker-controlled via the buffered flag.

EoP: ntoskrnl.exe base physical address is often fixed at 0x100400000 on Windows 24H2 (both Hyper-V and VMware). Overwrite security check in PsOpenProcess — replace SeDebugPrivilege check with SeChangeNotifyPrivilege (same technique as Part II).

CVEs: CVE-2024-38238, CVE-2024-38241, CVE-2025-24046 (double free variant), CVE-2025-24066


Bug Class 4: Frame Buffer Misalignment (CVE-2024-38245)

KS Allocator

KsCreateAllocator creates a pool of pre-allocated frame buffers. DefAllocatorAlloc allocates with alignment:

char *DefAllocatorAlloc(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Alignment) {
    buffer = ExAllocatePoolWithTag(PoolType | 0x400, size, 'adSK'); // [1]
    padding = (~FileAlignment & (buffer + FileAlignment + 4)) - buffer;
    buffer += padding;
    *(buffer - 1) = padding;  // [2] store padding size before buffer
}

Vulnerability

KS only validates alignment mask >= FILE_OCTA_ALIGNMENT (0xFFF). Values below 0xFFF are accepted without power-of-two validation. Supplying alignment = 7 (results in 8-byte padding) causes all buffers to have addresses ending in 0x8 — not 0x10-byte aligned.

LookasideList Corruption

LookasideList entries must be 0x10-byte aligned (SLIST_ENTRY). On free:

ExFreeToNPagedLookasideList:
    NextChunk = ListHead->FreeChunk & 0xFFFFFFFFFFFFFFF0;  // align to 0x10
    Chunk->Next = NextChunk;

When a misaligned buffer (address ending 0x8) is freed, its Next field points to a 0x10-aligned address. After freeing A→B→C→D (each at 0x???8):

  • D’s Next = aligned(C) → points to the padding bytes before C’s frame buffer
  • The 4 bytes at *(buffer_C - 4) contain the padding size (e.g., 0x8)
  • As a 64-bit pointer: 0x0000000800000000 → falls in user-mode address range!

Attack:

  1. Allocate page at 0x800000000 — control LookasideList traversal
  2. Construct fake linked list entry pointing to target kernel address
  3. On next allocation, allocator traverses fake list → target address gets written as frame data destination
  4. Trigger STOP → free all frames → LookasideList contains target address entry
  5. Next pool allocation returns target address → Next pointer of target corrupted to user-controlled value → arbitrary memory write

EoP: Use NtQuerySystemInformation to find ETHREAD address. Write to token privilege bits via arbitrary write. Must restore LookasideList after exploit to prevent crash.


Bug Class 5: MSKSSRV Type Confusion (CVE-2023-36802)

mskssrv.sys implements the Windows Camera Frame Server — virtualizes physical cameras so multiple apps can share one device. Its IOCTL interface has a separate type system from ks.sys.

Root Cause

FSRendezvousServer::FindObject() returns FILE_OBJECT.FsContext2 without validating the object type. IOCTL_FRAMESERVER_INIT_CONTEXT (0x2F0400) stores a small FsContextReg (0x78 bytes) there, while IOCTL_FRAMESERVER_PUBLISH_RX (0x2F040C) passes FsContext2 to FSStreamReg::PublishRx(), which expects the larger FSStreamReg (0x1D8 bytes).

FsContextReg size:  0x78 bytes
FSStreamReg size:   0x1D8 bytes
Critical offset:    FSStreamReg+0x1C8 → 0x150 bytes PAST end of FsContextReg
→ FsContextReg[0x1C8] = attacker-controlled adjacent pool data (named pipe spray)

Exploit Primitive: ObfDereferenceObject Arbitrary Decrement

FSStreamReg::PublishRx() calls ObfDereferenceObject(ptr + 0x1C8) where ptr + 0x1C8 is attacker-controlled. ObfDereferenceObject(addr) atomically decrements *(addr - 0x30).

Attacker places: (KTHREAD + 0x232 + 0x30) at FsContextReg+0x1C8 offset in pool
ObfDereferenceObject sees addr = KTHREAD + 0x262
Decrement target: KTHREAD + 0x262 - 0x30 = KTHREAD + 0x232 = PreviousMode
PreviousMode: 1 → 0 → NtReadVirtualMemory/NtWriteVirtualMemory act KernelMode

Pool Spray (NonPagedPoolNx, 0x90 bytes)

Named pipe unbuffered write via NtFsControlFile(IOCTL=0x119FF8), 0x80 payload → 0x90 allocation:

Spray 0x10000 entries; free every 4th to create holes → allocate FsContextReg into hole
Adjacent named pipe data at FsContextReg+0x150 contains KTHREAD+0x262

Crash Avoidance

FSStreamReg::PublishRx() calls KeSetEvent on a fake structure → BSOD. Mitigated by:

  • Running PUBLISH_RX from a secondary thread
  • Setting FSStreamReg+0x1A8 (ProcessBilled) = NULL in adjacent data → skips pool billing crash
  • Self-referencing FSFrameMdl::MoveNext Flink/Blink → keeps secondary thread in loop
  • Main thread signals secondary thread to break loop once PreviousMode is flipped

In-the-Wild CLFS Path

ITW exploit replaced PreviousMode decrement with CLFS vtable dispatch:

  1. Create CLFS log file → leak kernel address
  2. Place fake CClfsContainer with fake vtable at FsContextReg+0x1C8 target
  3. FSFrameMdl::UnmapPages() calls vtable dispatch on forged object
  4. Gadget: PoFxProcessorNotificationRtlClearBit → zero a kernel security field

Patch

FindObject() renamed to FindStreamObject() with added check: obj->TypeField == 2 (only set in FSStreamReg constructor). FsContextReg has a different TypeField value → returns FALSE.


Historical Vulnerabilities (MSKSSRV)

CVEBug ClassDiscovered ByNotes
CVE-2023-29360AccessMode mismatch in MmProbeAndLockPagesSynacktivPwn2Own 2023; kernel addr → user-space mapping; ITW
CVE-2023-36802Type confusion: FsContextReg/FSStreamReg; ObfDereferenceObject decrementchompie1337ITW when patched (Sept 2023); CLFS-based ITW path documented
CVE-2024-30089Race condition / reference countchompie1337IBM X-Force “The Little Bug That Could” blog

Other KS Bugs (portcls / ksthunk)

CVEComponentBug
CVE-2024-38055portcls.sysOOB read — unchecked length in SetDataFormat for Pin
CVE-2024-38056portcls.sysRelated OOB
CVE-2024-38054ksthunk.sysOOB write — unchecked index; public exploit by @Fr0st1706
CVE-2024-38057ksthunk.sysRelated OOB
CVE-2020-16889ks.sysLast known vuln before 2023 wave
CVE-2020-17045ks.sysFound by @nghiadt1098

Attack Surface Map

Attacker (Medium IL)
        │
        ├─ mskssrv.sys IOCTLs (Frame Server)
        │         ├─ IOCTL_FRAMESERVER_INIT_CONTEXT (0x2F0400) → place FsContextReg in FsContext2
        │         └─ IOCTL_FRAMESERVER_PUBLISH_RX (0x2F040C) → type confusion FsContextReg/FSStreamReg
        │                  └─ ObfDereferenceObject(FsContextReg+0x1C8) → arbitrary decrement
        │                           └─ target KTHREAD.PreviousMode → kernel R/W  [CVE-2023-36802]
        │
        ├─ IOCTL_KS_PROPERTY (Neither I/O → double fetch opportunity)
        │         └─ UnserializePropertySet → KsSynchronousIoControlDevice (KernelMode)
        │                  └─ ksthunk KSPROPSETID_DrmAudioStream → arbitrary call [CVE-2024-35250]
        │
        ├─ IOCTL_KS_ENABLE_EVENT (WoW64 path → ThunkEnableEventIrp)
        │         └─ KSEVENT_TYPE_QUERYBUFFER → KsSynchronousIoControlDevice (KernelMode)
        │                  └─ ks.sys KspEnableEvent KSEVENTF_KSWORKITEM → addr++  [CVE-2024-30090]
        │
        └─ IOCTL_KS_READ_STREAM (WoW64 path → MDL pre-allocation)
                  ├─ MDL mismatch via PERSIST_SAMPLE flag → heap overflow  [CVE-2024-38237]
                  ├─ Forgotten MDL lock → uninitialized PFN → phys mem write  [CVE-2024-38238]
                  └─ KS Allocator misalignment → LookasideList corruption  [CVE-2024-38245]

Hunting Strategy

  1. IoBuildDeviceIoControlRequest callers: Any kernel driver calling IoBuildDeviceIoControlRequest without explicitly setting RequestorMode to UserMode in the IRP before IofCallDriver → check if downstream handler uses RequestorMode for security decisions.

  2. Neither I/O IOCTLs: IOCTLs using METHOD_NEITHER that read from Type3InputBuffer twice (once for validation, once for use) → double fetch opportunity.

  3. MDL lifecycle: IoAllocateMdlMmMapLockedPagesSpecifyCache without MmProbeAndLockPages in between → uninitialized PFN.

  4. Alignment mask validation: Any allocation that accepts user-supplied alignment mask without validating it’s a power-of-two mask → LookasideList corruption potential.

  5. Frame buffer size tracking: Multiple KSSTREAM_HEADER structures with mixed OptionsFlags → cross-check MDL sizes against FrameExtent values.

  6. MSKSSRV object dispatch without type check: Any IOCTL handler that retrieves FILE_OBJECT.FsContext/FsContext2 and passes it to a typed method without checking a type discriminant → look for methods expecting large structs when small structs can be placed via a separate initialization IOCTL.


Exploit Relevance

  • Kernel Streaming is present in every Windows installation (ks.sys, ksthunk.sys, MSKSSRV)
  • Audio device required for CVE-2024-35250 ksthunk path, but CVE-2024-30084 double fetch makes it exploitable via MSKSSRV on any system (including Hyper-V)
  • MDL-class bugs (38238, 38245) require WoW64 or 32-bit process context
  • Physical address predictability (ntoskrnl.exe at 0x100400000 on Win24H2) is hardware/config-dependent
  • 20+ CVEs found in 2023–2024; research ongoing (Part III of series at OffensiveCon 2025)
  • Adjacent components worth fuzzing: Hdaudio.sys, Usbvideo.sys, portcls.sys device-specific property handlers

References

  • Angelboy (DEVCORE), “Streaming vulnerabilities from Windows Kernel - Proxying to Kernel - Part I”, devco.re, 2024-08-23
  • Angelboy (DEVCORE), “Streaming vulnerabilities from Windows Kernel - Proxying to Kernel - Part II”, devco.re, 2024-10-05
  • Angelboy (DEVCORE), “Frame by Frame, Kernel Streaming Keeps Giving Vulnerabilities”, devco.re, 2025-05-17 (OffensiveCon 2025)
  • chompie1337 (IBM X-Force), “Critically Close to Zero-Day: Exploiting Microsoft Kernel Streaming Service” — CVE-2023-36802
  • chompie1337 (IBM X-Force), “The Little Bug That Could” — CVE-2024-30089
  • Synacktiv, “Windows Kernel Security: A Deep Dive into Two Exploits Demonstrated at Pwn2Own” (HITB 2023 HKT) — CVE-2023-29360
  • James Forshaw (Project Zero), “Windows Kernel Logic Bug Class: Access Mode Mismatch in IO Manager”, projectzero.google, 2019-03
  • James Forshaw (Project Zero), “Hunting for Bugs in Windows Mini-Filter Drivers”, projectzero.google, 2021-01
  • @Fr0st1706, CVE-2024-38054 exploit, github.com/Black-Frost/windows-learning
  • Microsoft Learn, “Kernel Streaming” — learn.microsoft.com/en-us/windows-hardware/drivers/stream/kernel-streaming