
phpMyAdmin 5.2.3 - Alta - Remota - residual - setup/validate aún accesible
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
Análisis: https://abraxaslabs.tech/research/phpmyadmin-setup-validate
Clase: SSRF Alcance: Remoto
phpMyAdmin 5.2.3 (etiqueta RELEASE_5_2_3, commit 962857e). setup/index.php termina cuando config.inc.php está presente. setup/validate.php no. Este último sigue cargándose bajo $isMinimumCommon, toma un token CSRF de la página de inicio de sesión pública y llama a Validator::testDBConnection -> mysqli_connect hacia el host, puerto, usuario y contraseña del campo JSON values.
Un cliente no autenticado hace GET a / para obtener una cookie de sesión y un token, y luego hace POST a setup/validate.php con id=Server y los valores Servers/1/host y Servers/1/port que elija. El host de phpMyAdmin abre un handshake TCP de MySQL hacia esa dirección. Eso es SSRF sobre el protocolo MySQL: 3306 interno, credential stuffing contra un servidor interno, un oráculo de puertos a partir de los tiempos de respuesta y los errores de mysqli. No es SSRF de metadatos HTTP a menos que algo en ese puerto hable MySQL. hide_db también interpola una regex del usuario en preg_match. No ejecuté esa ruta de ReDoS en este laboratorio.
La imagen oficial phpmyadmin:5.2.3 elimina setup/. Este remanente solo aplica cuando ese directorio sigue en la raíz web, que es el remanente habitual tras una instalación. El laboratorio restaura setup/ desde el tarball de 5.2.3 para que la versión fijada coincida con RELEASE_5_2_3.
PMASA-2016-44 / CVE-2016-6621 cubrió parte del SSRF de setup. La comprobación de "deshabilitar setup cuando existe config" nunca se aplicó a validate.php / config.php.
| ID | aún sin CVE |
| Clase | SSRF (protocolo MySQL) |
| Alcance | Remoto (no autenticado si setup/ sigue siendo accesible por web) |
| CWE | CWE-918 |
| CVSS | Alta: 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N |
| Producto | phpMyAdmin |
| Afectado | 5.2.3 etiqueta RELEASE_5_2_3 (962857e) con setup/ aún en el docroot |
| Autenticación | No autenticado. Token CSRF de la página de inicio de sesión pública. Sin inicio de sesión MySQL. |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:19230 |
Cualquiera que pueda alcanzar un árbol setup/ remanente puede hacer que el host de phpMyAdmin abra una conexión TCP con protocolo MySQL hacia un host y puerto que elija.
| Privilegio | Método / ruta | Demostrado en laboratorio o inferido |
|---|---|---|
| Abrir TCP desde el host de PMA hacia host:puerto del atacante (integridad de la conexión saliente; reconocimiento de ese puerto) | POST /setup/validate.php no autenticado con id=Server y Servers/1/host + Servers/1/port más un token de GET / | Demostrado en laboratorio. El oráculo en oracle:13306 registró PMA-SETUP-VALIDATE-WITNESS desde el contenedor de PMA |
| Confirmar que la interfaz de setup está desactivada mientras validate sigue activo | GET /setup/index.php | Demostrado en laboratorio. El cuerpo contiene "setup is disabled" / configuration already exists |
| Fallar de forma segura sin el token CSRF de la página de inicio de sesión | Mismo POST, sin token | Demostrado en laboratorio. Cero impactos en el oráculo |
| Oráculo de puertos / credenciales a partir de errores de mysqli y tiempos de respuesta | Mismo testDBConnection | Inferido. El cuerpo del laboratorio fue mysqli_connect(): (HY000/2006): MySQL server has gone away después de que el oráculo aceptara y luego cerrara |
| Hablar MySQL con un 3306 interno y probar el usuario/contraseña enviados | Mismo mysqli_connect | Inferido. No apuntado al servicio db del laboratorio |
ReDoS mediante validateRegex que interpola una regex del usuario | id=Servers/1/hide_db | Inferido. No ejercitado |
Cerrado en este laboratorio: SSRF de metadatos HTTP (el handshake es MySQL, no GET /latest/meta-data), inicio de sesión PMA sin autenticación, shell del SO y el propio asistente de configuración (index.php permanece deshabilitado). FAIL si setup/ no está desplegado (predeterminado de la imagen oficial).
Ocho búsquedas paralelas de código fuente de RELEASE_5_2_3. setup/index.php tiene el error fatal de configuración existente. setup/validate.php no lo tiene. setup/lib/common.inc.php establece $isMinimumCommon y no busca CONFIG_FILE.
Falsos caminos: tratar la imagen oficial como este remanente (elimina setup/); hacer POST sin el token de la página de inicio de sesión (cero aciertos del oráculo); tratar esto como SSRF de metadatos HTTP (el handshake es MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
o
cd lab
./run.sh
Solo loopback: http://127.0.0.1:19230. Proyecto de Compose phpmyadmin-setup-validate. El Dockerfile restaura setup/ desde el tarball 5.2.3 y ejecuta un oráculo TCP en el puerto 13306. Testigo PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
Coloca el fatal file_exists(CONFIG_FILE) en setup/lib/common.inc.php para que todos los scripts de configuración mueran. Restringe los hosts de testDBConnection. No construyas delimitadores de preg_match a partir de cadenas de usuario.
962857e)setup/index.php fatal de configuración existentesetup/validate.php sin esa comprobaciónlibraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. Consulta LICENSE. Solo para laboratorio de loopback. Sin garantía.