
phpMyAdmin 5.2.3 - Alta - Remota - leftover - setup/validate ancora raggiungibile
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
Write-up: https://abraxaslabs.tech/research/phpmyadmin-setup-validate
Classe: SSRF Portata: Remota
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). setup/index.php termina quando config.inc.php è presente. setup/validate.php no. Viene comunque caricato sotto $isMinimumCommon, prende un token CSRF dalla pagina di login pubblica e chiama Validator::testDBConnection -> mysqli_connect verso host, porta, utente e password nel campo JSON values.
Un client non autenticato esegue una GET su / per ottenere un cookie di sessione e un token, poi invia una POST a setup/validate.php con id=Server e Servers/1/host e Servers/1/port a propria scelta. L'host phpMyAdmin apre un handshake TCP MySQL verso quell'indirizzo. Si tratta di SSRF sul protocollo MySQL: 3306 interno, credential stuffing contro un server interno, un port oracle basato su timing ed errori mysqli. Non è SSRF verso metadata HTTP a meno che qualcosa su quella porta parli MySQL. Anche hide_db interpola una regex fornita dall'utente in preg_match. Non ho eseguito quel percorso ReDoS in questo lab.
L'immagine ufficiale phpmyadmin:5.2.3 elimina setup/. Questo residuo si applica solo quando quella directory è ancora nella web root, che è il residuo comune dopo un'installazione. Il lab ripristina setup/ dal tarball 5.2.3 in modo che il pin corrisponda a RELEASE_5_2_3.
PMASA-2016-44 / CVE-2016-6621 copriva parte delle SSRF di setup. Il controllo "disabilita setup quando la config esiste" non è mai stato applicato a validate.php / config.php.
| ID | nessuna CVE al momento |
| Classe | SSRF (protocollo MySQL) |
| Portata | Remota (non autenticata se setup/ è ancora raggiungibile via 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 |
| Prodotto | phpMyAdmin |
| Affetto | 5.2.3 tag RELEASE_5_2_3 (962857e) con setup/ ancora nella docroot |
| Auth | Non autenticata. Token CSRF dalla pagina di login pubblica. Nessun login MySQL. |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1:19230 |
Chiunque possa raggiungere un albero setup/ residuo può far aprire all'host phpMyAdmin una connessione TCP con protocollo MySQL verso un host e una porta a propria scelta.
| Privilegio | Metodo / percorso | Provato nel lab o dedotto |
|---|---|---|
| Aprire TCP dall'host PMA verso host:porta dell'attaccante (integrità della connessione in uscita; ricognizione di quella porta) | POST /setup/validate.php non autenticata con id=Server e Servers/1/host + Servers/1/port più un token da GET / | Provato nel lab. L'oracle su oracle:13306 ha registrato PMA-SETUP-VALIDATE-WITNESS dal container PMA |
| Confermare che la UI di setup è disattivata mentre validate resta attivo | GET /setup/index.php | Provato nel lab. Il body contiene "setup is disabled" / configuration already exists |
| Fallire in modo sicuro senza il token CSRF della pagina di login | Stessa POST, senza token | Provato nel lab. Zero hit sull'oracle |
| Port / credential oracle da errori mysqli e timing | Stesso testDBConnection | Dedotto. Il body del lab era mysqli_connect(): (HY000/2006): MySQL server has gone away dopo che l'oracle aveva accettato e poi chiuso |
| Parlare MySQL verso un 3306 interno e provare utente/password inviati | Stesso mysqli_connect | Dedotto. Non puntato al servizio db del lab |
ReDoS tramite validateRegex che interpola una regex utente | id=Servers/1/hide_db | Dedotto. Non esercitato |
Chiuso su questo lab: SSRF su metadata HTTP (l'handshake è MySQL, non GET /latest/meta-data), login PMA non autenticato, shell del sistema operativo e il wizard di setup stesso (index.php resta disabilitato). FAIL se setup/ non è distribuito (default dell'immagine ufficiale).
Otto ricerche parallele nel codice sorgente di RELEASE_5_2_3. setup/index.php presenta il fatal di configurazione-esistente. setup/validate.php no. setup/lib/common.inc.php imposta $isMinimumCommon e non cerca CONFIG_FILE.
Vicoli ciechi: considerare l'immagine ufficiale come questo residuo (elimina setup/); fare POST senza il token della pagina di login (zero riscontri dall'oracolo); considerarlo un SSRF su metadata HTTP (l'handshake è MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
o
cd lab
./run.sh
Solo loopback: http://127.0.0.1:19230. Progetto Compose phpmyadmin-setup-validate. Il Dockerfile ripristina setup/ dal tarball 5.2.3 ed esegue un oracolo TCP sulla porta 13306. Witness PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
Inserisci il controllo fatale file_exists(CONFIG_FILE) in setup/lib/common.inc.php in modo che ogni script di setup termini. Limita gli host di testDBConnection. Non costruire delimitatori preg_match da stringhe fornite dall'utente.
962857e)setup/index.php controllo fatale config-existssetup/validate.php manca quel controllolibraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. Vedi LICENSE. Solo per laboratorio su loopback. Nessuna garanzia.