phpMyAdmin 5.2.3 - Alta - Remoto - SQLi - Identificadores não sanitizados no JSON do Designer
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-designer-json-sqli
Classe: SQLi Alcance: Remoto
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). O AJAX do Designer save_setting_value faz json_encode do blob de configurações e o concatena em um UPDATE/INSERT entre aspas simples no link do usuário de controle. O nome de usuário é escapado. O JSON não. json_encode não escapa uma aspa simples.
Um usuário autenticado envia POST para index.php?route=/database/designer com operation=save_setting_value e uma aspa em value. queryAsControlUser então executa essa string como o usuário de controle do pma contra pma__designer_settings. Essa conta é o armazenamento de configuração, não o SQL box do usuário logado. O phpMyAdmin 6.x envolve esse blob em quoteString no ControlUser. O 5.2.3 ainda o concatena cru.
CVEs mais antigas do designer (2016-6616, 2019-11768, 2019-18622) eram de nome de usuário / nome de banco de dados. Este resquício é a coluna JSON settings_data.
| ID | ainda sem CVE |
| Classe | SQLi (usuário de controle em pma__designer_settings) |
| Alcance | Remoto (login autenticado por cookie; Designer + pma__designer_settings habilitados) |
| CWE | CWE-89 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produto | phpMyAdmin |
| Afetado | 5.2.3 tag RELEASE_5_2_3 (962857e) |
| Autenticação | Login autenticado por cookie. Designer + pma__designer_settings habilitados. |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1:19220 |
Um usuário autenticado do phpMyAdmin que consegue abrir o Designer pode injetar SQL como o usuário de controle em pma__designer_settings.
| Privilégio | Método / caminho | Comprovado em lab ou inferido |
|---|---|---|
| Quebrar a string UPDATE/INSERT do usuário de controle (integridade do SQL do pmadb) | POST index.php?route=/database/designer operation=save_setting_value com uma aspa em value | Comprovado em lab. General log: SET settings_data = '{"snap_line":"PMA-DESIGNER-JSON-SQLI-WITNESS'#" }' cru. quoteString ausente |
Truncar o próprio settings_data para que não seja mais JSON (integridade da própria linha) | Mesmo POST; # comenta o resto da instrução | Comprovado em lab. O blob de appuser contém o witness e não é JSON válido. O save limpo grid-ok desapareceu |
| Sobrescrever as linhas de designer de outros usuários sem queries empilhadas (integridade da linha da vítima) | Mesmo # comenta WHERE username = '...' | Comprovado em lab. O victim semeado {"keep":"safe"} tornou-se o blob witness truncado |
| Instruções extras como o usuário de controle | Mesmo sink se o link mysqli de controle permitir multi-query | Inferido. O padrão de mysqli::query é instrução única. Não habilitado aqui |
Alcançar outras tabelas do pmadb (bookmarks, history, pma__userconfig) | Apenas se queries empilhadas ou um breakout de escrita for possível | Inferido. O usuário de controle neste lab tem apenas DML em phpmyadmin.* |
Fechado neste lab: acesso não autenticado, o SQL box do appuser autenticado (apenas appdb; appuser não tem GRANT em phpmyadmin), shell do SO e queries empilhadas. O recurso não faz nada se o pmadb / designer settings estiver desligado (isso é um FAIL, não este resquício).
Oito caçadas paralelas ao código-fonte de RELEASE_5_2_3. saveSetting concatena json_encode em '...'. O nome de usuário é escapeString. O 6.x já faz quoteString desse blob. O 5.2.3 não.
Caminhos errados: injetar no nome de usuário (ele é escapado); esperar um #1064 (o # comenta o resto, então o MySQL aceita o UPDATE truncado); tratar queries empilhadas como comprovadas (o padrão do mysqli é instrução única).
python3 phpmyadmin-designer-json-sqli-Abraxas-Labs.py
ou
cd lab
./run.sh
Apenas loopback: http://127.0.0.1:19220. Imagens phpmyadmin:5.2.3 e mysql:8.0. Projeto Compose phpmyadmin-designer-json-sqli. Witness PMA-DESIGNER-JSON-SQLI-WITNESS.
SUCCESS phpmyadmin-designer-json-sqli version=5.2.3 how=live raw-concat=yes truncated=true sql-error=false quoteString=no PMA-DESIGNER-JSON-SQLI-WITNESS
quoteString(..., ControlUser) / escapeString no blob JSON, assim como RecentFavoriteTable::saveToDb() e o phpMyAdmin 6.x nesta coluna. Não coloque a saída de json_encode dentro de um literal SQL entre aspas simples.
962857e)libraries/classes/Database/Designer/Common.php saveSettingControllers/Database/DesignerController.php POST operation=save_setting_valueGET|POST /database/designerGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.