Seguridad

CVE-2026-42608: Path Traversal en Grav CMS que hackeó el leak site de Cl0p

TL;DR — Lo que vas a tener al final

  • Tiempo de setup: 30 minutos a 2 horas dependiendo de la complejidad del entorno.
  • Requisitos: Acceso root, Linux moderno, conexión a internet para descargar dependencias.
  • Resultado: Servicio funcional y estable, documentado paso a paso.
  • Troubleshooting: Logs estándar en /var/log/, comandos de verificación al final de cada sección.

Qué pasó exactamente

El 25 de septiembre de 2026, BleepingComputer confirmó que el grupo de ransomware Cl0p movió su sitio de filtraciones (data leak site) a una nueva dirección .onion después de admitir que su servidor anterior fue comprometido y desfigurado por ShinyHunters. El vector de entrada fue una vulnerabilidad zero-day sin parche en Grav CMS, no en el plugin Form como se pensó al principio.

ShinyHunters logró subir un archivo de texto pequeño al servidor y luego reemplazó el sitio completo con una página de defacement mostrando el logo del Pokémon Umbreon y un enlace a su propio data leak site. El grupo asegura haber exfiltrado código fuente, plugins de Grav, logs del servidor y las claves privadas del servicio .onion de Cl0p, y emitió una exigencia de rescate bajo amenaza de publicar todo.

Cl0p, por su parte, reconoció que su instalación de Grav no estaba totalmente actualizada, pero negó que el servidor contuviera datos operativos o financieros sensibles: «solo tenía contenido, ni datos ni actividad financiera», declaró la banda a BleepingComputer.

El fallo técnico: CVE-2026-42608

La vulnerabilidad está rastreada como CVE-2026-42608 y reside en el núcleo de Grav CMS, específicamente en la clase GravFrameworkFormFormFlash, no en el plugin Form como muchos asumieron al inicio. Grav confirmó a BleepingComputer que el reporte del atacante es exacto: «sí, es un fallo legítimo, y la descripción del atacante es precisa».

Atributo Detalle
CVE CVE-2026-42608
Componente GravFrameworkFormFormFlash (núcleo)
Parámetro vulnerable __form-flash-id en POST requests
Tipo Path traversal sin autenticación + escritura arbitraria de archivos
Severidad High (sin CVSS publicado al cierre)
Versiones afectadas Grav ≤ 1.7.49.5 (todas las 1.7.x sin parche)
Versiones parchadas 2.0.0-beta.2 (abr-2026) y 1.7.53.4 (24-sep-2026)
Advisory GHSA-hmcx-ch82-3fv2

Cómo funciona el exploit

El bug vive en FormFlash::__construct(), método getTmpDir(). La clase se usa para persistir datos de formularios a través de redirects. Construye la ruta temporal usando el session_id que llega en __form-flash-id sin sanitizar.

El código vulnerable, según el advisory de GitHub, era esencialmente:

$folder = $config['folder'] ?? ($this->sessionId ? 'tmp://forms/' . $this->sessionId : '');
$this->folder = $folder && $locator->isStream($folder)
    ? $locator->findResource($folder, true, true)
    : $folder;

Cuando el atacante envía un valor como ../../user/config/proof_dir en __form-flash-id, Grav no limpia la cadena y la pasa al localizador de streams. findResource() resuelve el prefijo tmp:// y acepta secuencias ../, dejando al visitante no autenticado escapar del directorio previsto y crear carpetas arbitrarias dentro del alcance del servidor web (típicamente user/config/, cache/, logs/, tmp/).

Una vez escrita la carpeta, Grav también escribe un index.yaml controlado por el atacante con los datos del POST. Esto significa que un atacante puede inyectar configuración de Grav en user/config/ y cambiar el comportamiento de la aplicación sin necesidad de cuenta.

Reproducción del ataque (defensa)

Los pasos para reproducir, según el reporte original, son tres y no requieren autenticación:

# 1. Identificar cualquier página con un formulario Grav
# (típicamente /contact, /comentarios, /suscripcion)
curl -I https://victima.example/contact/
# 2. Capturar el POST durante un envío de formulario legítimo
# (puedes usar Burp, mitmproxy, o construir el POST a mano con la cookie de sesión)
# 3. Reescribir __form-flash-id con una secuencia de traversal
curl -X POST https://victima.example/contact/ 
  -d '__form-flash-id=../../user/config/proof_dir' 
  -d 'name=test&message=anything'
