Tabby
Last updated
Last updated
Publicado: 21 de Mayo de 2025 Autor: José Miguel Romero aKa x3m1Sec Dificultad: ⭐ Easy
Tabby es una máquina Linux de dificultad fácil que requiere la explotación de un Local File Inclusion (LFI) para extraer credenciales de Tomcat. La escalada inicial se consigue mediante la subida de un archivo WAR malicioso aprovechando el rol manager-script. La escalada de privilegios se realiza aprovechando la pertenencia al grupo lxd. El reto implica técnicas de enumeración web, explotación de LFI, análisis de archivos de configuración, crackeo de contraseñas y conocimiento sobre contenedores LXD para lograr acceso completo al sistema.
La ruta de explotación incluye:
Descubrir un LFI en un sitio web
Obtener credenciales de un archivo de configuración de Tomcat
Desplegar un archivo WAR malicioso utilizando el API de Tomcat
Crackear la contraseña de un archivo ZIP para reutilizarla y obtener acceso de usuario
Escalar privilegios aprovechando la pertenencia al grupo lxd
💡 Nota: El TTL cercano a 64 sugiere que probablemente sea una máquina Linux.
http://10.10.10.194/
Al enumerar sobre algunas de las secciones de este sitio web encontramos que al acceder a la sección news se está aplicando vhosting:
⚠️ Importante: Detectamos durante la fase de enumeración con nmap que se está realizando virtual hosting. Debemos añadir el siguiente vhost a nuestro fichero /etc/hosts
http://megahosting.htb/news.php?file=statement
Encontramos un mensaje de aviso en el que se indica que se ha producido una brecha de seguridad y el sitio ha sido modificado para eliminar la herramienta.
Llama la atención ese parámetro file. Verificamos si es vulnerable a LFI y lo confirmamos con el siguiente payload:
http://megahosting.htb/news.php?file=..//..//..//..//etc/passwd
No encontramos nada relevante
http://supersecurehotel.htb:8080
Aquí vemos bastante información que podría combinarse con el LFI que hemos encontrado de cara a obtener un posible vector de ataque.
Accedemos al manager pero las credenciales por defecto no funcionan (había que intentarlo) http://megahosting.htb:8080/manager/html
En la página anterior leemos que el archivo tomcat-users.xml se encuentra en: /etc/tomcat9/tomcat-users.xml
.
Abusamos del LFI para leer este fichero aunque no nos devuelva nada:
http://megahosting.htb/news.php?file=..//..//..//..//etc/tomcat9/tomcat-users.xml
Después de bucear un poco en google encontramos que el archivo tomcat-users.xml puede ubicarse tanto en
Usamos el LFI con esta ubicación y leemos el archivo correctamente obteniendo una contraseña en texto claro:
Con estas credenciales, accedemos correctamente al host manager:
Tanto la aplicación web del administrador como las aplicaciones web del administrador del host tienen enlaces desde la página predeterminada de Tomcat.
NOTA: Por razones de seguridad, el uso de la aplicación web del administrador está restringido a usuarios con rol “manager-gui”. La aplicación web host-manager está restringida a usuarios con rol “admin-gui”. Los usuarios se definen en
/etc/tomcat9/tomcat-users.xml
.
El usuario tomcat tiene admin-gui
, pero no manager-gui
, lo que significa que no puedo acceder a la aplicación web del administrador:
Pero sí podemos acceder al host manager:
http://megahosting.htb:8080/host-manager/html
NO podemos hacer a priori gran cosa, revisando los roles que tiene este usuario, vemos que también tiene uno llamado manager-script:
Este es un caso algo distinto al habitual porque nuestro usuario de tomcat solo tiene el manager-script role y no tiene el habitual manager-gui role, sin embargo, podemos usr esto para usar el tomcat /manager/text scripting API. Pero antes, debemos generar una reverse shell dentro un fichero .WAR, para ello podemos usar la herramienta msfvenom:
Podemos ver la lista de comandos aquí:
https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html#Supported_Manager_Commands
Ahora podemos usar el siguiente comando para subirlo. En el path podemos definir lo que queramos:
Parece que funcionó. A continuación iniciamos un listener usando nc
y luego dispararlo con curl http://10.10.10.194:8080/test
. Recupero una conexión con un shell:
Enumeramos el directorio de usuarios y vemos el directorio de un usuario llamado ash pero no tenemos permisos:
Tampoco funciona reutilizar con este usuario la contraseña $3cureP4s5w0rd123!. Encontramos un archivo .zip en el directorio /var/www/html
Lo transferimos a nuestro host de ataque de la siguiente forma:
En nuestro host de ataque ejecutamos:
En el host comprometido ejecutamos:
Hacemos un md5sum en origen y en destino para verificar la integridad de la transferencia.
Al intentar descomprimirlo nos pide una contraseña, de primeras probamos con la que ya teníamos pero nos indica que es incorrecta:
Usamos la herramienta zip2john para extraer un hash que podemos intentar crackear mediante un ataque con diccionario:
Usamos john the ripper y el diccionario rockyou para intentar crackear el el hash:
Obtenemos la contraseña. Descomprimimos de nuevo el .zip usando la contraseña obtenida admin@it
No encontramos nada interesante al descomprimir el archivo, sin embargo, sí que descubrimos que la contraseña que hemos obtenido se está reutilizando por el usuario ash y obtenemos la primera flag:
Verificamos si hay algún usuario que pueda ejecutar algo como root:
Verificamos los grupos del usuario ash:
El grupo lxd es un grupo privilegiado.
Si intentamos ejecutar lxc, vemos que el binario no está añadido al path y nos indica que debemos usar /snap/bin/lxc
Lo añadimos al path
Para llevar a cabo la explotación y escalada de privilegios, descargamos en primer lugar la imagen de alpine en el host de ataque:
Iniciamos un servidor web con python:
En el host comprometido, descargamos el archivo:
Importamos la imagen
Nos da un error y tras buscar información sobre él comprobamos que se está ejecutando una instancia de lxc de snap (confinada) y no tiene acceso a lo que hay en el directorio /tmp
La solución es mover la imagen de alpine a una ruta donde snap tenga acceso y volver a ejecutar
Una vez hecho, si ahora listamos las imágenes:
Ahora ejecutamos lo siguiente:
NOTA: si nos da el error: Error: No storage pool found. Please create a new storage pool
Ejecutar esto para crear un pool llamado default
, usando dir
como backend:
Ahora sí, de nuevo
Ahora nos movemos al path que habíamos montado en el contenedor /mnt/root y finalmente al directorio /root y obtenemos la flag: