
phpMyAdmin 5.2.3 - High - Remote - leftover - setup/validate still reachable
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
Class: SSRF Reach: Remote
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). setup/index.php dies when config.inc.php is present. setup/validate.php does not. It still loads under $isMinimumCommon, takes a CSRF token from the public login page, and calls Validator::testDBConnection -> mysqli_connect to the host, port, user, and password in the JSON values field.
An unauthenticated client GETs / to pick up a session cookie and token, then POSTs setup/validate.php id=Server with Servers/1/host and Servers/1/port of their choosing. The phpMyAdmin host opens a TCP MySQL handshake to that address. That is SSRF over the MySQL protocol: internal 3306, credential stuffing against an internal server, a port oracle from timing and mysqli errors. It is not HTTP metadata SSRF unless something on that port speaks MySQL. hide_db also interpolates a user regex into preg_match. I did not run that ReDoS path in this lab.
The official phpmyadmin:5.2.3 image deletes setup/. This leftover only applies when that directory is still in the web root, which is the common leftover after an install. The lab restores setup/ from the 5.2.3 tarball so the pin matches RELEASE_5_2_3.
PMASA-2016-44 / CVE-2016-6621 covered some setup SSRF. The "disable setup when config exists" check was never applied to validate.php / config.php.
| ID | no CVE yet |
| Class | SSRF (MySQL protocol) |
| Reach | Remote (unauthenticated if setup/ is still web-reachable) |
| CWE | CWE-918 |
| CVSS | High: 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N |
| Product | phpMyAdmin |
| Affected | 5.2.3 tag RELEASE_5_2_3 (962857e) with setup/ still in the docroot |
| Auth | Unauthenticated. CSRF token from the public login page. No MySQL login. |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:19230 only |
Anyone who can reach a leftover setup/ tree can make the phpMyAdmin host open a MySQL-protocol TCP connection to a host and port they choose.
| Privilege | Method / path | Lab-proven or inferred |
|---|---|---|
| Open TCP from the PMA host to attacker host:port (integrity of outbound connect; recon of that port) | Unauthenticated POST /setup/validate.php id=Server with Servers/1/host + Servers/1/port plus a token from GET / | Lab-proven. Oracle on oracle:13306 logged PMA-SETUP-VALIDATE-WITNESS from the PMA container |
| Confirm setup UI is off while validate stays on | GET /setup/index.php | Lab-proven. Body contains "setup is disabled" / configuration already exists |
| Fail closed without the login-page CSRF token | Same POST, no token | Lab-proven. Zero oracle hits |
| Port / credential oracle from mysqli errors and timing | Same testDBConnection | Inferred. Lab body was mysqli_connect(): (HY000/2006): MySQL server has gone away after the oracle accepted then closed |
| Talk MySQL to an internal 3306 and try posted user/password | Same mysqli_connect | Inferred. Not pointed at the lab db service |
ReDoS via validateRegex interpolating user regex | id=Servers/1/hide_db | Inferred. Not exercised |
Closed on this lab: HTTP metadata SSRF (the handshake is MySQL, not GET /latest/meta-data), unauthenticated PMA login, OS shell, and the setup wizard itself (index.php stays disabled). FAIL if setup/ is not deployed (official image default).
Eight parallel source hunts of RELEASE_5_2_3. setup/index.php has the config-exists fatal. setup/validate.php does not. setup/lib/common.inc.php sets $isMinimumCommon and does not look for CONFIG_FILE.
Wrong turns: treating the official image as this leftover (it deletes setup/); POSTing without the login-page token (zero oracle hits); treating this as HTTP metadata SSRF (the handshake is MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
or
cd lab
./run.sh
Loopback only: http://127.0.0.1:19230. Compose project phpmyadmin-setup-validate. Dockerfile restores setup/ from the 5.2.3 tarball and runs a TCP oracle on port 13306. Witness PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
Put the file_exists(CONFIG_FILE) fatal in setup/lib/common.inc.php so every setup script dies. Restrict testDBConnection hosts. Do not build preg_match delimiters from user strings.
962857e)setup/index.php config-exists fatalsetup/validate.php no that checklibraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.