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
Write-up: https://abraxaslabs.tech/research/phpmyadmin-designer-json-sqli
Classe: SQLi Alcance: Remoto
phpMyAdmin 5.2.3 (tag RELEASE_5_2_3, commit 962857e). O AJAX save_setting_value do Designer aplica json_encode ao blob de configurações e o concatena em um UPDATE/INSERT com aspas simples no vínculo do usuário de controle. O nome de usuário é escapado. O JSON não é. json_encode não escapa aspas simples.
Um usuário autenticado envia via POST para index.php?route=/database/designer com operation=save_setting_value e uma aspa em value. Em seguida, queryAsControlUser executa essa string como o usuário de controle do pma contra pma__designer_settings. Essa conta é o armazenamento de configuração, não a caixa SQL do usuário logado. O phpMyAdmin 6.x envolve esse blob em quoteString no ControlUser. O 5.2.3 ainda o concatena diretamente.
CVEs mais antigas do designer (2016-6616, 2019-11768, 2019-18622) envolviam o nome de usuário / nome do banco de dados. Este resquício é a coluna JSON settings_data.
| ID | sem CVE ainda |
| 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. Log geral: SET settings_data = '{"snap_line":"PMA-DESIGNER-JSON-SQLI-WITNESS'#" }' bruto. quoteString ausente |
Truncar o próprio settings_data para que não seja mais JSON (integridade da própria linha) | Mesmo POST; # comenta o restante da instrução | Comprovado em lab. O blob de appuser contém o witness e não é JSON válido. O salvamento limpo grid-ok desapareceu |
| Sobrescrever linhas de designer de outros usuários sem consultas empilhadas (integridade da linha da vítima) | O mesmo # comenta WHERE username = '...' | Comprovado em lab. O seed victim {"keep":"safe"} tornou-se o blob witness truncado |
| Instruções extras como o usuário de controle | Mesmo sink se o vínculo mysqli de controle permitir múltiplas consultas | Inferido. O padrão mysqli::query é de instrução única. Não habilitado aqui |
Alcançar outras tabelas do pmadb (bookmarks, history, pma__userconfig) | Apenas se consultas 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, a caixa SQL do appuser autenticado (apenas appdb; appuser não tem GRANT em phpmyadmin), shell do SO e consultas empilhadas. O recurso não faz nada se o pmadb / as configurações do designer estiverem desativados (isso é uma FALHA, não este resquício).
Oito buscas paralelas no código-fonte de RELEASE_5_2_3. saveSetting concatena json_encode em '...'. O nome de usuário passa por escapeString. O 6.x já aplica quoteString a este blob. O 5.2.3 não.
Erros de percurso: injetar no nome de usuário (ele é escapado); esperar um #1064 (o # comenta o resto, então o MySQL aceita o UPDATE truncado); tratar consultas 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, da mesma forma que 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. Consulte LICENSE. Apenas laboratório em loopback. Sem garantias.