PostgreSQL 18.6 — высокий уровень — удалённо — запись файлов — pg_basebackup следует по абсолютной tar-символической ссылке, остаток от CVE-2026-6475
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · postgres-basebackup-symlink
Класс: запись файлов Достижимость: удалённая
PostgreSQL 18.6 (724edf9) — PostgreSQL Global Development Group
CVE-2026-6475 добавил path_is_safe_for_extraction для имён членов tar. Абсолютные цели симлинков по-прежнему пропускают эту проверку, чтобы работали табличные пространства. Затем astreamer_file.c вызывает symlink() для цели, а позже fopen(..., "wb") следует по ней. Формат pg_basebackup по умолчанию — plain (-F p). pg_rewind create_target_symlink проверяет путь и никогда не создаёт ссылку.
Враждебный источник, говорящий на BASE_BACKUP, может подложить абсолютный симлинк и перезаписать любой файл, доступный на запись UID резервного копирования. Та же модель жертвы, что и в 6475. Это не повторная заявка по проверкам имён членов.
| ID | CVE пока нет |
| Класс | Запись файлов (остаток абсолютного симлинка tar от CVE-2026-6475) |
| Достижимость | Удалённая (UI:R клиент против враждебного PostgreSQL) |
| CWE | CWE-59, CWE-22 |
| CVSS | High: 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 |
Тот, кто может заставить оператора запустить pg_basebackup -D против своего PostgreSQL (та же модель UI:R, что и в CVE-2026-6475), может писать за пределами -D.
| Привилегия | Метод / точка сброса | Доказано в лаборатории или выведено |
|---|---|---|
Целостность: запись файла за пределами -D | Враждебный tar BASE_BACKUP: член с typeflag '2' с безопасным относительным именем (pg_tblspc/16384) и абсолютной целью ссылки, затем обычный член под этим именем. extract_link, затем create_file_for_extract fopen(..., "wb") без O_NOFOLLOW | Доказано в лаборатории. Записан POSTGRES-BASEBACKUP-SYMLINK-WITNESS в /work/oracle/. Dest содержит симлинк. Контрольный tar (без симлинка) оставил oracle пустым и записал PG_VERSION только внутри -D |
Целостность: перезапись shell rc, authorized_keys, пользовательского юнита systemd или crontab | Та же точка сброса, любой путь, доступный на запись UID клиента | Выведено. Эта лаборатория не трогает эти файлы |
| Доступность: разрушение конфигурации или ключей клиента | Та же запись | Выведено. Не продемонстрировано |
| Разведка диска клиента | extract — это запись, а не чтение | Закрыто |
Обход .. или абсолютные имена членов | path_is_safe_for_extraction | Закрыто. Это CVE-2026-6475 |
| Непривилегированный SQL на стороне сервера / неаутентифицированный протокол | сервер по умолчанию 18.6 | Закрыто. Этот остаток — на стороне клиента |
| Резервное копирование только в tar | pg_basebackup -F t сохраняет tar без извлечения | Закрыто |
RCE внутри postgres | не эта точка сброса | Закрыто |
pg_rewind имеет тот же остаток create_target_symlink / open(). Эта лаборатория задействует только pg_basebackup.
Я зафиксировал postgres/postgres REL_18_6 после волны 18.6 (28 CVE, плюс набор 18.4/18.2, уже присутствующий в этом дереве). Двадцать два поиска. Сервер по умолчанию, непривилегированный 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). Loopback 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, чтобы подложенная ссылка не могла быть пройдена. Применять path_is_safe_for_extraction к rewind link, а также к path. Отклонять обычный член, путь которого проходит через симлинк, вышедший за пределы -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. Только loopback-лаборатория. Без гарантий.