
Учебный proof-of-concept для PrintNightmare (CVE-2021-1675/34527) с имитацией нерабочей полезной нагрузки, анализом вектора атаки, сопоставлением с MITRE, рекомендациями по обнаружению и шагами по устранению уязвимости.
Тип: Proof of Concept — Симуляция (нерабочий) CVE: CVE-2021-1675 + CVE-2021-34527 CVSS: 7.8 (LPE) / 8.8 (RCE) Псевдоним: PrintNightmare Исправлено: Июнь/Июль 2021 — KB5004945 Добавлено в CISA KEV: Июль 2021
⚠️ Полезная нагрузка этого PoC является явно вымышленной и не-вредоносной — всего 4 байта заголовка DCE/RPC, за которыми следует имя функции в ASCII. Она не выполняет код, не устанавливает драйвер, не повышает привилегии. Использование исключительно в целях обучения и разработки детектов.
Разработано: HKK$ cat ./vulnerability_summary.txtCVE-2021-1675, известный как PrintNightmare, — это критическая уязвимость удаленного выполнения кода и локального повышения привилегий в службе Windows Print Spooler. Ошибка позволяет атакующим выполнять произвольный код с привилегиями SYSTEM, эксплуатируя функцию RpcAddPrinterDriverEx(), используемую для удаленной установки драйверов принтера без надлежащей проверки контроля доступа.
Первоначально классифицированная как LPE (CVSS 7.8) и исправленная в «вторнике исправлений» в июне 2021 года, Microsoft переклассифицировала уязвимость как RCE (CVSS 8.8) 21 июня. Чтобы избежать путаницы, вектор RCE получил новый идентификатор, CVE-2021-34527 — оба обычно называют PrintNightmare.
$ cat ./timeline.txt08 июня 2021 Microsoft публикует первоначальный патч в «вторник исправлений» — CVE-2021-1675 (LPE, CVSS 7.8)
21 июня 2021 Microsoft переклассифицирует как RCE (CVSS 8.8)
29 июня 2021 Исследователи случайно публикуют PoC — полагая, что это та же уже исправленная уязвимость
01 июля 2021 CVE-2021-34527 присвоен вектору RCE — отличному от исходного LPE
02 июля 2021 Microsoft выпускает экстренный внеплановый патч: KB5004945
Июль 2021 CISA добавляет в каталог Known Exploited Vulnerabilities
Активная эксплуатация группами программ-вымогателей (Vice Society, Magniber и т.д.)
$ cat ./architecture.txt┌──────────────────────────────────────────────────────────────────────────┐
│ PRINTNIGHTMARE — СХЕМА АТАКИ │
│ │
│ АТАКУЮЩИЙ (аутентифицированный пользователь) WINDOWS PRINT SPOOLER │
│ (spoolsv.exe) │
│ 1. Аутентифицироваться с любой ┌────────────────────┐ │
│ действительной учетной записью домена │ Работает как SYSTEM│ │
│ │ │ Активен по умолчанию│ │
│ 2. Подключиться через RPC к │ на всех Windows, │ │
│ именованному каналу \pipe\spoolss │ включая DC │ │
│ │ └──────────┬─────────┘ │
│ 3. Вызвать RpcAddPrinterDriverEx() │ │
│ с путем к вредоносной DLL ────────────────────────────►│ │
│ (UNC: \\attacker\share\evil.dll) │ │
│ ┌─────────────────▼─────────┐ │
│ │ Print Spooler загружает │ │
│ │ драйвер (DLL) как SYSTEM │ │
│ │ без проверки источника │ │
│ │ или целостности │ │
│ └─────────────────┬─────────┘ │
│ │ │
│ ◄── RCE / LPE как SYSTEM ────────────────────────────────┘ │
│ Новый пользователь admin, reverse shell, │
│ развертывание программ-вымогателей и т.д. │
│ │
│ ───────────────────────────────────────────────────────────────────── │
│ ЭТОТ PoC: только TCP connect + 25 байт → без реального RPC → без эксплойта
└──────────────────────────────────────────────────────────────────────────┘
$ cat ./design_decisions.mdfake_rpc_payload = b"\x05\x00\x0b\x03RpcAddPrinterDriverEx"
Эта полезная нагрузка имеет 25 байт и демонстрирует две концепции одновременно:
Байты 0-3: Легитимный заголовок DCE/RPC
Байты 4-24: Имя функции в ASCII
RpcAddPrinterDriverEx — имя уязвимой функции, в открытом виде.
Почему эта полезная нагрузка не работает как реальный эксплойт?
Легитимный BIND RPC потребовал бы после 4-байтового заголовка:
- max_xmit_frag (2 байта)
- max_recv_frag (2 байта)
- assoc_group_id (4 байта)
- num_ctx_items (1 байт)
- context_elem[] → UUID интерфейса MS-RPRN:
{12345678-1234-ABCD-EF00-0123456789AB}
- transfer_syntaxes → UUID NDR
Без этой структуры Windows немедленно отклоняет пакет. Полезная нагрузка, по сути, является лишь проверкой связности — «могу ли я достичь порта 445 с этой вымышленной полезной нагрузкой?».
sock.connect((target_ip, 445))
Почему 445, а не 135 (RPC Endpoint Mapper)?
PrintNightmare использует SMB именованный канал \pipe\spoolss как транспорт — не прямой RPC. Реальный поток:
1. TCP connect → порт 445 (SMB)
2. SMB negotiate + session setup (аутентификация NTLM/Kerberos)
3. Tree connect → IPC$
4. Открытие именованного канала → \pipe\spoolss
5. DCE/RPC BIND → интерфейс MS-RPRN
6. Вызов RpcAddPrinterDriverEx() с NDR marshaling
PoC имитирует только шаг 1 — начальное TCP-соединение — без реализации шагов 2-6.
sock.settimeout(5): таймаут в 5 секунд предотвращает зависание PoC на хостах, которые не отвечают. Полезно для быстрого сканирования доступности порта.
Корневая причина в обоих случаях одна и та же: функция RpcAddPrinterDriverEx() не проверяет источник файлов драйвера, не накладывает надлежащих ограничений привилегий для установки драйверов и не проверяет подлинность или целостность загружаемых DLL.
$ cat ./mitre_mapping.ymltactic: Initial Access / Lateral Movement
- T1210 # Exploitation of Remote Services
# RPC-вызов через \pipe\spoolss на удаленный хост
# Требуется действительная учетная запись домена
tactic: Privilege Escalation
- T1068 # Exploitation for Privilege Escalation
# обычный пользователь → SYSTEM через Print Spooler
# CVE-2021-1675 (LPE): локальный процесс повышается до SYSTEM
tactic: Execution
- T1569.002 # System Services: Service Execution
# Вредоносная DLL загружается spoolsv.exe как SYSTEM
# Эквивалент выполнения кода через службу Windows
- T1055 # Process Injection
# DLL внедряется в контекст процесса spoolsv.exe (SYSTEM)
tactic: Persistence
- T1547.012 # Boot or Logon Autostart: Print Processors
# Зарегистрированный драйвер сохраняется между перезагрузками
# Хранится в: HKLM\SYSTEM\CurrentControlSet\Control\Print\
tactic: Defense Evasion
- T1036.005 # Masquerading: Match Legitimate Name or Location
# Вредоносная DLL названа как легитимный драйвер (напр.: Canon_XP.dll)
$ cat ./detection_opportunities.md# Event ID 808 — Print Spooler не смог загрузить подозрительную DLL
# Источник: Microsoft-Windows-PrintService/Admin
Условие:
EventID: 808
Log: Microsoft-Windows-PrintService/Admin
Level: Error
Description СОДЕРЖИТ: "failed to load a plug-in module"
Реальное свидетельство (observed in-the-wild):
"The print spooler failed to load a plug-in module
C:\Windows\system32\spool\DRIVERS\x64\3\svch0st.dll"
# Typosquatting svchost.dll → вредоносная DLL
# Event ID 316 — Драйвер установлен через RpcAddPrinterDriverEx
# Источник: Microsoft-Windows-PrintService/Admin
Условие:
EventID: 316
Log: Microsoft-Windows-PrintService/Admin
Message СОДЕРЖИТ: "RpcAddPrinterDriverEx"
ИЛИ
Message СОДЕРЖИТ: "\\\\*\\*" # UNC-путь → удаленная DLL
# Подозрительный дочерний процесс Print Spooler
EventID: 1 (Process Creation)
Условие:
ParentImage: C:\Windows\System32\spoolsv.exe
Image: cmd.exe ИЛИ powershell.exe ИЛИ wscript.exe ИЛИ mshta.exe
Серьезность: КРИТИЧЕСКАЯ — spoolsv не должен порождать оболочки
# DLL загружена из нестандартного пути
EventID: 7 (Image Loaded)
Условие:
Image: C:\Windows\System32\spoolsv.exe
ImageLoaded НЕ НАЧИНАЕТСЯ С:
- C:\Windows\System32\spool\DRIVERS\
- C:\Windows\System32\
- C:\Windows\SysWOW64\
Серьезность: ВЫСОКАЯ
Для обнаружения на сетевом уровне отслеживайте SMB именованные каналы: наличие \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 — Заблокировать удаленную печать через Group Policy
Computer Configuration → Administrative Templates → Printers
→ "Allow Print Spooler to accept client connections": DISABLED
Это отключает только удаленный вектор, сохраняя локальную печать
ВАРИАНТ 3 — Установить патчи (обязательно независимо от вариантов выше)
KB5004945 → внеплановый патч Июль 2021
+ последующие кумулятивные обновления
ПРОВЕРКА ПОСЛЕ ПАТЧА — Реестр все еще может оставить уязвимость:
REG QUERY "HKLM\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint"
Если NoWarningNoElevationOnInstall=1 ИЛИ UpdatePromptSettings=0 → ВСЕ ЕЩЕ УЯЗВИМО
Исправление: установить оба значения в 0 или удалить ключи
ОСОБЫЙ ПРИОРИТЕТ: Контроллеры домена
DC работают с Print Spooler по умолчанию
Компрометация DC через PrintNightmare = полная компрометация домена 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 отправлен на 192.168.1.117
# Ожидаемый вывод, если порт закрыт/фильтруется:
[-] Ошибка подключения: [Errno 111] Connection refused
# или
[-] Ошибка подключения: timed out
Что означает этот вывод: только то, что порт 445 доступен. Это не подтверждает уязвимость — для этого потребовался бы реальный RPC BIND + проверка версии патча.
$ cat ./poc_vs_real_exploit.mdЯвное сравнение между симулированным PoC и реальным эксплойтом.
$ cat ./lessons_learned.txt[+] Print Spooler, активный на DC по умолчанию, — самый критический сценарий — SYSTEM на DC = game over
[+] SMB именованные каналы как транспорт RPC — недооцененный вектор в защитах, ориентированных на периметр
[+] DCE/RPC — сложный протокол — понимание структуры bind/call помогает создавать сигнатуры
[+] Опубликованный CVE ≠ примененный патч — спустя недели после патча большинство сред все еще были уязвимы
[+] Ключи реестра PointAndPrint могут вернуть уязвимость даже после патча — критический контроль после патча
[-] Этот PoC только проверяет TCP-связность — не проверяет, заплатена ли система на самом деле
[-] Чистый сокет без SMB не может согласовать аутентификацию — фундаментальное ограничение подхода
[-] settimeout(5) может давать ложные отрицательные результаты в медленных сетях — рассмотреть параметризуемый таймаут
[→] Улучшения: использовать impacket для реального RPC, проверять SMB-баннер для определения версии ОС,
проверять установленный KB через удаленный запрос реестра
CVE Research · PrintNightmare · Исправлено Июль 2021 · CISA KEV · Только симулированная полезная нагрузка
| Байт | Значение | Смысл |
|---|
\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 (вторник исправлений) | Июль 2021 (внеплановый KB5004945) |
| Уязвимая функция | RpcAddPrinterDriverEx | RpcAddPrinterDriverEx |
| Сценарий | Локальное повышение привилегий | Удаленный RCE через SMB именованный канал |
| Компонент | Этот PoC | Реальный эксплойт |
|---|
| Соединение | TCP-сокет порт 445 | SMB-сессия + Tree connect IPC$ |
| Аутентификация | Нет | NTLM или Kerberos (учетная запись домена) |
| Именованный канал | Не реализован | \pipe\spoolss |
| RPC BIND | Поддельный (4 байта + ASCII) | DCE/RPC BIND с UUID MS-RPRN |
| Вызываемая функция | Не вызывается | RpcAddPrinterDriverEx() через NDR |
| Путь к DLL | Не отправляется | UNC: \\attacker\share\evil.dll |
| Результат | Вывод в консоль | RCE как SYSTEM / LPE |
| Обнаружение | Почти нулевое | EventID 808, 316, Sysmon 1/7 |