# CVE-2020-0986: Windows splwow64 Untrusted Pointer Dereference

Untrusted pointer dereference in splwow64's GdiPrinterThunk lets a low-integrity IE renderer send crafted LPC messages to gain arbitrary write in medium-integrity splwow64, escaping the sandbox.

- Payout: Real-world hack
- Severity: high
- Program: Microsoft Windows
- Credited: Maddie Stone, Project Zero (Originally posted on [Project Zero blog](https://googleprojectzero.blogspot.com/p/rca.html) 2020-09-02)
- Disclosed: 2020-05-19
- CVE: CVE-2020-0986
- Write-up quality: 8/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2020/CVE-2020-0986.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2020-0986
- Tags: impact:privesc impact:rce kind:incident platform:project-zero sev:high technique:chained technique:incomplete-fix technique:source-review vuln:memory-corruption vuln:privilege-escalation vuln:sandbox-escape

**Target:** splwow64 / gdi32full!GdiPrinterThunk LPC message handler
**Root cause:** GdiPrinterThunk trusts pointers supplied in an LPC message (msg type 0x6D DocumentEvent) and passes attacker-controlled source, destination and size directly to memcpy without validation.
**Steps:**
1. Start splwow64 by invoking CreateDCW on 'Microsoft XPS Document Writer' (or CreateDC.exe).
2. Derive port name `\RPC Control\UmpdProxy_<sessionId>_<tokenstats>_0x2000` via NtOpenProcessToken/ZwQueryInformationToken.
3. Create shared section (0x20000) and connect with ZwSecureConnectPort using PORT_VIEW (Length 0x30, ViewSize 0x9000).
4. Craft PORT_MESSAGE: DataSize 0x20, MessageSize 0x48, MsgSendLen 0x88, PtrMsgSend=ViewRemoteBase, MsgReplyLen 0x10, PtrMsgReply=ViewRemoteBase+0x88.
5. In shared buffer set msg type 0x6D at +0x04, iEsc at +0x38 (0x04/0x01), pointer-to-source at +0x50, dest at +0x58; size read from `[src+0x40]`.
6. Send via NtRequestWaitReplyPort to trigger memcpy at gdi32full!GdiPrinterThunk+0x1E85A with arbitrary args.
**How found:** Variant analysis: bug is a shallow variant of CVE-2019-0880 (also exploited in the wild), found by auditing GdiPrinterThunk for untrusted pointer dereferences.
**Exploitation:** Chained with CVE-2020-1380 (IE RCE) in Operation PowerFall: attacker with code execution in the LOW-integrity IE renderer sends the crafted LPC message to splwow64, obtaining an arbitrary write primitive in the MEDIUM-integrity splwow64 address space to escape the sandbox.
**Escalation:** Chained RCE (CVE-2020-1380) in IE renderer with this EoP to break out of the sandbox; the flawed pointer-to-offset patch was later bypassed as CVE-2020-17008/CVE-2021-1648.
**Insight:** Legacy LPC/RPC ports like splwow64 accept raw pointers in message payloads; audit GdiPrinterThunk-style handlers for memcpy args taken straight from shared-memory message fields, and check whether a pointer-to-offset 'fix' still leaves all three memcpy args attacker-controlled.
