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
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 de la lista de permitidos, incluida 2fa. UserPreferences::persistOption no realiza ninguna validación. Settings -> Two-factor todavía llama a TwoFactor::check(true) antes de eliminar el factor. /config/set no lo hace.
Una sesión autenticada, 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 solicitud de TOTP, WebAuthn ni Simple. Eliminación duradera, no un salto de una sola petición.
| ID | sin CVE todavía |
| 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 tag 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 el 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, pmadb config_data quedó como [] |
| Iniciar sesión solo con contraseña después de 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, aterrizó en la UI normal |
| Mantener la sesión actual mientras el 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 hacer POST con el token de la página | Restos de la misma revisión, no este laboratorio | Integridad del 2FA tras un POST del mismo origen | Inferido |
| Eliminar el 2FA a través de Settings | POST /preferences/two-factor 2fa_remove=1 | Integridad del 2FA mediante la UI documentada | Probado en laboratorio cerrado. Sin el factor, PMA muestra la página de confirmación y pmadb todavía tiene backend=simple |
Cerrado en este residual: acceso no autenticado, omitir la contraseña de MySQL, RCE del SO, leer filas de pmadb de otros usuarios. No necesité el residual #1 (firma de CustomServer). No omití la contraseña de MySQL.
Mismo pin: WebAuthn CustomServer leftover.
Fijé 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 enrolar 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 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 se descarte 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 por defecto para esa ruta también es null.
Settings -> Two-factor es el contraste. TwoFactorController no hará configure('') hasta que TwoFactor::check(true) devuelva true.
Caminos equivocados ya registrados: tratar el 2fa_remove de Settings como el agujero (todavía exige el factor); afirmar acceso no autenticado; afirmar un salto de la contraseña de MySQL; tratar esto como el residual #1 (CustomServer); una reverse shell. Teatro.
python3 phpmyadmin-config-set-2fa-Abraxas-Labs.py
# or: cd lab && ./run.sh
Objetivo solo http://127.0.0.1:19280. Proyecto de Compose phpmyadmin-config-set-2fa. Pin RELEASE_5_2_3. run.sh copia o clona ese tag en lab/src/ para la imagen. El stack se desmonta después de la ejecución.
Settings enroló Simple 2FA. Un segundo navegador llegó a la página 2fa_confirm. El POST 2fa_remove sin el factor permaneció en la UI de confirmación y dejó backend=simple en pmadb. El POST /config/set entonces devolvió success:true, pmadb quedó como [], y el siguiente inicio de sesión aterrizó en la UI 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 laboratorio en loopback. Sin garantía.