
phpMyAdmin 5.2.3 – Hoch – Remote – verbleibend – setup/validate weiterhin erreichbar
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
Write-up: https://abraxaslabs.tech/research/phpmyadmin-setup-validate
Klasse: SSRF Reichweite: Remote
phpMyAdmin 5.2.3 (Tag RELEASE_5_2_3, Commit 962857e). setup/index.php bricht ab, wenn config.inc.php vorhanden ist. setup/validate.php nicht. Es wird weiterhin unter $isMinimumCommon geladen, holt sich ein CSRF-Token von der öffentlichen Login-Seite und ruft Validator::testDBConnection -> mysqli_connect mit Host, Port, Benutzer und Passwort aus dem JSON-Feld values auf.
Ein nicht authentifizierter Client sendet ein GET an /, um ein Session-Cookie und ein Token zu erhalten, und sendet dann ein POST an setup/validate.php mit id=Server sowie selbst gewähltem Servers/1/host und Servers/1/port. Der phpMyAdmin-Host öffnet einen TCP-MySQL-Handshake zu dieser Adresse. Das ist SSRF über das MySQL-Protokoll: internes 3306, Credential Stuffing gegen einen internen Server, ein Port-Orakel aus Timing und mysqli-Fehlern. Es ist kein HTTP-Metadata-SSRF, es sei denn, auf diesem Port spricht etwas MySQL. hide_db interpoliert außerdem einen Benutzer-Regex in preg_match. Diesen ReDoS-Pfad habe ich in diesem Lab nicht ausgeführt.
Das offizielle Image phpmyadmin:5.2.3 löscht setup/. Dieser Überrest gilt nur, wenn dieses Verzeichnis noch im Web-Root liegt, was der übliche Überrest nach einer Installation ist. Das Lab stellt setup/ aus dem 5.2.3-Tarball wieder her, damit die Version zu RELEASE_5_2_3 passt.
PMASA-2016-44 / CVE-2016-6621 deckte einige Setup-SSRF ab. Die Prüfung „Setup deaktivieren, wenn Konfiguration existiert“ wurde nie auf validate.php / config.php angewendet.
| ID | noch keine CVE |
| Klasse | SSRF (MySQL-Protokoll) |
| Reichweite | Remote (nicht authentifiziert, wenn setup/ noch über das Web erreichbar ist) |
| CWE | CWE-918 |
| CVSS | Hoch: 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N |
| Produkt | phpMyAdmin |
| Betroffen | 5.2.3 Tag RELEASE_5_2_3 (962857e) mit setup/ noch im Docroot |
| Auth | Nicht authentifiziert. CSRF-Token von der öffentlichen Login-Seite. Kein MySQL-Login. |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1:19230 |
Jeder, der einen zurückgebliebenen setup/-Baum erreichen kann, kann den phpMyAdmin-Host dazu bringen, eine TCP-Verbindung mit MySQL-Protokoll zu einem selbst gewählten Host und Port zu öffnen.
| Berechtigung | Methode / Pfad | Im Lab nachgewiesen oder abgeleitet |
|---|---|---|
| TCP vom PMA-Host zum Angreifer-Host:Port öffnen (Integrität des ausgehenden Verbindungsaufbaus; Recon dieses Ports) | Nicht authentifiziertes POST /setup/validate.php id=Server mit Servers/1/host + Servers/1/port plus einem Token aus GET / | Im Lab nachgewiesen. Orakel auf oracle:13306 protokollierte PMA-SETUP-VALIDATE-WITNESS aus dem PMA-Container |
| Bestätigen, dass die Setup-UI aus ist, während validate an bleibt | GET /setup/index.php | Im Lab nachgewiesen. Body enthält „setup is disabled“ / configuration already exists |
| Fail closed ohne das CSRF-Token der Login-Seite | Derselbe POST, ohne token | Im Lab nachgewiesen. Null Orakel-Treffer |
| Port-/Credential-Orakel aus mysqli-Fehlern und Timing | Derselbe testDBConnection | Abgeleitet. Der Lab-Body war mysqli_connect(): (HY000/2006): MySQL server has gone away, nachdem das Orakel akzeptiert und dann geschlossen hatte |
| MySQL mit einem internen 3306 sprechen und geposteten Benutzer/Passwort versuchen | Derselbe mysqli_connect | Abgeleitet. Nicht auf den Lab-db-Dienst gerichtet |
ReDoS über validateRegex, das Benutzer-Regex interpoliert | id=Servers/1/hide_db | Abgeleitet. Nicht ausgeführt |
Auf diesem Lab geschlossen: HTTP-Metadaten-SSRF (der Handshake ist MySQL, nicht GET /latest/meta-data), unauthentifizierter PMA-Login, OS-Shell und der Setup-Assistent selbst (index.php bleibt deaktiviert). FAIL, wenn setup/ nicht bereitgestellt ist (Standard des offiziellen Images).
Acht parallele Quellensuchen in RELEASE_5_2_3. setup/index.php hat den Fatal-Fehler bei vorhandener Konfiguration. setup/validate.php nicht. setup/lib/common.inc.php setzt $isMinimumCommon und sucht nicht nach CONFIG_FILE.
Irrwege: das offizielle Image für diesen Überrest zu halten (es löscht setup/); POSTen ohne das Token der Login-Seite (null Oracle-Treffer); dies für HTTP-Metadaten-SSRF zu halten (der Handshake ist MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
oder
cd lab
./run.sh
Nur Loopback: http://127.0.0.1:19230. Compose-Projekt phpmyadmin-setup-validate. Das Dockerfile stellt setup/ aus dem 5.2.3-Tarball wieder her und betreibt ein TCP-Oracle auf Port 13306. Witness PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
Setze den file_exists(CONFIG_FILE)-Fatalfehler in setup/lib/common.inc.php ab, sodass jedes Setup-Skript abbricht. Beschränke die Hosts von testDBConnection. Baue keine preg_match-Delimiter aus Benutzerzeichenketten.
962857e)setup/index.php Fatalfehler bei vorhandener Konfigurationsetup/validate.php ohne diese Prüfunglibraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. Siehe LICENSE. Nur für Loopback-Labore. Keine Gewährleistung.