
CakePHP 5.4.2 - Élevé - À distance - Cookie - Le cookie jar du client HTTP fait correspondre les domaines comme un suffixe d'expression régulière
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cookie-suffix
Write-up : https://abraxaslabs.tech/research/cakephp-cookie-suffix
Classe : Fuite / implantation de cookie Portée : Distant
CakePHP 5.4.2 (887b641) - Cake Software Foundation
CookieCollection::findMatchingCookies utilise preg_match('/' . preg_quote($domain) . '$/', $host). Il s'agit d'un suffixe de chaîne, et non d'une correspondance de domaine RFC 6265. Un cookie pour api.partner.com est envoyé à evilapi.partner.com. Un cookie pour bank.com est envoyé à notbank.com.
Cookie::createFromHeaderString() copie également le Domain= de Set-Cookie sans aucune vérification par rapport à l'hôte de la réponse. addFromResponse depuis attacker.test avec Domain=victim.internal stocke ce cookie et l'attache ensuite à victim.internal.
Une application qui utilise Cake\Http\Client avec le jar par défaut sur plusieurs hôtes peut divulguer un cookie de session partenaire à un hôte frère confondu par suffixe, ou implanter un cookie sur un hôte interne après avoir récupéré une URL d'attaquant. other.com ne correspond pas. Ce n'est pas un bug de cookie de navigateur. Le cakephp/app standard n'appelle pas un second hôte de lui-même.
| ID | pas encore de CVE |
| Classe | Fuite / implantation de cookie (correspondance de domaine par suffixe regex) |
| Portée | Distante (l'application utilise le jar du Http Client sur plusieurs hôtes) |
| CWE | CWE-565, CWE-201 |
| CVSS | Élevé : 8.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N |
| Produit | CakePHP |
| Affecté | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | l'application utilise Cake\Http\Client avec le jar de cookies par défaut sur plusieurs hôtes |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Nécessite une application qui conserve les cookies de Cake\Http\Client sur plusieurs hôtes (OAuth, webhooks, une URL fournie par l'utilisateur, une seconde API).
| Privilège | Méthode / sink | Prouvé en lab ou déduit |
|---|---|---|
| Divulguer un cookie stocké à un hôte frère confondu par suffixe | CookieCollection::addToRequest pour https://evilapi.partner.com/ après un cookie de domaine api.partner.com | Prouvé en lab. Le Cookie de la requête est sid=SECRET. RFC 6265 ne correspondrait pas |
| Même fuite pour un suffixe enregistrable | Domaine du cookie bank.com, hôte de la requête notbank.com | Prouvé en lab. Le Cookie de la requête est sid=SECRET |
| Contrôle négatif | Hôte de la requête other.com | Prouvé en lab. Aucun en-tête Cookie |
| Implanter un cookie pour un hôte interne | addFromResponse de Set-Cookie: sid=x; Domain=victim.internal depuis https://attacker.test/ | Prouvé en lab. Le domaine stocké est victim.internal ; la requête suivante vers cet hôte envoie sid=x |
| Fixation de session / session partenaire volée lors du prochain appel Client | sid implanté ou divulgué utilisé comme session API | Déduit. Le lab s'arrête à l'oracle de l'en-tête Cookie |
| L'envoi vers le même hôte fonctionne toujours | Domaine du cookie api.partner.com vers l'hôte api.partner.com | Prouvé en lab. Attendu, pas un bug |
Fermé sur ce point restant : other.com ne correspond pas. Les jars de cookies des navigateurs ne sont pas concernés par ce bug. Pas de shell. Pas de RCE non authentifiée sur une application squelette.
J'ai épinglé cakephp/cakephp 5.4.2 après GHSA-2qh5, GHSA-fxf7, GHSA-vjqc, et la note filename= de la 5.4.2. La correspondance des cookies du Http Client est un suffixe regex :
$pattern = '/' . preg_quote($domain, '/') . '$/';
if (!preg_match($pattern, $host)) {
continue;
}
addFromResponse ne transmet l'hôte de la requête qu'à titre de valeur par défaut. Un attribut Domain= provenant de Set-Cookie l'écrase et est stocké.
Fausses pistes déjà consignées : traiter cela comme un bug de cookie de navigateur ; affirmer que other.com correspond aussi ; gonfler un oracle d'en-tête Cookie en ATO sans une application qui utilise le pot de cookies entre hôtes. Théâtre : un reverse shell.
python3 cakephp-cookie-suffix-Abraxas-Labs.py
ou
cd lab
./run.sh
Git clone tag 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) en PHP 8.3. Oracle HTTP loopback sur 127.0.0.1:19420. Aucune origine HTTP supplémentaire n'est requise ; l'oracle exécute CookieCollection depuis le pin.
sid=SECRET au domaine api.partner.com. addToRequest https://evilapi.partner.com/ -> Cookie: sid=SECRET.https://other.com/ -> aucun en-tête Cookie.https://api.partner.com/ envoie toujours sid=SECRET.bank.com -> https://notbank.com/ envoie sid=SECRET.addFromResponse depuis https://attacker.test/ avec Set-Cookie: sid=x; Domain=victim.internal; Path=/. Ensuite https://victim.internal/ envoie sid=x.SUCCESS cakephp-cookie-suffix suffix-leak=yes control-other=yes plant-domain=yes how=cakephp-5.4.2 CAKEPHP-COOKIE-SUFFIX-WITNESS
Correspondance de domaine selon la RFC 6265 (host === domain || str_ends_with($host, '.' . $domain)). Cookies limités à l'hôte lorsque Domain est omis. Rejeter un Domain qui ne correspond pas au domaine de l'hôte de la requête. Rejeter les suffixes publics.
887b641de9f7aba06071f98f17edcbc573cbcf63)src/Http/Cookie/CookieCollection.php · src/Http/Cookie/Cookie.phpGNU Affero GPL v3.0. Voir LICENSE. Laboratoire en boucle locale uniquement. Aucune garantie.