# Verificar:
# ls -la user/config/proof_dir/
# Aparece un index.yaml con los datos que mandaste

Troubleshooting: si tu servidor corre Grav detrás de un WAF estricto, la mayoría de WAF bloquean el patrón ../ por defecto y este vector deja de ser viable. Si el exploit funciona, el indicador más fiable es encontrar directorios creados por el usuario del servidor web (www-data) en rutas que no deberían existir bajo user/config/ o cache/.

El fix: sanitizeId() con allowlist estricta

El parche —disponible primero en Grav 2.0.0-beta.2 (abril 2026) y backporteado a Grav 1.7.53.4 el 24 de septiembre de 2026 tras este incidente— añade una función sanitizeId() que solo acepta identificadores que coincidan con la expresión regular:

[A-Za-z0-9,_-]{1,64}

Cualquier valor que no cumpla el patrón colapsa a cadena vacía, lo que hace que save(), delete() y getTmpDir() sean no-op. Un POST con __form-flash-id=../../user/config/proof_dir simplemente no escribe nada en disco. El commit de fix (firmado por Andy Miller) se aplicó en los archivos:

  • system/src/Grav/Framework/Form/FormFlash.php
  • tests/unit/Grav/Common/Security/FormFlashSecurityTest.php (32 casos de prueba cubriendo el PoC original y variantes)

Grav developers dejaron un punto muy importante en su declaración: «el bug vive en Grav core, no en el plugin Form, así que la versión del plugin (7.3.0 en el ejemplo de ellos) no cambia si un sitio es vulnerable. Es la versión del core la que importa». Esto descarta la primera reacción instintiva de muchos sysadmins, que era actualizar el plugin Form pensando que eso bastaba.

Por qué importa para sysadmins Linux

El caso Cl0p deja tres lecciones aplicables a cualquier CMS, no solo Grav:

1. Los leaks sites de ransomware no son sistemas secundarios. Operan infraestructura real con dependencias reales. Un leak site tumbado no detiene al grupo, pero una vulnerabilidad en él sirve como plataforma de presión, intel y humillación pública. Defensores que clasifican sitios de filtraciones como «infraestructura secundaria» les abren la puerta a los atacantes.

2. Las versiones LTS viejas son siempre el eslabón débil. Cl0p corría Grav 1.7.43, mientras la línea 2.0 ya tenía el fix desde abril. Quienes alojan CMS en versiones LTS o stable heredadas («porque funciona») acumulan deuda de seguridad invisible. Si tu servidor tiene un CMS en una rama que recibe solo parches críticos, define una cadencia explícita de upgrade o migra a la rama actual.

3. Path traversal sigue ganando en 2026. Hace décadas que existen los ataques de traversales y siguen dando frutos. Validar entradas con allowlist (como hace ahora Grav con [A-Za-z0-9,_-]{1,64}) no es opcional. Verifica siempre que cualquier parámetro que toque el filesystem pase por una función de sanitización explícita antes de construir una ruta.

Cómo comprobar si estás afectado (en menos de 5 minutos)

Si administras un sitio Grav, estos pasos confirman si necesitas actualizar ya:

# 1. Verificar la versión de Grav core (NO el plugin Form)
cd /var/www/mi-sitio-grav
grep -i 'version:' system/defines.php | head -5
# O desde el admin web: aparece en el panel de administración
# 2. Si tu versión core es:
# - 2.x  → ya estás protegido
# - 1.7.53.4 o superior → ya estás protegido
# - 1.7.49.5 o inferior (1.7.x) → ACTUALIZA YA
# 3. Actualizar Grav core con el instalador de Grav (GPM)
bin/gpm self-update
# 4. Verificar el resultado
bin/grav --version
# Debe mostrar 1.7.53.4 (rama 1.7) o 2.0+
# 5. Auditoría adicional: buscar directorios sospechosos creados por el webserver
find user/config cache logs tmp -type d -not -group root 2>/dev/null
# Cualquier directorio con propietario www-data/apache/nginx inesperado es candidato a investigación

Troubleshooting: si bin/gpm self-update no devuelve una versión posterior, revisa que system/defines.php apunte a una rama 1.7 o develop (no master, que ya no recibe backports). Si tu instalación está muy customizada y temes romperla, al menos aplica el parche manual copiando la función sanitizeId() del commit a tu árbol y reiniciando el servicio web.

