
phpMyAdmin 5.2.3 – Hoch – Remote – XSS – Designer Visual Query Builder
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-vqb-xss
Klasse: Stored XSS Reichweite: Remote
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
js/src/designer/history.js erstellt den Verlauf visueller Abfragen mit innerHTML. Spaltennamen durchlaufen $('<div/>').text(...).html(). Tabellennamen nicht. TableName erlaubt weiterhin < und >. Ein Konto mit geringen Rechten und CREATE TABLE auf einer gemeinsam genutzten Datenbank platziert einen HTML-Bezeichner. Wenn ein Benutzer mit höheren Rechten den Designer öffnet, liegt getTableName() auf der Seite und DesignerHistory.display() schreibt ihn in #ab.
Ein Stored XSS im phpMyAdmin-Ursprung. Gleiche Klasse wie PMASA-2025-1, anderes Feature. Check-tables-Überschriften wurden escaped. Dieser Pfad nicht.
| ID | noch keine CVE |
| Klasse | Stored XSS |
| Reichweite | Remote (authentifiziertes CREATE TABLE; Opfer öffnet Designer) |
| CWE | CWE-79 |
| CVSS | Hoch: 8.0 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N |
| Produkt | phpMyAdmin |
| Betroffen | 5.2.3 Tag RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Auth | authentifiziert. Angreifer benötigt CREATE TABLE auf einer Datenbank, die das Opfer im Designer öffnet |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Einen HTML-Tabellennamen platzieren und dann darauf warten, dass ein Benutzer mit höheren Rechten den Designer auf dieser Datenbank öffnet und den Verlauf visueller Abfragen rendert.
| Recht | Methode / Sink | Recon / Integrität / Verfügbarkeit | Im Lab nachgewiesen oder abgeleitet |
|---|---|---|---|
| Markup in den phpMyAdmin-Ursprung injizieren | DesignerHistory.display() konkateniert getTab() in #ab innerHTML | Integrität des Opfer-Ursprungs | Im Lab nachgewiesen. Live history.js auf phpmyadmin:5.2.3. <h3> enthielt <i id="pma-vqb"> |
Aus einem Designer-table_name-Attribut ausbrechen | database_tables.twig small_tab_pref_1 verwendet designerTable.getTableName() | Recon des rohen MySQL-Namens im Designer-DOM | Im Lab nachgewiesen, lesbar als der rohe Bezeichner |
Das Session-Cookie des Opfers und das CSRF-token lesen | Same-Origin-Skript, sobald der Verlauf gerendert wird | Recon der PMA-Session des Opfers | Abgeleitet aus Stored XSS im PMA-Ursprung. Dieses Lab verwendet einen <i>-Marker, kein Skript |
| SQL ausführen, Benutzer verwalten, exportieren, als das MySQL-Konto des Opfers | Token-gestütztes POST /sql, /server/privileges, Export | Integrität von allem, was dieses MySQL-Konto berühren kann | Abgeleitet. Gleiche Auswirkungsklasse wie PMASA-2025-1 |
| 2FA / userconfig ändern | POST /config/set als das Opfer | Integrität des Präferenzspeichers des Opfers | Abgeleitet. Verwandter Rest, nicht dieses Lab |
Bei diesem Rest ausgeschlossen: unauthentifizierter Zugriff, OS RCE und der VQB-OK-Button-Pfad. .small_tab_pref_click_opt escaped table_name vorab und Twig escaped es erneut automatisch, sodass dieser Klick derzeit Entities in getTab() einspeist. Das ist keine Behebung von history.js. Spaltenzellen bleiben text-escaped (c<b id=pma-col>y, kein <b id="pma-col">-Knoten).
Gleicher Pin: WebAuthn CustomServer Rest.
Ich habe phpMyAdmin RELEASE_5_2_3 gepinnt. PMASA-2025-1/2/3 sind bereits in 5.2.2. Der Designer erstellt VQB-Verlaufs-HTML weiterhin von Hand.
js/src/designer/history.js (ausgeliefert als js/dist/designer/history.js):
temp = historyArray[i].getTab();
str += '<h3 class="tiger"><a href="#">' + temp + '</a></h3>';
// ...
'<td width="175" style="padding-left: 5px">' + $('<div/>').text(historyArray[i].getColumnName()).html() + '<td>';
libraries/classes/Dbal/TableName.php prüft nur auf nicht leer, maximal 64, kein abschließendes Leerzeichen. < und > sind zulässig. MySQL akzeptiert sie in einem quoted identifier.
templates/database/designer/database_tables.twig kopiert designerTable.getTableName() in table_name auf .small_tab_pref_1. Die VQB-Optionszelle verwendet eine vorab escaped Kopie desselben Namens.
Bereits festgehaltene Irrwege: das doppelt escaped Attribut des Options-Buttons als die Behebung zu betrachten (ist es nicht - small_tab_pref_1 legt weiterhin den rohen Namen offen, und history.js ist der Sink); den Spalten-Helper als Abdeckung für Tabellennamen zu betrachten; unauthentifiziertes XSS zu behaupten; eine Reverse Shell. Theater.
python3 phpmyadmin-vqb-xss-Abraxas-Labs.py
# or: cd lab && ./run.sh
Ziel nur http://127.0.0.1:19250. Images phpmyadmin:5.2.3 und mysql:8.0. Compose-Projekt phpmyadmin-vqb-xss. Playwright Chromium im poc-Service. Der Stack wird nach dem Lauf abgebaut.
Zwei Benutzer, gemeinsame shareddb. Der Benutzer mit geringen Rechten creator führt CREATE TABLE \tx` (`cy` INT)aus. Der Benutzer mit höheren Rechtenvictimmeldet sich bei phpMyAdmin an und öffnet den Designer mitquery=1. Live history.js ist die Kopie aus dem Container (h3-unescaped=yes, Spalten-Helper vorhanden). Chromium ruft DesignerHistory.display()mit dem Tabellennamen ausgetTableName()` auf der Seite auf.
Ergebnis: #ab h3.tiger innerHTML ist <a href="#">t<i id="pma-vqb">x</i></a>. Der Spalten-td-Text ist c<b id=pma-col>y ohne b#pma-col-Knoten.
SUCCESS phpmyadmin-vqb-xss h3-markup=yes col-escaped=yes how=live PMA-VQB-XSS-WITNESS
getTab() mit $('<div/>').text(temp).html() oder Functions.escapeHtml escapen, bevor es in das <h3> konkateniert wird. Sich nicht auf die Twig-Doppelkodierung eines Attributs verlassen. Den Spaltennamen-Helper als Vorbild beibehalten.
962857e4f63d42e38f11ff4d63f5e722018add76)js/src/designer/history.jslibraries/classes/Dbal/TableName.phpGNU Affero GPL v3.0. Siehe LICENSE. Nur Loopback-Lab. Keine Gewährleistung.