# CVE-2023-36802: Microsoft Streaming Service Proxy Elevation of Privilege Vulnerability

Type confusion in mskssrv.sys: INIT_CONTEXT stores an FsContextReg where PublishRx expects FsStreamReg, giving OOB writes used to zero PreviousMode and gain kernel R/W.

- Payout: Real-world hack
- Severity: high
- Program: Windows
- Credited: Benoît Sevens
- Disclosed: 2023-09-12
- CVE: CVE-2023-36802
- Write-up quality: 10/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2023/CVE-2023-36802.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2023-36802
- Tags: domain:desktop impact:privesc impact:rce kind:incident platform:project-zero sev:high tech:windows technique:chained technique:source-review vuln:memory-corruption vuln:privilege-escalation

**Target:** mskssrv.sys kernel streaming service driver (IOCTL_FRAMESERVER_* handlers)
**Root cause:** FSRendezvousServer::FindObject() validated object presence but not type, so FSStreamReg::PublishRx() treated an FsContextReg (0x78 bytes) as an FsStreamReg (0x1d8 bytes), reading fields out of bounds into neighboring pool chunks.
**Steps:**
1. Open device via `KsOpenDefaultDevice(KSNAME_Server, GENERIC_READ|GENERIC_WRITE, &h)`.
2. Leak KTHREAD, EPROCESS/Token, and FILE_OBJECT addresses via `NtQuerySystemInformation(SystemExtendedHandleInformation)`.
3. Spray 0x80-byte pool chunks with `NtFsControlFile` fsctl `0x119ff8` (named pipe technique), then close some to create holes.
4. Send `IOCTL_FRAMESERVER_INIT_CONTEXT` with `*(int32_t*)buf=1` to allocate FsContextReg (0x78) into a hole and set FILE_OBJECT->FsContext2.
5. Refill remaining holes with attacker-controlled data placing PreviousMode address at the OOB field offset.
6. In a separate thread send `IOCTL_FRAMESERVER_PUBLISH_RX` with `*((DWORD*)buf+8)=1; *((DWORD*)buf+9)=1` to trigger ObfDereferenceObject on PreviousMode, decrementing it to 0.
7. Forge a self-referencing usermode list entry so FSFrameMdlList::MoveNext loops, holding PublishRx before KeSetEvent.
8. In main thread use `NtReadVirtualMemory`/`NtWriteVirtualMemory` to copy System token into current EPROCESS, NULL the ProcessBilled field, break the loop, restore state, reset PreviousMode, spawn cmd.exe.
**How found:** Project Zero analyzed an in-the-wild exploit sample; the bug itself was independently found by Valentina Palmiotti via manual code auditing of mskssrv.sys IOCTL handlers, noting FindObject checked presence but not type.
**Exploitation:** In-the-wild sample used the ObfDereferenceObject call in newer mskssrv.sys to decrement PreviousMode to 0, then NtReadVirtualMemory/NtWriteVirtualMemory to steal the System token; on older builds it instead used FSFrameMdl::UnmapPages OOB writes to corrupt a CLFS log offset, pivoting through a fake CClfsContainer vtable to nt!PoFxProcessorNotification -> nt!RtlClearBit to zero PreviousMode.
**Escalation:** Chained pool grooming + kernel address leak + type confusion to obtain arbitrary kernel R/W, then token theft for SYSTEM; CLFS variant chains a second bug class (CLFS offset corruption) to reach a controlled vtable call under CFG.
**Insight:** When a driver stores a context pointer in FILE_OBJECT->FsContext2 across multiple IOCTLs, check whether each handler validates the object's type tag, not just non-NULL; mixing INIT and PUBLISH/CONSUME IOCTLs on one handle is a cheap type-confusion trigger, and OOB field reads into adjacent pool chunks turn into decrement/write primitives on fields like PreviousMode.
