
phpMyAdmin 5.2.3 - Alta - Remoto - leftover - verificação isSuperUser ignorada
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-issuperuser
Classe: Privilégio remanescente Alcance: Remoto
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
DatabaseInterface::isSuperUser() não é uma verificação de SUPER / SYSTEM_USER. É SELECT 1 FROM mysql.user LIMIT 1. Qualquer conta que consiga ler mysql.user é armazenada em cache como superusuário pelo resto da sessão. $cfg['AllowUserDropDatabase'] tem como padrão false. DestroyController, SqlController, ImportController e a página de bancos de dados usam o atalho isSuperUser contornando essa flag.
Um bypass de política do phpMyAdmin, não um novo privilégio do MySQL. SELECT em mysql.user mais DROP, e sem SUPER, é suficiente para Drop através do PMA.
| ID | sem CVE ainda |
| Classe | Privilégio remanescente |
| Alcance | Remoto (login autenticado por cookie como uma conta MySQL) |
| CWE | CWE-863 |
| CVSS | Médio: 6.3 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L |
| Produto | phpMyAdmin |
| Afetado | 5.2.3 tag RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Autenticação | login autenticado por cookie como uma conta MySQL |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Uma conta MySQL autenticada que consegue ler mysql.user (típico SELECT de backup/monitoramento) mais DROP, sem SUPER, é tratada como superusuário do phpMyAdmin.
| Privilégio | Método / sink | Recon / integridade / disponibilidade | Comprovado em lab ou inferido |
|---|---|---|---|
Contornar $cfg['AllowUserDropDatabase']=false e ver Drop na página de bancos de dados | GET index.php?route=/server/databases | Recon da UI de Drop | Comprovado em lab. bulkActionDropButton / selected_dbs[] presente para selectuser; ausente para plaindrop |
| Dropar um banco de dados através do handler destroy do PMA | POST index.php?route=/server/databases/destroy selected_dbs[]=dropme ajax_request=true | Integridade / disponibilidade desse banco de dados | Comprovado em lab. JSON success:true, "1 database has been dropped successfully." dropme sumiu |
Executar DROP DATABASE pela caixa SQL | POST index.php?route=/sql sql_query=DROP DATABASE \dropme_sql`` | Integridade / disponibilidade desse banco de dados | Comprovado em lab. Banco de dados sumiu. Conta negativa recebe "DROP DATABASE statements are disabled." |
Desbloquear outras telas do PMA protegidas por isSuperUser() | Privilégios, replicação, status, grupos de usuários, engines, binlog, variáveis | Recon / integridade dessas telas | Inferido a partir dos call sites. Não exercitado |
Ler mysql.user | SELECT no MySQL que o PMA usa como oráculo de SUPER | Recon do catálogo que o PMA confunde com SUPER | Comprovado em lab. Essa concessão é o que o remanescente confunde com SUPER |
Fechado neste lab: SUPER real do MySQL (SHOW GRANTS permanece USAGE + DROP de tabela + SELECT em mysql.user). FILE, GRANT OPTION, shutdown e ALL PRIVILEGES não são concedidos. Uma conta com DROP mas sem SELECT em mysql.user ainda não consegue dropar através do PMA. Este não é um novo privilégio do MySQL e não é RCE.
Mesmo pin: WebAuthn CustomServer leftover.
Eu fixei o phpMyAdmin RELEASE_5_2_3. Gates de privilégio que falam como SUPER deveriam parecer SUPER. Este se parece com um SELECT de catálogo:
$result = $this->tryQuery('SELECT 1 FROM mysql.user LIMIT 1');
$isSuperUser = false;
if ($result) {
$isSuperUser = (bool) $result->numRows();
}
SessionCache::set('is_superuser', $isSuperUser);
Gates que usam essa flag em torno de AllowUserDropDatabase (padrão false):
Controllers/Server/DatabasesController.php is_drop_allowedControllers/Server/Databases/DestroyController.php (destroy AJAX)Controllers/Sql/SqlController.php / Sql::hasNoRightsToDropDatabaseControllers/Import/ImportController.phpControllers/Database/OperationsController.phpCaminhos errados já registrados: alegar SUPER real do MySQL; tratar uma conta apenas com DROP como o bug (essa conta é o controle negativo); inflar isso para RCE; um reverse shell. Teatro.
python3 phpmyadmin-issuperuser-Abraxas-Labs.py
# or: cd lab && ./run.sh
Alvo apenas http://127.0.0.1:19270. Imagens phpmyadmin:5.2.3 e mysql:8.0. Projeto Compose phpmyadmin-issuperuser. $cfg['AllowUserDropDatabase']=false. A stack é desmontada após a execução.
selectuser tem SELECT em mysql.user mais DROP em dropme / dropme_sql, sem SUPER. plaindrop tem DROP apenas em nodropme. A página de bancos de dados desenha Drop para selectuser. POST /server/databases/destroy dropa dropme. POST /sql com DROP DATABASE dropme_sql também executa. plaindrop ainda recebeu o JSON de Error do destroy e "DROP DATABASE statements are disabled" do /sql.
SUCCESS phpmyadmin-issuperuser drop-ui=yes destroy=ok sql-drop=ok grants-no-super=yes mysql.user-select=yes neg-drop-ui=no neg-destroy=denied PMA-ISSUPERUSER-WITNESS
Teste SUPER / SYSTEM_USER reais via INFORMATION_SCHEMA ou SHOW GRANTS. Mantenha uma flag separada de "pode ler mysql.user" para UI que realmente precise desse catálogo. Não armazene em cache um SELECT de catálogo como superusuário.
962857e4f63d42e38f11ff4d63f5e722018add76)libraries/classes/DatabaseInterface.php isSuperUser()GNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.