phpMyAdmin 5.2.3 - Alta - Remota - 2FA - config/set borra la autenticación de dos factores
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-config-set-2fa
Análisis: https://abraxaslabs.tech/research/phpmyadmin-config-set-2fa
Clase: Privilegio residual / falta de step-up Alcance: Remoto
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
POST index.php?route=/config/set escribe cualquier preferencia incluida en la lista de permitidas, incluida 2fa. UserPreferences::persistOption no realiza ninguna validación. Settings -> Two-factor sigue llamando a TwoFactor::check(true) antes de eliminar el factor. /config/set no lo hace.
Una sesión con sesión iniciada, o XSS/CSRF que pueda enviar por POST el token de la página, puede enviar key=2fa y value=null. El siguiente inicio de sesión con contraseña no tiene TOTP, WebAuthn ni solicitud Simple. Eliminación duradera, no un salto de una sola petición.
| ID | aún sin CVE |
| Clase | Privilegio residual / falta de step-up |
| Alcance | Remoto (inicio de sesión autenticado por cookie; se requiere token CSRF) |
| CWE | CWE-620 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Producto | phpMyAdmin |
| Afectado | 5.2.3 etiqueta RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Autenticación | inicio de sesión por cookie. Se requiere token CSRF. Completa XSS o CSRF hacia una eliminación duradera de 2FA |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1 |
Eliminar 2FA de una cuenta de phpMyAdmin sin presentar TOTP, WebAuthn ni el campo de confirmación Simple. El siguiente inicio de sesión con contraseña es solo con contraseña. PMA completo como ese usuario de MySQL (SQL, usuarios, exportación).
| Privilegio | Método / ruta | Reconocimiento / integridad / disponibilidad | Probado en laboratorio o inferido |
|---|---|---|---|
Persistir 2fa a null y eliminar el segundo factor de pmadb | POST index.php?route=/config/set autenticado key=2fa value=null más un token válido | Integridad del almacén de preferencias | Probado en laboratorio. success:true, config_data de pmadb pasó a [] |
| Iniciar sesión solo con contraseña tras esa escritura | Nueva sesión por cookie, mismo usuario de MySQL | Integridad de la ruta de inicio de sesión | Probado en laboratorio. Sin 2fa_confirm, se accedió a la interfaz normal |
| Mantener la sesión actual mientras 2FA desaparece para inicios de sesión posteriores | Mismo handler; persistOption escribe el almacén, no el flag activo two_factor_check | Integridad de sesiones posteriores | Probado en laboratorio. La sesión A permaneció dentro. La sesión B había visto 2FA. La sesión C no |
| Encadenar desde XSS almacenado o CSRF que pueda enviar por POST con el token de la página | Restos de la misma revisión, no de este laboratorio | Integridad de 2FA tras un POST del mismo origen | Inferido |
| Eliminar 2FA mediante Settings | POST /preferences/two-factor 2fa_remove=1 | Integridad de 2FA mediante la interfaz documentada | Probado en laboratorio como cerrado. Sin el factor, PMA muestra la página de confirmación y pmadb sigue teniendo backend=simple |
Cerrado en este resto: acceso no autenticado, omisión de la contraseña de MySQL, RCE del SO, lectura de filas de pmadb de otros usuarios. No necesité el resto #1 (firma CustomServer). No omití la contraseña de MySQL.
Misma versión fijada: resto de WebAuthn CustomServer.
Fijé la versión 5.2.3 después de PMASA-2025-1/2/3. Autenticación por cookie, pmadb pma__userconfig. El laboratorio activa $cfg['DBG']['simple2fa'] solo para que Settings pueda registrar el backend Simple sin una llave de hardware. TOTP y WebAuthn viven en la misma clave de preferencia 2fa.
SetConfigController toma key y el value en JSON y llama a Config::setUserValue. UserPreferences::persistOption está documentado como "¡No se realiza ninguna validación!" apply() incluye 2fa en la lista de permitidos para que la clave no sea descartada como una preferencia desconocida.
$result = $this->config->setUserValue(null, $key, json_decode($value));
json_decode('null') es null de PHP. persistOption('2fa', null, $default) entonces elimina config_data['2fa'] porque el valor predeterminado para esa ruta también es null.
Settings -> Two-factor es el contraste. TwoFactorController no hará configure('') hasta que TwoFactor::check(true) devuelva true.
Falsos caminos ya registrados: tratar Settings 2fa_remove como el agujero (sigue exigiendo el factor); afirmar acceso no autenticado; afirmar un salto de la contraseña de MySQL; tratar esto como el remanente #1 (CustomServer); una reverse shell. Teatro.
python3 phpmyadmin-config-set-2fa-Abraxas-Labs.py
# or: cd lab && ./run.sh
Apunta solo a http://127.0.0.1:19280. Compón el proyecto phpmyadmin-config-set-2fa. Fija RELEASE_5_2_3. run.sh copia o clona esa etiqueta en lab/src/ para la imagen. El stack se desmonta tras la ejecución.
La configuración registró Simple 2FA. Un segundo navegador accedió a la página 2fa_confirm. El POST a 2fa_remove sin el factor permaneció en la interfaz de confirmación y dejó backend=simple en pmadb. El POST a /config/set devolvió entonces success:true, pmadb quedó como [], y el siguiente inicio de sesión aterrizó en la interfaz normal.
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
Denegar 2fa (y otras claves de autenticación) en /config/set. Requerir TwoFactor::check(true) antes de cualquier mutación de 2FA. Mantener la ruta de Settings como el único escritor.
962857e4f63d42e38f11ff4d63f5e722018add76)libraries/classes/Controllers/Config/SetConfigController.phplibraries/classes/Config/UserPreferences.phpGNU Affero GPL v3.0. Ver LICENSE. Solo para laboratorio en loopback. Sin garantía.