
Educational proof-of-concept for PrintNightmare (CVE-2021-1675/34527) with simulated non-functional payload, attack flow analysis, MITRE mapping, detection guidance, and remediation steps.
Type: Proof of Concept — Simulated (Non-Functional) CVE: CVE-2021-1675 + CVE-2021-34527 CVSS: 7.8 (LPE) / 8.8 (RCE) Alias: PrintNightmare Patched: June/July 2021 — KB5004945 Added to CISA KEV: July 2021
⚠️ The payload of this PoC is explicitly fictitious and non-malicious — just 4 bytes of DCE/RPC header followed by the function name in ASCII. It does not execute code, does not install a driver, does not escalate privileges. For exclusive use for learning and detection development purposes.
Developed by: HKK$ cat ./vulnerability_summary.txtCVE-2021-1675, known as PrintNightmare, is a critical Remote Code Execution and Local Privilege Escalation vulnerability in the Windows Print Spooler service. The flaw allows attackers to execute arbitrary code with SYSTEM privileges by exploiting the RpcAddPrinterDriverEx() function, used for remote installation of printer drivers without adequate access control validation.
Originally classified as LPE (CVSS 7.8) and patched in the June 2021 Patch Tuesday, Microsoft reclassified the vulnerability as RCE (CVSS 8.8) on June 21. To avoid confusion, the RCE vector received a new identifier, CVE-2021-34527 — both are commonly called PrintNightmare.
$ cat ./timeline.txtJun 08, 2021 Microsoft publishes initial patch on Patch Tuesday — CVE-2021-1675 (LPE, CVSS 7.8)
Jun 21, 2021 Microsoft reclassifies as RCE (CVSS 8.8)
Jun 29, 2021 Researchers accidentally publish PoC — believing it to be the same already-patched vuln
Jul 01, 2021 CVE-2021-34527 assigned to the RCE vector — distinct from the original LPE
Jul 02, 2021 Microsoft releases emergency out-of-band patch: KB5004945
Jul 2021 CISA adds to Known Exploited Vulnerabilities Catalog
Active exploitation by ransomware groups (Vice Society, Magniber, etc.)
$ cat ./architecture.txt┌──────────────────────────────────────────────────────────────────────────┐
│ PRINTNIGHTMARE — ATTACK FLOW │
│ │
│ ATTACKER (authenticated user) WINDOWS PRINT SPOOLER │
│ (spoolsv.exe) │
│ 1. Authenticate with any ┌────────────────────────────┐ │
│ valid domain account │ Runs as SYSTEM │ │
│ │ │ Active by default on all │ │
│ 2. Connect via RPC to │ Windows, including DCs │ │
│ named pipe \pipe\spoolss └──────────────┬─────────────┘ │
│ │ │ │
│ 3. Call RpcAddPrinterDriverEx() │ │
│ with path to malicious DLL ───────────────────────►│ │
│ (UNC: \\attacker\share\evil.dll) │ │
│ ┌────────────▼────────────┐ │
│ │ Print Spooler loads │ │
│ │ the driver (DLL) as │ │
│ │ SYSTEM without checking │ │
│ │ origin or integrity │ │
│ └────────────┬────────────┘ │
│ │ │
│ ◄── RCE / LPE as SYSTEM ──────────────────────────────┘ │
│ New admin user, reverse shell, │
│ ransomware deployment, etc. │
│ │
│ ───────────────────────────────────────────────────────────────────── │
│ THIS POC: just TCP connect + 25 bytes → no real RPC → no exploit │
└──────────────────────────────────────────────────────────────────────────┘
$ cat ./design_decisions.mdfake_rpc_payload = b"\x05\x00\x0b\x03RpcAddPrinterDriverEx"
This payload is 25 bytes and demonstrates two concepts simultaneously:
Bytes 0-3: Legitimate DCE/RPC Header
| Byte | Value | Meaning |
|---|---|---|
\x05 | 5 | DCE/RPC protocol version (version 5 — Windows standard) |
\x00 | 0 | Minor version 0 |
\x0b | 11 | PDU Type: BIND — first step of RPC negotiation |
\x03 | 3 | Flags: `PFC_FIRST_FRAG(0x01) |
Bytes 4-24: Function name in ASCII
RpcAddPrinterDriverEx — the name of the vulnerable function, in plain text.
Why doesn't this payload work as a real exploit?
A legitimate RPC BIND would require, after the 4-byte header:
- max_xmit_frag (2 bytes)
- max_recv_frag (2 bytes)
- assoc_group_id (4 bytes)
- num_ctx_items (1 byte)
- context_elem[] → MS-RPRN Interface UUID:
{12345678-1234-ABCD-EF00-0123456789AB}
- transfer_syntaxes → NDR UUID
Without this structure, Windows rejects the packet immediately. The payload is, effectively, just a connectivity assertion — "can I reach port 445 with this fictitious payload?".
sock.connect((target_ip, 445))
Why 445 and not 135 (RPC Endpoint Mapper)?
PrintNightmare uses the SMB named pipe \pipe\spoolss as transport — not direct RPC. The real flow is:
1. TCP connect → port 445 (SMB)
2. SMB negotiate + session setup (NTLM/Kerberos authentication)
3. Tree connect → IPC$
4. Named pipe open → \pipe\spoolss
5. DCE/RPC BIND → MS-RPRN interface
6. RpcAddPrinterDriverEx() call with NDR marshaling
The PoC simulates only step 1 — the initial TCP connection — without implementing steps 2-6.
sock.settimeout(5): a 5-second timeout prevents the PoC from hanging on hosts that don't respond. Useful for quick scanning of port availability.
| Aspect | CVE-2021-1675 | CVE-2021-34527 |
|---|---|---|
| Vector | Local (LPE) | Remote (RCE) |
| CVSS | 7.8 | 8.8 |
| Authentication | Local account | Authenticated domain account |
| Patch | June 2021 (Patch Tuesday) | July 2021 (out-of-band KB5004945) |
| Vulnerable function | RpcAddPrinterDriverEx | RpcAddPrinterDriverEx |
| Scenario | Local escalation | Remote RCE via SMB named pipe |
The root cause in both is the same: the RpcAddPrinterDriverEx() function fails to validate the origin of driver files, does not enforce adequate privilege restrictions for driver installation, and does not verify the authenticity or integrity of the DLLs being loaded.
$ cat ./mitre_mapping.ymltactic: Initial Access / Lateral Movement
- T1210 # Exploitation of Remote Services
# RPC call via \pipe\spoolss to remote host
# Requires valid domain credential
tactic: Privilege Escalation
- T1068 # Exploitation for Privilege Escalation
# regular user → SYSTEM via Print Spooler
# CVE-2021-1675 (LPE): local process elevates to SYSTEM
tactic: Execution
- T1569.002 # System Services: Service Execution
# Malicious DLL loaded by spoolsv.exe as SYSTEM
# Equivalent to code execution via Windows service
- T1055 # Process Injection
# DLL injected into the context of the spoolsv.exe process (SYSTEM)