Back Sploitus Exploit for Improper Authentication in Openprinting Cups
Local privilege escalation against a root `cupsd`. When coerced into acting as an IPP
**client** toward a rogue local server, cupsd answers a `401 WWW-Authenticate: Local`
challenge by replaying its own admin token. Capturing that token lets an unprivileged user
drive cupsd as admin (root). A persistent `file://` print queue (`printer-is-temporary=false`)
bypasses the FileDevice policy, so a raw `Print-Job` writes attacker bytes to any path as
Two primitives chain into arbitrary root file-write:
1. **Reusable `Local` auth.** cupsd accepts a `Local` authentication backed by a root
certificate under `/run/cups/certs/`. Acting as an IPP client, it *volunteers* that admin
token when challenged with `401 WWW-Authenticate: Local`. Point cupsd at a fake IPP server
you control and you capture a token valid to drive it as root.
2. **FileDevice bypass.** `file://` as a `device-uri` is refused by default. Creating the queue
with `printer-is-temporary=false` persists it and side-steps that guard; a raw `Print-Job`
then writes its bytes straight into the target file, as root.
cupsd (root) rogue server 127.0.0.1:9189
CUPS-Create-Local-Printer |
device-uri=ipp://127.0.0.1:9189/ipp/print |
|----------------------------------->| capture
`` is cupsd's own admin token — replay it against `/admin/` and you are root-equivalent.
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/-pwn
printer-is-temporary=false (FileDevice bypass) + accept + resume
Print-Job (application/vnd.cups-raw, gzip) = " ALL=(ALL) NOPASSWD: ALL"
4. Verify sudo -n id -> root
(fallback: a root cron job dropped to /etc/cron.d/-pwn copies /etc/shadow
to /tmp/shadow- mode 644; wait ≤90s for cron)
The reference PoC (GHSA-c54j-2vqw-wpwp / *cups2root*, R. de Jager) is a **demo harness**: it
runs as root, spawns its own cupsd and a throwaway `unpriv` user, then `sudo -u unpriv` to
simulate the attacker. Unusable as-is. Changes:
1. **De-harnessed** — no root/spawn scaffolding; targets the **system cupsd already root** on
2. **Real target** — attacker = current user (or `$ATTACKER`); fragment ` ALL=(ALL) NOPASSWD: ALL`.
3. **Raw IPP over sockets** — full rewrite with no `ipptool` / `lpadmin` / `lpinfo` / `cupsctl`
| Status | Versions |
|------------|-----------------------------------------------------|
| Vulnerable | CUPS ≤ 2.4.16 |
| Fixed | CUPS 2.4.17 and later |
| File | Role |
|--------------|---------------------------------------------------------------|
| `exploit.py` | PoC: token leak → file:// queue → raw Print-Job → sudoers root |
| `README.md` | This file |
Python 3 standard library only — no dependencies.
# attacker = current user, cupsd on 127.0.0.1:631
# override the target user (e.g. after landing as anotheruser)
IPP_HOST=127.0.0.1 IPP_PORT=631 CAPTURE_PORT=9189 python3 exploit.py
2. Do not run `cupsd` as root where avoidable; drop privileges / sandbox the service.
3. Restrict the `Local` auth and `file://` device backend; keep FileDevice policy enforced for
4. If printing is not needed: `systemctl disable --now cups cups-browsed` and remove the
* GHSA-c54j-2vqw-wpwp — *cups2root* (R. de Jager, v12-security)
* OpenPrinting CUPS 2.4.17 release notes
This project is for authorized security testing, education, and defensive research only. You are responsible for complying with applicable laws and the rules of engagement of your lab or client.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
