
phpMyAdmin 5.2.3 - Alta - Remota - XSS - Designer Visual Query Builder
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-vqb-xss
Classe: XSS memorizzato Portata: Remota
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
js/src/designer/history.js costruisce la cronologia delle query visuali con innerHTML. I nomi delle colonne passano attraverso $('<div/>').text(...).html(). I nomi delle tabelle no. TableName consente ancora < e >. Un account con privilegi ridotti con CREATE TABLE su un database condiviso inserisce un identificatore HTML. Quando un utente con privilegi superiori apre Designer, getTableName() è presente nella pagina e DesignerHistory.display() lo scrive in #ab.
Un XSS memorizzato nell'origine di phpMyAdmin. Stessa classe di PMASA-2025-1, funzionalità diversa. Le intestazioni di Check-tables erano sottoposte a escape. Questo percorso no.
| ID | nessuna CVE al momento |
| Classe | XSS memorizzato |
| Portata | Remota (CREATE TABLE autenticato; la vittima apre Designer) |
| CWE | CWE-79 |
| CVSS | Alto: 8.0 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N |
| Prodotto | phpMyAdmin |
| Affetto | 5.2.3 tag RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Auth | autenticato. L'attaccante necessita di CREATE TABLE su un database che la vittima apre in Designer |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Inserire un nome di tabella HTML, poi attendere che un utente con privilegi superiori apra Designer su quel database e visualizzi la cronologia delle query visuali.
| Privilegio | Metodo / sink | Ricognizione / integrità / disponibilità | Provato in lab o dedotto |
|---|---|---|---|
| Iniettare markup nell'origine di phpMyAdmin | DesignerHistory.display() concatena getTab() nell'innerHTML di #ab | Integrità dell'origine della vittima | Provato in lab. history.js live su phpmyadmin:5.2.3. <h3> conteneva <i id="pma-vqb"> |
Uscire da un attributo table_name di designer | database_tables.twig small_tab_pref_1 usa designerTable.getTableName() | Ricognizione del nome MySQL grezzo nel DOM di Designer | Provato in lab, leggibile come identificatore grezzo |
Leggere il cookie di sessione della vittima e il token CSRF | Script same-origin una volta renderizzata la cronologia | Ricognizione della sessione PMA della vittima | Dedotto da XSS memorizzato nell'origine PMA. Questo lab usa un marcatore <i>, non uno script |
| Eseguire SQL, gestire utenti, esportare, come l'account MySQL della vittima | POST con token su /sql, /server/privileges, export | Integrità di tutto ciò che quell'account MySQL può toccare | Dedotto. Stessa classe di impatto di PMASA-2025-1 |
| Modificare 2FA / userconfig | POST /config/set come la vittima | Integrità dell'archivio delle preferenze della vittima | Dedotto. Residuo affine, non questo lab |
Chiusi su questo residuo: accesso non autenticato, RCE a livello OS e il percorso del pulsante OK del VQB. .small_tab_pref_click_opt pre-esegue l'escape di table_name e Twig lo auto-esegue di nuovo, quindi quel click attualmente immette entità in getTab(). Non è una correzione di history.js. Le celle delle colonne restano con testo sottoposto a escape (c<b id=pma-col>y, nessun nodo <b id="pma-col">).
Stesso pin: residuo WebAuthn CustomServer.
Ho fissato phpMyAdmin RELEASE_5_2_3. PMASA-2025-1/2/3 sono già in 5.2.2. Designer costruisce ancora a mano l'HTML della cronologia VQB.
js/src/designer/history.js (distribuito come 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 verifica solo che non sia vuoto, massimo 64, nessuno spazio finale. < e > sono legali. MySQL li accetta in un identificatore tra virgolette.
templates/database/designer/database_tables.twig copia designerTable.getTableName() in table_name su .small_tab_pref_1. La cella dell'opzione VQB usa una copia pre-eseguita con escape dello stesso nome.
Vicoli ciechi già registrati: trattare l'attributo del pulsante opzione con doppio escape come la correzione (non lo è - small_tab_pref_1 espone ancora il nome grezzo, e history.js è il sink); trattare l'helper delle colonne come coprente dei nomi delle tabelle; sostenere XSS non autenticato; una reverse shell. Teatro.
python3 phpmyadmin-vqb-xss-Abraxas-Labs.py
# or: cd lab && ./run.sh
Target solo http://127.0.0.1:19250. Immagini phpmyadmin:5.2.3 e mysql:8.0. Progetto Compose phpmyadmin-vqb-xss. Playwright Chromium nel servizio poc. Lo stack viene smontato dopo l'esecuzione.
Due utenti, shareddb condiviso. Il creator a privilegi ridotti esegue CREATE TABLE \tx` (`cy` INT). La victimcon privilegi superiori accede a phpMyAdmin e apre Designer conquery=1. history.js live è la copia dal container (h3-unescaped=yes, helper delle colonne presente). Chromium chiama DesignerHistory.display()con il nome della tabella dagetTableName()` nella pagina.
Risultato: l'innerHTML di #ab h3.tiger è <a href="#">t<i id="pma-vqb">x</i></a>. Il testo della td della colonna è c<b id=pma-col>y senza nodo b#pma-col.
SUCCESS phpmyadmin-vqb-xss h3-markup=yes col-escaped=yes how=live PMA-VQB-XSS-WITNESS
Eseguire l'escape di getTab() con $('<div/>').text(temp).html() o Functions.escapeHtml prima di concatenare nell'<h3>. Non affidarsi alla doppia codifica Twig di un attributo. Mantenere l'helper del nome della colonna come modello.
962857e4f63d42e38f11ff4d63f5e722018add76)js/src/designer/history.jslibraries/classes/Dbal/TableName.phpGNU Affero GPL v3.0. Vedi LICENSE. Solo lab su loopback. Nessuna garanzia.