
phpMyAdmin 5.2.3 - Élevé - À distance - CSRF - suppression de jeton sur /sql
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-csrf-sql
Classe : CSRF Portée : Distante
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). Common.php construit la requête PSR-7 à partir des globales avant checkTokenRequestParam. En cas de non-concordance, Sanitize::removeRequestVars efface $_POST et $_GET mais pas cet instantané. $sql_query est ensuite copié depuis $request->getParsedBodyParam('sql_query'). Les POST AJAX s'interrompent en cas de non-concordance de jeton. Les POST non-AJAX continuent. SqlController privilégie $_POST['sql_query'] nettoyé et conserve sinon la globale.
Une victime disposant d'un cookie de session phpMyAdmin suffit. POSTez sur index.php?route=/sql avec sql_query et sans jeton valide, et sans ajax_request. Le SELECT s'exécute en tant que cet utilisateur MySQL. Le CookieSameSite=Strict par défaut en 5.2.3 bloque de nombreux navigateurs cross-site. Same-site, Lax, None ou HTTP-auth passent toujours. C'est dans tous les cas un contrôle CSRF défaillant.
| ID | pas encore de CVE |
| Classe | CSRF |
| Portée | Distante. Le CookieSameSite=Strict par défaut bloque de nombreux navigateurs cross-site. Same-site / Lax / None / HTTP-auth subsistent. |
| CWE | CWE-352 |
| CVSS | Élevé : 8.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N |
| Produit | phpMyAdmin |
| Affecté | 5.2.3 tag RELEASE_5_2_3 (962857e) |
| Auth | Cookie de session phpMyAdmin de la victime (ou HTTP auth). Aucun jeton CSRF valide. |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:19240 uniquement |
Quiconque peut amener le navigateur de la victime à POSTer vers phpMyAdmin sans ajax_request peut exécuter du SQL en tant que cet utilisateur MySQL.
| Privilège | Méthode / chemin | Prouvé en lab ou déduit |
|---|---|---|
| Exécuter du SQL attaquant en tant que compte MySQL de la victime (intégrité + reconnaissance de cette base SQL) | POST index.php?route=/sql sql_query=... db=... sans token, sans ajax_request | Prouvé en lab. Le corps de la réponse contenait PMA-CSRF-SQL-WITNESS. Le journal général a montré le SELECT en tant que appuser |
| Interrompre le même handler en AJAX | Même POST avec ajax_request=1 | Prouvé en lab. Token mismatch. Ligne marqueur INSERT absente. Le journal général n'a pas exécuté cet INSERT |
Contourner les handlers qui ne lisent que $_POST nettoyé | POST /database/structure/drop-table sans jeton | Prouvé en lab. keepme toujours présent |
Même faille sur l'export (SaveDir), DROP/TRUNCATE de partition, verrouillage de compte, /config/set, création pmadb | Tout handler qui lit le corps PSR-7 après le nettoyage | Déduit. Non exercé |
Fermé sur ce lab : PMA non authentifié (connexion par cookie requise au préalable), routes AJAX (elles sortent en cas de non-concordance), drop-table sans jeton, shell OS. Le SameSite Strict par défaut signifie qu'un formulaire cross-site classique n'enverra souvent pas le cookie ; le reliquat reste néanmoins une vérification CSRF échouée en same-site et sur les déploiements Lax/None.
Huit recherches parallèles dans le code source de RELEASE_5_2_3. Common.php crée $request = createFromGlobals() avant checkTokenRequestParam(). En cas de non-concordance, Sanitize::removeRequestVars() efface uniquement $_POST/$_GET. Le non-AJAX continue. SqlController utilise la globale $sql_query si $_POST est vide. Route GET|POST /sql.
Fausses pistes : traiter l'AJAX /sql comme le reliquat (il s'interrompt sur Token mismatch) ; traiter drop-table comme le reliquat (ce handler ne lit que $_POST nettoyé) ; traiter le SameSite Strict par défaut comme « CSRF est fermé » (le contrôle est toujours défaillant ; same-site / Lax / None subsistent).
python3 phpmyadmin-csrf-sql-Abraxas-Labs.py
ou
cd lab
./run.sh
Loopback uniquement : http://127.0.0.1:19240. Images phpmyadmin:5.2.3 et mysql:8.0. Projet Compose phpmyadmin-csrf-sql. Le PoC est un POST loopback same-site (le SameSite Strict envoie quand même le cookie). Témoin PMA-CSRF-SQL-WITNESS.
SUCCESS phpmyadmin-csrf-sql sql-ran=yes ajax-abort=yes drop-held=yes PMA-CSRF-SQL-WITNESS
En cas de non-concordance, remplacer la requête par un corps vide, ou refuser tous les POST, pas seulement les AJAX. Ne pas copier sql_query depuis une requête obsolète. Échouer en mode fermé comme à la déconnexion.
962857e)libraries/classes/Common.php instantané de requête avant nettoyage du jetonSanitize::removeRequestVars efface uniquement $_POST/$_GETSqlController globale $sql_queryGNU Affero GPL v3.0. Voir LICENSE. Lab loopback uniquement. Aucune garantie.