// 01
Resumen
Soccer es una máquina de dificultad fácil de la plataforma HackTheBox, que combina mala configuración de credenciales, un RCE conocido en una aplicación de gestión de archivos, e inyección SQL ciega sobre un canal poco habitual: WebSockets.
El punto de entrada es Tiny File Manager v2.4.3, expuesto bajo /tiny/, accesible con las credenciales por defecto del proyecto. Esta versión es vulnerable a CVE-2021-45010, que permite subir archivos arbitrarios — en este caso, una webshell en PHP que entrega una reverse shell como www-data.
Revisando la configuración de Nginx se descubre un vhost interno
(soc-player.soccer.htb) que expone un sitio de venta de
tickets. Su funcionalidad de verificación de tickets usa un WebSocket
vulnerable a blind SQL injection, explotada con un script en
Python para extraer credenciales de la base de datos soccer_db.
Esas credenciales se reutilizan para autenticarse como el usuario del sistema
player.
La escalada de privilegios aprovecha una regla mal configurada en
doas (alternativa a sudo)
que permite ejecutar dstat sin contraseña. Como
dstat puede cargar plugins de Python arbitrarios,
se crea uno malicioso que otorga el bit SUID a /bin/bash,
obteniendo una shell como root.
| Fase | Técnica / Herramienta | Resultado |
|---|---|---|
| Escaneo | nmap -p- -sSCV --min-rate=5000 -oX | Puertos 22 (SSH) y 80 (HTTP) abiertos |
| Reporte | xsltproc soccer.xml | Reporte HTML visual del scan Nmap |
| Enum. Web | feroxbuster --url http://soccer.htb | Ruta /tiny/ — Tiny File Manager 2.4.3 |
| Acceso inicial | Credenciales por defecto admin/admin@123 | Acceso al explorador de archivos |
| RCE | CVE-2021-45010 — upload de webshell PHP | Reverse shell como www-data |
| Post-explot. | /etc/nginx/sites-available/soc-player.htb | vhost soc-player.soccer.htb descubierto |
| Enum. Web 2 | feroxbuster soc-player.soccer.htb | Rutas /login, /signup, /check |
| Inyección | Blind SQLi vía WebSocket (puerto 9091) | Dump de soccer_db.accounts |
| Movimiento lateral | Password reuse — su player | Shell como player + user.txt |
| Enum. Privesc | find / -perm -4000 / doas.conf | doas permite dstat sin password |
| Privesc | Plugin malicioso dstat_evil.py (GTFOBins) | chmod +s /bin/bash |
| Root | /bin/bash -p | Shell como root + root.txt |
// 02
Reconocimiento
Se lanza un escaneo agresivo sobre todos los puertos, con detección de servicios y versión (-sSCV), sin resolución DNS (-n), sin ping previo (-Pn) y con una tasa mínima de paquetes alta para acelerar el escaneo.
El header http-title revela que el servidor
redirige a soccer.htb. Se convierte el XML a HTML para una
lectura más cómoda y se agrega el dominio al /etc/hosts local.
// 03
Tiny File Manager
Se fuzzea el sitio principal con Feroxbuster para descubrir rutas no enlazadas:
/tiny/ expone el login de
Tiny File Manager. Revisando el código fuente de la página
(view-source:) se identifica la versión exacta del software.
Tiny File Manager documenta públicamente sus credenciales por defecto en su propio sitio (tinyfilemanager.github.io). Muchas instalaciones nunca las cambian.
// ACCESO CONFIRMADO
Con estas credenciales se obtiene acceso completo al explorador de archivos en tinyfilemanager.php?p=, incluyendo subida de archivos.
// 04
Foothold — CVE-2021-45010
// CVE-2021-45010
Tiny File Manager <= 2.4.3 permite a un usuario autenticado subir archivos sin restricción de extensión, incluyendo .php, lo que resulta en ejecución remota de código sobre el servidor.
Se navega a la carpeta de uploads dentro del explorador y se sube este archivo como revershell.php. Al ejecutarse en el servidor, abre una conexión inversa hacia la IP y puerto del atacante:
Se sube el archivo como revershell.php y se deja un listener en Kali antes de invocar el archivo desde el navegador:
// FOOTHOLD CONFIRMADO
Al visitar /tiny/uploads/revershell.php desde el navegador, el archivo se ejecuta en el servidor y se recibe la conexión como www-data.
// 05
Pivote — Descubrimiento del vhost
Dentro del sistema, se buscan archivos de configuración de Nginx que puedan revelar otros sitios alojados internamente:
Se agrega el nuevo subdominio al /etc/hosts local y se fuzzea con parámetros ajustados para evitar falsos positivos por redirecciones 302:
// HTB FOOTBALL CLUB
El sitio expone un sistema de venta de tickets para partidos. Tras registrarse en /signup, se obtiene acceso a /check, donde se valida el número de ticket.
// 06
Blind SQL Injection vía WebSockets
El código fuente de /check revela que la
validación del ticket no se hace por HTTP normal, sino mediante un
WebSocket abierto en el puerto 9091:
El parámetro id enviado por el socket es
vulnerable a inyección SQL ciega. El oráculo es el mensaje de
error "Ticket Doesn't Exist": si está presente, el carácter probado es incorrecto.
El código fuente de /check revela que la
validación del ticket no se hace por HTTP normal, sino mediante un
WebSocket abierto en el puerto 9091:
El parámetro id enviado por el socket es
vulnerable a inyección SQL ciega. El oráculo es el mensaje de
error "Ticket Doesn't Exist": si está presente, el carácter probado es incorrecto.
El script anterior conecta al WebSocket y fuerza bruta cada posición de la consulta
group_concat(schema_name) sobre
information_schema.schemata para listar todas las bases de datos disponibles.
Se sustituye la consulta para apuntar a information_schema.tables, filtrando por el esquema soccer_db encontrado en el paso anterior, y se obtiene el nombre de la única tabla relevante:
Con la tabla accounts identificada, se consulta information_schema.columns para listar sus columnas:
Se amplía el set de caracteres permitidos para cubrir letras, dígitos y símbolos comunes en contraseñas, y se concatenan usuario y contraseña en una sola consulta sobre soccer_db.accounts. La palabra clave binary fuerza una comparación sensible a mayúsculas/minúsculas, necesaria porque MySQL compara cadenas sin distinguir mayúsculas por defecto:
// 07
Acceso como player
Las credenciales extraídas de la base de datos web también son válidas para el usuario player del sistema operativo — un caso clásico de password reuse.
Para tener una shell totalmente interactiva (autocompletado, Ctrl+C funcional, editores), se realiza el upgrade clásico de TTY:
// SECUENCIA COMPLETA
1. En la shell remota: ejecutar el comando anterior, luego Ctrl+Z
2. En Kali: stty raw -echo; fg y pulsar Enter dos veces
3. En la shell remota: export TERM=xterm,
export SHELL=/bin/bash,
stty rows 50 columns 100,
PS1='\u@\h:\w$ '
// 08
Escalada de privilegios
doas es una alternativa ligera a
sudo originaria de OpenBSD. Se busca su archivo
de configuración:
// REGLA PELIGROSA
El usuario player puede ejecutar dstat como root sin contraseña (nopass). dstat por sí solo no es peligroso — el problema es su soporte de plugins externos.
Según GTFOBins,
dstat puede cargar plugins de Python ubicados en
rutas específicas, ejecutándolos con los mismos privilegios del proceso. Se verifica un
directorio escribible por player:
// 09
Root
Se invoca dstat a través de
doas, cargando el plugin
evil (sin el sufijo .py):
// EL PLUGIN "FALLA" — PERO YA SE EJECUTÓ
dstat falla en cargar el plugin como un módulo de estadísticas válido, pero el efecto secundario de os.system() ya ocurrió como root antes de que fallara la carga. El bit SUID quedó activo en /bin/bash.
// 10
Referencia de Comandos
- -C — códigos de estado a filtrar/ignorar
- -S — filtra por tamaño de respuesta
- -N — número de resultados nuevos antes de auto-filtrar
- nopass — permite ejecutar sin pedir contraseña
- cmd — restringe la regla a un binario específico
- plugins — buscados en ~/.dstat/, /usr/share/dstat/, /usr/local/share/dstat/
- ws.send() — envía el payload JSON
- ws.recv() — recibe la respuesta del servidor
// 11
Glosario
.php dentro del webroot, un atacante puede ejecutar código arbitrario en el servidor simplemente visitando la URL del archivo subido.server_name) enviado en la petición HTTP. Es habitual encontrar vhosts internos no listados en DNS público, descubribles solo revisando archivos de configuración del servidor.substr(...)='a', ='b', etc., carácter por carácter).sudo: permitir ejecutar comandos con privilegios elevados según reglas definidas. Su archivo de configuración (doas.conf) usa una sintaxis simple de tipo permit/deny. Reglas mal definidas — como permitir un binario con funcionalidad extensible sin restricciones — pueden convertirse en una vía directa de escalada de privilegios.chmod +s /bin/bash se ejecute como root, dejando una bash con privilegios elevados disponible para cualquier usuario.~/.dstat/, /usr/share/dstat/, /usr/local/share/dstat/). Si un usuario tiene permiso de escritura sobre alguno de esos directorios y, además, puede ejecutar dstat como root (vía doas o sudo), puede colocar un plugin con código Python arbitrario que se ejecutará con privilegios de root al ser invocado — incluso si el plugin "falla" como módulo de estadísticas.log.progress), empaquetado de bytes, y manejo de señales. En esta máquina se usó principalmente para mostrar el progreso de la extracción de datos durante el ataque de fuerza bruta de la inyección SQL ciega.