Otras contramedidas inmediatas

Además de actualizar Grav core, hay tres mitigaciones que puedes aplicar sin tocar el código del CMS:

# Bloqueo en Nginx contra secuencias de traversal en POST
location ~ .php$ {
    if ($request_body ~ "../") {
        return 403;
    }
    # ... resto de tu config
}
  • WAF estricto: Cloudflare, ModSecurity con reglas CRS 3.x o CrowdSec con la app nginx-ssl detectan patrones ../ en el cuerpo del POST por defecto.
  • Permisos del filesystem: el directorio user/config/ debe ser escribible solo por el usuario que despliega Grav, no por el usuario del servidor web (www-data, nginx). Así, aunque el exploit escriba, no podrá inyectar configuración operativa.
  • Tripwire / file integrity monitoring: configurar alertas sobre creación de directorios nuevos bajo user/config/, cache/, logs/. Un directorio creado ahí por el usuario del webserver fuera de un deploy legítimo es una IoC fiable.

El contexto: extortion gangs atacándose entre sí

Este incidente es parte de una tendencia creciente en 2026: extortion gangs (no solo ransomware) atacando a otros grupos criminaless. ShinyHunters venía haciéndolo contra Oracle PeopleSoft, Salesforce y distintos data leak sites. Que un grupo criminal hackee a otro y use la covertura mediática para presionar («te defaceamos tu leak site, robamos tus claves Tor») introduce una variable nueva para los defensores: las defensas que hagas pensando en atacantes legítimos también pueden quedar expuestas ante atacantes con motivos políticos o de mercado dentro del mismo underground.

Para Cl0p, además del golpe de imagen, perder las claves del servicio .onion significa haber perdido control sobre la infraestructura de extortion pública. Mientras migran a una nueva dirección .onion, los datos que ya filtraron a víctimas previas quedan en limbo: ¿a qué dirección les pagan ahora las víctimas? ¿Cómo verifican que el sitio nuevo es legítimo y no una trampa de ShinyHunters? Esa incertidumbre operativa es, probablemente, más costosa que el defacement mismo.

Conclusión para sysadmins

Si administras un sitio Grav, actualiza a 1.7.53.4 (o a la rama 2.0 si puedes) hoy mismo. El parche está firmado por Andy Miller y verificado por GitHub. Si administras otro CMS, audita ahora mismo cualquier parámetro que forme rutas: file, path, dir, template, id, form-flash-id. El patrón es universal, no exclusivo de Grav.

Y si corres cualquier infraestructura oculta (.onion, I2P, hosts internos), asume que también es infraestructura crítica: actualiza con la misma cadencia que tu front-end público.

Preguntas frecuentes

¿Por qué CVE-2026-42608: Path Traversal en Grav CMS que hackeó el leak site de Cl0p es relevante para sysadmins Linux?

Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.

¿Qué necesito para empezar con CVE-2026-42608: Path Traversal en Grav?

Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.

¿Cuáles son los errores más comunes con CVE-2026-42608: Path Traversal en Grav?

Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.

¿Cuándo usar CVE-2026-42608: Path Traversal en Grav y cuándo una alternativa?

Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.

¿Cómo migro desde una configuración previa a CVE-2026-42608: Path Traversal en Grav?

Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.

Lee también

Alfonso Moreno | Sysadmin Senior

Soy Alfonso, sysadmin senior con RHCE y más de 10 años administrando sistemas Linux para empresas y proyectos personales. Me especializo en infraestructura, redes, virtualización, monitoring, automation y self-hosting. Sobre SoyLinux.com SoyLinux.com es un blog técnico en español sobre Linux, software libre y self-hosting. Lo mantengo en mi tiempo libre. Áreas de expertise - Linux server administration: RHEL, CentOS, Rocky, Alma, Fedora, Debian, Ubuntu - Network services: Postfix, BIND, Samba, NFS, Squid - Virtualización y containers: KVM, Proxmox, Docker, Podman - Monitoring: Prometheus, Grafana, Zabbix - Automation: Ansible, Bash scripting - Self-hosting: Vaultwarden, Nextcloud, Jellyfin, Immich, Homelab Contacto - Email: [email protected]

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *