phpMyAdmin 5.2.3 - Élevé - À distance - 2FA - config/set efface l'authentification à deux facteurs
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-config-set-2fa
Write-up : https://abraxaslabs.tech/research/phpmyadmin-config-set-2fa
Classe : Résidu de privilège / étape d'authentification manquante Portée : Distante
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
POST index.php?route=/config/set écrit n'importe quelle préférence autorisée, y compris 2fa. UserPreferences::persistOption n'effectue aucune validation. Paramètres -> Authentification à deux facteurs appelle toujours TwoFactor::check(true) avant d'accepter de supprimer le facteur. /config/set ne le fait pas.
Une session authentifiée, ou un XSS/CSRF capable de POSTer le jeton de page, peut envoyer key=2fa et value=null. La connexion par mot de passe suivante n'a ni invite TOTP, WebAuthn, ni Simple. Suppression durable, pas un contournement d'une seule requête.
| ID | pas encore de CVE |
| Classe | Résidu de privilège / étape d'authentification manquante |
| Portée | Distante (connexion par cookie authentifiée ; jeton CSRF requis) |
| CWE | CWE-620 |
| CVSS | Élevé : 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produit | phpMyAdmin |
| Affecté | 5.2.3 tag RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Auth | connexion par cookie. Jeton CSRF requis. Permet d'aboutir d'un XSS ou CSRF à une suppression durable de la 2FA |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Supprimer la 2FA d'un compte phpMyAdmin sans présenter de TOTP, de WebAuthn, ni le champ de confirmation Simple. La connexion par mot de passe suivante ne demande que le mot de passe. Contrôle total de PMA en tant que cet utilisateur MySQL (SQL, utilisateurs, export).
| Privilège | Méthode / chemin | Reconnaissance / intégrité / disponibilité | Prouvé en lab ou déduit |
|---|---|---|---|
Persister 2fa à null et supprimer le second facteur de pmadb | POST index.php?route=/config/set authentifié key=2fa value=null plus un token valide | Intégrité du stockage des préférences | Prouvé en lab. success:true, config_data de pmadb est devenu [] |
| Se connecter uniquement avec le mot de passe après cette écriture | Nouvelle session par cookie, même utilisateur MySQL | Intégrité du chemin de connexion | Prouvé en lab. Pas de 2fa_confirm, arrivée dans l'interface normale |
| Conserver la session courante tandis que la 2FA disparaît pour les connexions ultérieures | Même handler ; persistOption écrit dans le stockage, pas dans le flag two_factor_check actif | Intégrité des sessions ultérieures | Prouvé en lab. La session A est restée connectée. La session B avait vu la 2FA. La session C ne l'a pas vue |
| Chaîner depuis un XSS stocké ou un CSRF capable de POSTer avec le jeton de page | Résidus de même revue, pas ce lab | Intégrité de la 2FA après un POST same-origin | Déduit |
| Supprimer la 2FA via Paramètres | POST /preferences/two-factor 2fa_remove=1 | Intégrité de la 2FA via l'interface documentée | Prouvé en lab comme fermé. Sans le facteur, PMA affiche la page de confirmation et pmadb contient toujours backend=simple |
Fermé sur ce résidu : accès non authentifié, contournement du mot de passe MySQL, RCE OS, lecture des lignes pmadb d'autres utilisateurs. Je n'ai pas eu besoin du résidu #1 (signature CustomServer). Je n'ai pas contourné le mot de passe MySQL.
Même version épinglée : Résidu WebAuthn CustomServer.
J'ai épinglé la version 5.2.3 après PMASA-2025-1/2/3. Authentification par cookie, pmadb pma__userconfig. Le lab active $cfg['DBG']['simple2fa'] uniquement pour que Settings puisse enrôler le backend Simple sans clé matérielle. TOTP et WebAuthn résident dans la même clé de préférence 2fa.
SetConfigController prend key et la value JSON et appelle Config::setUserValue. UserPreferences::persistOption est documenté « No validation is done! » apply() autorise 2fa dans sa liste blanche afin que la clé ne soit pas écartée comme préférence inconnue.
$result = $this->config->setUserValue(null, $key, json_decode($value));
json_decode('null') est le null PHP. persistOption('2fa', null, $default) désactive ensuite config_data['2fa'] car la valeur par défaut de ce chemin est également null.
Settings -> Two-factor est le contraste. TwoFactorController ne fera pas configure('') tant que TwoFactor::check(true) ne renvoie pas true.
Fausses pistes déjà consignées : traiter le 2fa_remove de Settings comme la faille (il exige toujours le facteur) ; affirmer un accès non authentifié ; affirmer un contournement du mot de passe MySQL ; traiter cela comme le reliquat #1 (CustomServer) ; un reverse shell. Du théâtre.
python3 phpmyadmin-config-set-2fa-Abraxas-Labs.py
# or: cd lab && ./run.sh
Ciblez uniquement http://127.0.0.1:19280. Composez le projet phpmyadmin-config-set-2fa. Épinglez RELEASE_5_2_3. run.sh copie ou clone ce tag dans lab/src/ pour l'image. La stack est démontée après l'exécution.
Les paramètres ont enrôlé Simple 2FA. Un second navigateur a atteint la page 2fa_confirm. Un POST 2fa_remove sans le facteur est resté sur l'interface de confirmation et a laissé backend=simple dans pmadb. Un POST /config/set a ensuite renvoyé success:true, pmadb est devenu [], et la connexion suivante a abouti à l'interface normale.
SUCCESS phpmyadmin-config-set-2fa enroll=simple ui-remove-blocked=yes config-set-cleared=yes next-login-password-only=yes PMA-CONFIG-SET-2FA-WITNESS
Refuser 2fa (et les autres clés d'authentification) sur /config/set. Exiger TwoFactor::check(true) avant toute mutation de la 2FA. Conserver le chemin Settings comme seul point d'écriture.
962857e4f63d42e38f11ff4d63f5e722018add76)libraries/classes/Controllers/Config/SetConfigController.phplibraries/classes/Config/UserPreferences.phpGNU Affero GPL v3.0. Voir LICENSE. Environnement de laboratoire en boucle locale uniquement. Aucune garantie.