
phpMyAdmin 5.2.3 - Alta - Remoto - remanescente - setup/validate ainda acessível
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
Classe: SSRF Alcance: Remoto
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). setup/index.php morre quando config.inc.php está presente. setup/validate.php não. Ele ainda carrega sob $isMinimumCommon, pega um token CSRF da página de login pública e chama Validator::testDBConnection -> mysqli_connect para o host, porta, usuário e senha no campo JSON values.
Um cliente não autenticado faz GET em / para obter um cookie de sessão e token, depois faz POST em setup/validate.php id=Server com Servers/1/host e Servers/1/port de sua escolha. O host phpMyAdmin abre um handshake TCP MySQL para esse endereço. Isso é SSRF sobre o protocolo MySQL: 3306 interno, credential stuffing contra um servidor interno, um oráculo de porta a partir de timing e erros do mysqli. Não é SSRF de metadados HTTP a menos que algo naquela porta fale MySQL. hide_db também interpola uma regex de usuário em preg_match. Não executei esse caminho de ReDoS neste lab.
A imagem oficial phpmyadmin:5.2.3 deleta setup/. Esse resquício só se aplica quando esse diretório ainda está na raiz web, que é o resquício comum após uma instalação. O lab restaura setup/ a partir do tarball 5.2.3 para que o pin corresponda a RELEASE_5_2_3.
PMASA-2016-44 / CVE-2016-6621 cobriu parte do SSRF de setup. A verificação "desabilitar setup quando config existe" nunca foi aplicada a validate.php / config.php.
| ID | sem CVE ainda |
| Classe | SSRF (protocolo MySQL) |
| Alcance | Remoto (não autenticado se setup/ ainda é acessível pela web) |
| CWE | CWE-918 |
| CVSS | Alto: 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N |
| Produto | phpMyAdmin |
| Afetado | 5.2.3 tag RELEASE_5_2_3 (962857e) com setup/ ainda no docroot |
| Auth | Não autenticado. Token CSRF da página de login pública. Sem login MySQL. |
| Licença | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:19230 apenas |
Qualquer um que consiga alcançar uma árvore setup/ remanescente pode fazer o host phpMyAdmin abrir uma conexão TCP de protocolo MySQL para um host e porta de sua escolha.
| Privilégio | Método / caminho | Comprovado no lab ou inferido |
|---|---|---|
| Abrir TCP do host PMA para host:porta do atacante (integridade da conexão de saída; reconhecimento dessa porta) | POST /setup/validate.php não autenticado id=Server com Servers/1/host + Servers/1/port mais um token de GET / | Comprovado no lab. Oráculo em oracle:13306 registrou PMA-SETUP-VALIDATE-WITNESS do contêiner PMA |
| Confirmar que a UI de setup está desligada enquanto validate permanece ligado | GET /setup/index.php | Comprovado no lab. Corpo contém "setup is disabled" / configuração já existe |
| Falhar de forma segura sem o token CSRF da página de login | Mesmo POST, sem token | Comprovado no lab. Zero acertos no oráculo |
| Oráculo de porta / credenciais a partir de erros do mysqli e timing | Mesmo testDBConnection | Inferido. Corpo do lab foi mysqli_connect(): (HY000/2006): MySQL server has gone away após o oráculo aceitar e então fechar |
| Falar MySQL com um 3306 interno e tentar usuário/senha postados | Mesmo mysqli_connect | Inferido. Não apontado para o serviço db do lab |
ReDoS via validateRegex interpolando regex de usuário | id=Servers/1/hide_db | Inferido. Não exercitado |
Fechado neste lab: SSRF de metadados HTTP (o handshake é MySQL, não GET /latest/meta-data), login PMA não autenticado, shell do SO e o próprio assistente de setup (index.php permanece desabilitado). FAIL se setup/ não estiver implantado (padrão da imagem oficial).
Oito buscas paralelas no código-fonte de RELEASE_5_2_3. setup/index.php tem o fatal de config-exists. setup/validate.php não. setup/lib/common.inc.php define $isMinimumCommon e não procura por CONFIG_FILE.
Caminhos errados: tratar a imagem oficial como este resquício (ela deleta setup/); fazer POST sem o token da página de login (zero acertos no oráculo); tratar isso como SSRF de metadados HTTP (o handshake é MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
ou
cd lab
./run.sh
Apenas loopback: http://127.0.0.1:19230. Projeto Compose phpmyadmin-setup-validate. Dockerfile restaura setup/ a partir do tarball 5.2.3 e executa um oráculo TCP na porta 13306. Witness PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
Coloque o fatal file_exists(CONFIG_FILE) em setup/lib/common.inc.php para que todo script de setup morra. Restrinja os hosts de testDBConnection. Não construa delimitadores de preg_match a partir de strings de usuário.
962857e)setup/index.php fatal de config-existssetup/validate.php sem essa verificaçãolibraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.