
# PrintNightmare (CVE-2021-1675/34527) 교육용 개념 증명 시뮬레이션된 비기능적 페이로드, 공격 흐름 분석, MITRE 매핑, 탐지 지침 및 복구 절차를 포함한 PrintNightmare(CVE-2021-1675/34527) 교육용 개념 증명입니다.
유형: 개념 증명 — 시뮬레이션(비기능) CVE: CVE-2021-1675 + CVE-2021-34527 CVSS: 7.8 (LPE) / 8.8 (RCE) 별칭: PrintNightmare 패치됨: 2021년 6월/7월 — KB5004945 CISA KEV 추가: 2021년 7월
⚠️ 이 PoC의 페이로드는 명시적으로 가상이며 비악성입니다 — DCE/RPC 헤더 4바이트와 함수 이름(ASCII)뿐입니다. 코드를 실행하지 않으며, 드라이버를 설치하지 않고, 권한을 상승시키지 않습니다. 학습 및 탐지 개발 목적으로만 사용됩니다.
Developed by: HKK$ cat ./vulnerability_summary.txtCVE-2021-1675는 PrintNightmare로 알려져 있으며, Windows Print Spooler 서비스의 치명적인 원격 코드 실행 및 로컬 권한 상승 취약점입니다. 이 결함으로 인해 공격자는 적절한 접근 제어 검증 없이 프린터 드라이버의 원격 설치에 사용되는 RpcAddPrinterDriverEx() 함수를 악용하여 SYSTEM 권한으로 임의 코드를 실행할 수 있습니다.
원래 LPE(CVSS 7.8)로 분류되어 2021년 6월 패치 화요일에 패치되었지만, Microsoft는 6월 21일에 이 취약점을 RCE(CVSS 8.8)로 재분류했습니다. 혼란을 피하기 위해 RCE 벡터에는 CVE-2021-34527이라는 새로운 식별자가 부여되었습니다 — 둘 다 일반적으로 PrintNightmare라고 불립니다.
$ cat ./timeline.txt2021년 6월 8일 Microsoft가 패치 화요일에 초기 패치 게시 — CVE-2021-1675 (LPE, CVSS 7.8)
2021년 6월 21일 Microsoft가 RCE(CVSS 8.8)로 재분류
2021년 6월 29일 연구원들이 이미 패치된 동일한 취약점으로 착각하고 PoC를 실수로 공개
2021년 7월 1일 원래 LPE와 구분되는 RCE 벡터에 CVE-2021-34527 지정
2021년 7월 2일 Microsoft가 긴급 대역외 패치 출시: KB5004945
2021년 7월 CISA가 알려진 악용 취약점 카탈로그에 추가
랜섬웨어 그룹(Vice Society, Magniber 등)의 활발한 악용
$ cat ./architecture.txt┌──────────────────────────────────────────────────────────────────────────┐
│ PRINTNIGHTMARE — 공격 흐름 │
│ │
│ 공격자 (인증된 사용자) WINDOWS PRINT SPOOLER │
│ (spoolsv.exe) │
│ 1. 유효한 도메인 계정으로 ┌────────────────────────────┐ │
│ 인증 │ SYSTEM으로 실행 │ │
│ │ │ 모든 Windows에서 기본 활성, │ │
│ 2. RPC를 통해 named pipe │ DC 포함 │ │
│ \pipe\spoolss에 연결 └──────────────┬─────────────┘ │
│ │ │ │
│ 3. 악성 DLL 경로로 RpcAddPrinterDriverEx() 호출 │ │
│ (UNC: \\attacker\share\evil.dll) ─────────────────►│ │
│ ┌────────────▼────────────┐ │
│ │ Print Spooler가 출처나 │ │
│ │ 무결성을 확인하지 않고 │ │
│ │ 드라이버(DLL)를 SYSTEM │ │
│ │ 권한으로 로드 │ │
│ └────────────┬────────────┘ │
│ │ │
│ ◄── SYSTEM 권한의 RCE / LPE ──────────────────────────┘ │
│ 새 관리자 사용자 생성, 리버스 셸, │
│ 랜섬웨어 배포 등 │
│ │
│ ───────────────────────────────────────────────────────────────────── │
│ 이 PoC: TCP 연결 + 25바이트만 → 실제 RPC 없음 → 익스플로잇 없음 │
└──────────────────────────────────────────────────────────────────────────┘
$ cat ./design_decisions.mdfake_rpc_payload = b"\x05\x00\x0b\x03RpcAddPrinterDriverEx"
이 페이로드는 25바이트이며 두 가지 개념을 동시에 보여줍니다:
바이트 0-3: 합법적인 DCE/RPC 헤더
바이트 4-24: ASCII 함수 이름
RpcAddPrinterDriverEx — 취약한 함수의 이름(평문).
이 페이로드가 실제 익스플로잇으로 작동하지 않는 이유는?
합법적인 RPC BIND는 4바이트 헤더 뒤에 다음이 필요합니다:
- max_xmit_frag (2바이트)
- max_recv_frag (2바이트)
- assoc_group_id (4바이트)
- num_ctx_items (1바이트)
- context_elem[] → MS-RPRN 인터페이스 UUID:
{12345678-1234-ABCD-EF00-0123456789AB}
- transfer_syntaxes → NDR UUID
이 구조가 없으면 Windows는 패킷을 즉시 거부합니다. 페이로드는 사실상 연결성 확인에 불과합니다 — "이 가상 페이로드로 445 포트에 도달할 수 있는가?"
sock.connect((target_ip, 445))
135(RPC Endpoint Mapper)가 아닌 445를 사용하는 이유는?
PrintNightmare는 직접 RPC가 아닌 SMB named pipe \pipe\spoolss를 전송으로 사용합니다. 실제 흐름은 다음과 같습니다:
1. TCP 연결 → 포트 445 (SMB)
2. SMB 협상 + 세션 설정(NTLM/Kerberos 인증)
3. 트리 연결 → IPC$
4. named pipe 열기 → \pipe\spoolss
5. DCE/RPC BIND → MS-RPRN 인터페이스
6. NDR 마샬링을 통한 RpcAddPrinterDriverEx() 호출
PoC는 1단계(초기 TCP 연결)만 시뮬레이션하며 2-6단계는 구현하지 않습니다.
sock.settimeout(5): 5초 타임아웃은 응답하지 않는 호스트에서 PoC가 멈추는 것을 방지합니다. 포트 가용성의 빠른 스캔에 유용합니다.
두 경우의 근본 원인은 동일합니다: RpcAddPrinterDriverEx() 함수는 드라이버 파일의 출처 검증에 실패하고, 드라이버 설치에 대한 적절한 권한 제한을 적용하지 않으며, 로드되는 DLL의 인증성이나 무결성을 확인하지 않습니다.
$ cat ./mitre_mapping.ymltactic: Initial Access / Lateral Movement
- T1210 # 원격 서비스 악용
# 원격 호스트로 \pipe\spoolss를 통한 RPC 호출
# 유효한 도메인 자격 증명 필요
tactic: Privilege Escalation
- T1068 # 권한 상승 악용
# 일반 사용자 → Print Spooler를 통한 SYSTEM
# CVE-2021-1675 (LPE): 로컬 프로세스가 SYSTEM으로 상승
tactic: Execution
- T1569.002 # 시스템 서비스: 서비스 실행
# spoolsv.exe가 SYSTEM으로 악성 DLL 로드
# Windows 서비스를 통한 코드 실행과 동일
- T1055 # 프로세스 인젝션
# spoolsv.exe(SYSTEM) 프로세스 컨텍스트에 DLL 주입
tactic: Persistence
- T1547.012 # 부팅 또는 로그온 자동 시작: 인쇄 프로세서
# 등록된 드라이버가 재부팅 후에도 지속
# 저장 위치: HKLM\SYSTEM\CurrentControlSet\Control\Print\
tactic: Defense Evasion
- T1036.005 # 위장: 합법적인 이름 또는 위치 일치
# 합법적인 드라이버로 이름이 지정된 악성 DLL(예: Canon_XP.dll)
$ cat ./detection_opportunities.md# 이벤트 ID 808 — Print Spooler가 의심스러운 DLL 로드 실패
# 출처: Microsoft-Windows-PrintService/Admin
조건:
EventID: 808
Log: Microsoft-Windows-PrintService/Admin
Level: Error
Description CONTAINS: "failed to load a plug-in module"
실제 증거(야생에서 관찰됨):
"The print spooler failed to load a plug-in module
C:\Windows\system32\spool\DRIVERS\x64\3\svch0st.dll"
# svchost.dll의 오타 스쿼팅 → 악성 DLL
# 이벤트 ID 316 — RpcAddPrinterDriverEx를 통한 드라이버 설치
# 출처: Microsoft-Windows-PrintService/Admin
조건:
EventID: 316
Log: Microsoft-Windows-PrintService/Admin
Message CONTAINS: "RpcAddPrinterDriverEx"
OR
Message CONTAINS: "\\\\*\\*" # UNC 경로 → 원격 DLL
# Print Spooler의 의심스러운 자식 프로세스
EventID: 1 (프로세스 생성)
조건:
ParentImage: C:\Windows\System32\spoolsv.exe
Image: cmd.exe OR powershell.exe OR wscript.exe OR mshta.exe
심각도: 치명적 — spoolsv는 셸을 생성해서는 안 됨
# 비표준 경로에서 로드된 DLL
EventID: 7 (이미지 로드)
조건:
Image: C:\Windows\System32\spoolsv.exe
ImageLoaded NOT STARTS WITH:
- C:\Windows\System32\spool\DRIVERS\
- C:\Windows\System32\
- C:\Windows\SysWOW64\
심각도: 높음
네트워크 수준 탐지를 위해 SMB named pipe를 모니터링하세요: \pipe\spoolss의 존재와 RpcEnumPrinterDrivers 또는 RpcAddPrinterDriverEx 작업의 조합은 PrintNightmare 악용의 직접적인 지표입니다.
# 개념적 Zeek / Suricata 규칙:
alert smb any any -> $SERVERS 445 (
msg:"PrintNightmare RpcAddPrinterDriverEx via SMB";
content:"|5c 70 69 70 65 5c 73 70 6f 6f 6c 73 73|"; # \pipe\spoolss
content:"RpcAddPrinterDriverEx";
sid:2021001675;
)
$ cat ./remediation.md옵션 1 — Print Spooler 비활성화(인쇄가 필요하지 않은 경우)
PowerShell:
Stop-Service -Name Spooler -Force
Set-Service -Name Spooler -StartupType Disabled
옵션 2 — 그룹 정책으로 원격 인쇄 차단
컴퓨터 구성 → 관리 템플릿 → 프린터
→ "인쇄 스풀러가 클라이언트 연결을 수락하도록 허용": 사용 안 함
이렇게 하면 원격 벡터만 비활성화되고 로컬 인쇄는 유지됩니다
옵션 3 — 패치 적용(위 옵션과 관계없이 필수)
KB5004945 → 2021년 7월 대역외 패치
+ 이후 누적 패치
패치 후 검증 — 레지스트리가 여전히 취약하게 만들 수 있음:
REG QUERY "HKLM\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint"
NoWarningNoElevationOnInstall=1 또는 UpdatePromptSettings=0이면 → 여전히 취약
수정: 두 값을 0으로 설정하거나 키 제거
특별 우선순위: 도메인 컨트롤러
DC는 기본적으로 Print Spooler를 실행
PrintNightmare로 DC를 손상시키면 = AD 도메인 전체 손상
$ cat ./usage.sh# 종속성 설치(socket은 표준 라이브러리)
python --version # Python 3.x, pip 불필요
# 스크립트에서 대상 IP 편집(승인된 랩에서만)
# simulate_printnightmare_attack("192.168.1.xxx")
python poc_cve_2021_1675.py
# 445 포트에 접근 가능한 경우 예상 출력:
[+] Payload enviado para 192.168.1.117
# 포트가 닫혀 있거나 필터링된 경우 예상 출력:
[-] Erro ao conectar: [Errno 111] Connection refused
# 또는
[-] Erro ao conectar: timed out
이 출력이 의미하는 바: 445 포트에 접근 가능하다는 것뿐입니다. 취약점을 확인하지는 않습니다 — 이를 위해서는 실제 RPC BIND와 패치 버전 확인이 필요합니다.
$ cat ./poc_vs_real_exploit.md시뮬레이션된 PoC와 실제 익스플로잇의 명시적 비교.
$ cat ./lessons_learned.txt[+] DC에서 기본적으로 활성화된 Print Spooler가 가장 중요한 시나리오 — DC의 SYSTEM = 게임 오버
[+] RPC 전송으로서의 SMB named pipe는 경계 중심 방어에서 과소평가된 벡터
[+] DCE/RPC는 복잡한 프로토콜 — 바인드/호출 구조를 이해하면 시그니처 생성에 도움
[+] CVE 공개 ≠ 패치 적용 — 패치 후에도 수 주 동안 대부분의 환경은 여전히 취약
[+] PointAndPrint 레지스트리 키는 패치 후에도 취약점을 재도입할 수 있음 — 패치 후 제어가 중요
[-] 이 PoC는 TCP 연결성만 확인 — 시스템이 실제로 패치되었는지 검증하지 않음
[-] SMB 없는 순수 소켓은 인증을 협상할 수 없음 — 접근 방식의 근본적 한계
[-] settimeout(5)는 느린 네트워크에서 오탐을 유발할 수 있음 — 매개변수화된 타임아웃 고려
[→] 개선 사항: 실제 RPC에 impacket 사용, OS 버전 지문을 위한 SMB 배너 확인,
원격 레지스트리 쿼리로 적용된 KB 테스트
CVE Research · PrintNightmare · Patched July 2021 · CISA KEV · Simulated payload only
| 바이트 | 값 | 의미 |
|---|
\x05 | 5 | DCE/RPC 프로토콜 버전(버전 5 — Windows 표준) |
\x00 | 0 | 부 버전 0 |
\x0b | 11 | PDU 유형: BIND — RPC 협상의 첫 단계 |
\x03 | 3 | 플래그: `PFC_FIRST_FRAG(0x01) |
| 측면 | CVE-2021-1675 | CVE-2021-34527 |
|---|
| 벡터 | 로컬 (LPE) | 원격 (RCE) |
| CVSS | 7.8 | 8.8 |
| 인증 | 로컬 계정 | 인증된 도메인 계정 |
| 패치 | 2021년 6월(패치 화요일) | 2021년 7월(대역외 KB5004945) |
| 취약 함수 | RpcAddPrinterDriverEx | RpcAddPrinterDriverEx |
| 시나리오 | 로컬 권한 상승 | SMB named pipe를 통한 원격 RCE |
| 구성 요소 | 이 PoC | 실제 익스플로잇 |
|---|
| 연결 | 445 포트 TCP 소켓 | SMB 세션 + IPC$ 트리 연결 |
| 인증 | 없음 | NTLM 또는 Kerberos(도메인 계정) |
| Named pipe | 구현되지 않음 | \pipe\spoolss |
| RPC BIND | 가짜(4바이트 + ASCII) | MS-RPRN UUID가 있는 DCE/RPC BIND |
| 호출된 함수 | 호출되지 않음 | NDR을 통한 RpcAddPrinterDriverEx() |
| DLL 경로 | 전송되지 않음 | UNC: \\attacker\share\evil.dll |
| 결과 | 콘솔 출력 | SYSTEM 권한 RCE / LPE |
| 탐지 | 거의 없음 | EventID 808, 316, Sysmon 1/7 |