目标提交: 4b324845ba5d24682b9b3708a769f00d160afbd7(PostgreSQL 18.1 — 存在漏洞)
| 字段 | 详情 |
|---|---|
| CVE | CVE-2026-2005 |
| 类型 | 堆缓冲区溢出 |
| 组件 | contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey() |
| 影响 | 以运行 PostgreSQL 的操作系统用户身份执行任意代码(RCE) |
| CVSS | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| 所需认证 | 低 — 任何具有 CREATE 权限的已认证用户 |
| 受影响版本 | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| 修复版本 | 14.21, 15.16, 16.12, 17.8, 18.2(2026 年 2 月 12 日) |
| 架构 | aarch64 (ARM64) — 堆偏移量和 MBuf 布局与架构/glibc 相关 |
# 构建并启动 PostgreSQL 18.1(存在漏洞)
docker compose up -d --build
# 等待服务就绪
docker compose logs -f postgres
# 看到 "database system is ready to accept connections" 后按 Ctrl+C
# 一次性设置:复制 postgres 二进制文件用于离线符号解析
docker cp cve-2026-2005-poc:/usr/local/pgsql/bin/postgres ./postgres
# 安装 Node 依赖
npm install
# 运行完整的 RCE 利用链(纯 SQL — 无需与 Docker 交互)
node exploit.js --cmd "id"
# 启用详细输出
node exploit.js --cmd "id" --verbose
# 执行自定义命令
node exploit.js --cmd "whoami"
阶段 1:堆指针泄露
└─ 破坏 mdst chunk 头 → 解析 pfree() 错误消息
阶段 2:任意读取(多窗口扫描)
└─ 覆盖 mdst->data → 扫描泄露指针附近的内存
阶段 3:指针候选收集
└─ 扫描堆转储以查找类似指针的 8 字节值
阶段 4:PIE 基址解析
└─ 将泄露的地址与 ELF 符号偏移量进行投票比对(按页偏移
分组,离线 — 符号从本地二进制副本解析)
阶段 5:PIE 验证
└─ 在候选基址处任意读取 CurrentUserId → 与会话 OID 比较
阶段 6:任意写入
└─ 伪造 msrc + mdst MBuf → 覆盖 CurrentUserId → 10(超级用户)
阶段 7:命令执行
└─ COPY FROM PROGRAM → 以 postgres 用户身份执行任意操作系统命令
CVE-2026-2005/
├── Dockerfile # 从源码构建 PostgreSQL 18.1
├── docker-compose.yml # 带自动重启的 PostgreSQL 服务
├── init.sh # 入口点 — initdb + 监听配置
├── README.md # 本文件
└── poc/
├── package.json # Node.js 依赖(pg)
├── exploit.js # 完整的 7 阶段 RCE 利用脚本(Node.js)
├── verify.sh # 基于 Shell 的快速验证
└── test-pgcrypto.sql # 仅 SQL 的 pgcrypto 加载测试
git clone https://github.com/postgres/postgres.git
cd postgres
git checkout 4b324845ba5d24682b9b3708a769f00d160afbd7
./configure \
--prefix="$HOME/projects/pg/pgsql" \
--with-libxml \
--with-libxslt \
--enable-debug \
--with-ssl=openssl
make -j$(nproc)
make install-world-bin
tmux(可选 — 仅在 --gdb 标志下需要)该漏洞位于 contrib/pgcrypto/pgp-pubdec.c 中的 pgp_parse_pubenc_sesskey() 函数。
在解析 OpenPGP 公钥加密会话密钥数据包(标签 1)时:
memcpy 将会话密钥数据复制到固定大小的缓冲区中memcpy 可以写入超出堆缓冲区边界,破坏相邻的堆元数据或数据,从而导致任意代码执行。
pfree() 错误消息以提取 mdst->data 堆地址。/proc/<pid>/maps,在运行时查找 postgres 二进制的加载地址。msrc(源)和 mdst(目标)两个 MBuf 结构体。msrc 指向包含超级用户 OID(10)的内嵌 symenc 数据包;mdst 指向 CurrentUserId - 4(考虑 4 字节的 SET_VARSIZE 头)。CurrentUserId = 10(引导超级用户)时,执行 COPY FROM PROGRAM 以运行任意操作系统命令。pgcrypto 扩展是受信任的 — 任何具有 CREATE 权限(非超级用户)的用户都可以安装它,这使得该漏洞可以以低权限利用。--enable-debug,便于使用 gdb 进行调试。SRC_CHUNK_OFFSET=100、DST_CHUNK_OFFSET=172)特定于 aarch64 + glibc — 其他架构/分配器需要不同的偏移量。CurrentUserId 进行确认。| 标志 | 默认值 | 描述 |
|---|
--cmd | id | 利用成功后要执行的操作系统命令 |
--key-size | 3072 | RSA 密钥大小(位) |
--host | 127.0.0.1 | PostgreSQL 主机 |
--port | 5432 | PostgreSQL 端口 |
--user | postgres | 数据库用户 |
--password | (空) | 数据库密码 |
--dbname | postgres | 数据库名称 |
--binary | ./postgres | 用于符号解析的 postgres ELF 二进制文件路径 |
--scan-offset | 自动 | 覆盖从泄露指针开始的堆扫描偏移量 |
--verbose | 关闭 | 启用详细调试输出 |
--gdb | 关闭 | 在溢出点通过 tmux 附加 GDB |