PostgreSQL 18.6 - 高危 - 远程 - 文件写入 - pg_basebackup 跟随绝对路径 tar 符号链接,CVE-2026-6475 遗留问题
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · postgres-basebackup-symlink
技术分析文章:https://abraxaslabs.tech/research/postgres-basebackup-symlink
类别: 文件写入 可达性: 远程
PostgreSQL 18.6 (724edf9) - PostgreSQL Global Development Group
CVE-2026-6475 为 tar 成员名 添加了 path_is_safe_for_extraction。绝对 符号链接目标 仍然跳过该检查,以便表空间正常工作。随后 astreamer_file.c 会对目标执行 symlink(),之后 fopen(..., "wb") 会跟随该链接。默认的 pg_basebackup 格式为 plain(-F p)。pg_rewind 的 create_target_symlink 会检查路径,但从不检查链接。
一个能说 BASE_BACKUP 协议的恶意源可以植入绝对符号链接,并覆盖备份 UID 可写入的任何文件。 受害者模型与 6475 相同。这不是对成员名检查的重复提交。
| ID | 暂无 CVE |
| 类别 | 文件写入(CVE-2026-6475 遗留的绝对 tar 符号链接问题) |
| 可达性 | 远程(UI:R 客户端 对 恶意 PostgreSQL) |
| CWE | CWE-59、CWE-22 |
| CVSS | 高危:8.8 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| 产品 | PostgreSQL |
| 受影响版本 | 18.6 标签 REL_18_6(724edf9bde9d356724ad384a2e196edc3c9f80f7),源码树内的 pg_basebackup / pg_rewind |
| 认证 | 受害者针对攻击者源运行默认的 pg_basebackup -D <dir> |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
任何能让操作员针对其 PostgreSQL 运行 pg_basebackup -D 的人(与 CVE-2026-6475 相同的 UI:R 模型)都可以在 -D 之外写入。
| 权限 | 方法 / 汇点 | 实验验证或推断 |
|---|---|---|
完整性:在 -D 之外写入文件 | 恶意 BASE_BACKUP tar:typeflag 为 '2' 的成员,具有安全的相对名称(pg_tblspc/16384)和绝对链接目标,然后在该名称下放置一个常规成员。extract_link 随后 create_file_for_extract 调用 fopen(..., "wb"),且没有 O_NOFOLLOW | 实验验证。在 /work/oracle/ 写入了 POSTGRES-BASEBACKUP-SYMLINK-WITNESS。目标目录中保留了该符号链接。对照 tar(无符号链接)使 oracle 保持为空,并且仅在 -D 内写入了 PG_VERSION |
完整性:覆盖 shell rc、authorized_keys、systemd 用户单元或 crontab | 同一汇点,客户端 UID 可写入的任何路径 | 推断。本实验未触碰这些文件 |
| 可用性:破坏客户端配置或密钥 | 同一写入 | 推断。未演示 |
| 客户端磁盘侦察 | 解压是写入,不是读取 | 已排除 |
遍历 .. 或绝对 成员名 | path_is_safe_for_extraction | 已排除。那是 CVE-2026-6475 |
| 服务端非特权 SQL / 未认证协议 | 18.6 默认服务器 | 已排除。此遗留问题在客户端 |
| 仅 tar 备份 | pg_basebackup -F t 存储 tar 而不解压 | 已排除 |
在 postgres 内实现 RCE | 不是此汇点 | 已排除 |
pg_rewind 具有相同的 create_target_symlink / open() 遗留问题。本实验仅驱动 pg_basebackup。
在 18.6 浪潮之后(28 个 CVE,加上已在此代码树上的 18.4/18.2 系列),我锁定了 postgres/postgres REL_18_6。进行了二十二次排查。默认服务器、非特权 SQL、未认证协议:在此标准下均无发现。CVE-2026-6475 是值得重新阅读的同类问题。
成员名会被检查。绝对符号链接目标则不会:
if (!is_absolute_path(linktarget) &&
!path_is_safe_for_extraction(member->linktarget))
{
pg_fatal("link target has unsafe path name: \"%s\"",
member->linktarget);
}
extract_link(mystreamer->filename, linktarget);
create_file_for_extract 仍然是 fopen(filename, "wb")。astreamer_file.c:351-356 处的注释说,映射是在未检查链接是否位于 pg_tblspc 内的情况下应用的。
已记录的弯路:把 6475 当作已关闭并就此走开;将 -D 指向一个正在使用的数据目录;为了作秀而覆盖 shell rc。一个诚实的 18.6 服务器只会发出 pg_tblspc/<oid> 符号链接,并将表空间内容放入单独的归档中。一个会讲 BASE_BACKUP 的恶意源可以将后续的常规成员放入同一个 tar 中。这就是遗留问题。
python3 postgres-basebackup-symlink-Abraxas-Labs.py
或
cd lab
./run.sh
postgres:18.6 作为源镜像,运行 BASE_BACKUP 发送端。客户端使用同一标签的树内 pg_basebackup(pg_basebackup (PostgreSQL) 18.6)。回环地址 127.0.0.1:19370。Compose 项目 postgres-basebackup-symlink。不要将 -D 指向活动数据目录。
SUCCESS postgres-basebackup-symlink control-inside=yes oracle-outside=yes dest-is-symlink=yes image=postgres:18.6 how=pg_basebackup POSTGRES-BASEBACKUP-SYMLINK-WITNESS
除非通过 --tablespace-mapping 重写,否则将绝对符号链接目标视为不安全。使用 O_NOFOLLOW / lstat 打开提取文件,使预先植入的链接无法被跟随。对 link 以及 path 应用 path_is_safe_for_extraction 进行回退处理。拒绝路径经过已离开 -D 的符号链接的常规成员。
724edf9bde9d356724ad384a2e196edc3c9f80f7)src/fe_utils/astreamer_file.c · src/fe_utils/astreamer_tar.csrc/bin/pg_rewind/file_ops.cGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。不提供任何担保。