PostgreSQL 18.6 – Hoch – Remote – Dateischreiben – pg_basebackup folgt absolutem tar-Symlink, Überbleibsel von CVE-2026-6475
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · postgres-basebackup-symlink
Write-up: https://abraxaslabs.tech/research/postgres-basebackup-symlink
Klasse: Dateischreiben Reichweite: Remote
PostgreSQL 18.6 (724edf9) - PostgreSQL Global Development Group
CVE-2026-6475 fügte path_is_safe_for_extraction für Tar-Member-Namen hinzu. Absolute Symlink-Ziele umgehen diese Prüfung weiterhin, damit Tablespaces funktionieren. astreamer_file.c ruft dann symlink() auf das Ziel auf, und ein späteres fopen(..., "wb") folgt diesem. Das Standardformat von pg_basebackup ist plain (-F p). pg_rewind create_target_symlink prüft den Pfad und nie den Link.
Eine feindliche Quelle, die BASE_BACKUP spricht, kann einen absoluten Symlink platzieren und jede Datei überschreiben, die die Backup-UID schreiben kann. Dasselbe Opfermodell wie bei 6475. Dies ist keine erneute Meldung der Member-Namen-Prüfungen.
| ID | noch keine CVE |
| Klasse | Dateischreiben (Überbleibsel eines absoluten Tar-Symlinks aus CVE-2026-6475) |
| Reichweite | Remote (UI:R Client vs. feindliches 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 |
| Produkt | PostgreSQL |
| Betroffen | 18.6 Tag REL_18_6 (724edf9bde9d356724ad384a2e196edc3c9f80f7), im Baum enthaltenes pg_basebackup / pg_rewind |
| Auth | Opfer führt standardmäßig pg_basebackup -D <dir> gegen eine Angreiferquelle aus |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Wer einen Operator dazu bringt, pg_basebackup -D gegen sein PostgreSQL auszuführen (dasselbe UI:R-Modell wie bei CVE-2026-6475), kann außerhalb von -D schreiben.
| Privileg | Methode / Sink | Im Lab nachgewiesen oder abgeleitet |
|---|---|---|
Integrität: eine Datei außerhalb von -D schreiben | Feindliches BASE_BACKUP-Tar: Member mit typeflag '2' und einem sicheren relativen Namen (pg_tblspc/16384) sowie einem absoluten Link-Ziel, dann ein reguläres Member unter diesem Namen. extract_link und anschließend create_file_for_extract fopen(..., "wb") ohne O_NOFOLLOW | Im Lab nachgewiesen. Schrieb POSTGRES-BASEBACKUP-SYMLINK-WITNESS nach /work/oracle/. Das Ziel enthält den Symlink. Das Kontroll-Tar (ohne Symlink) ließ das Oracle leer und schrieb PG_VERSION nur innerhalb von -D |
Integrität: Shell-rc, authorized_keys, eine systemd-User-Unit oder crontab überschreiben | Derselbe Sink, jeder Pfad, den die Client-UID schreiben kann | Abgeleitet. Dieses Lab berührt diese Dateien nicht |
| Verfügbarkeit: Client-Konfiguration oder Schlüssel zerstören | Derselbe Schreibvorgang | Abgeleitet. Nicht demonstriert |
| Recon der Client-Festplatte | extract ist Schreiben, nicht Lesen | Geschlossen |
.. oder absolute Member-Namen durchlaufen | path_is_safe_for_extraction | Geschlossen. Das ist CVE-2026-6475 |
| Serverseitiges unprivilegiertes SQL / unauthentifiziertes Protokoll | 18.6 Standard-Server | Geschlossen. Dieses Überbleibsel betrifft den Client |
| Nur-Tar-Backup | pg_basebackup -F t speichert das Tar, ohne es zu entpacken | Geschlossen |
RCE innerhalb von postgres | nicht dieser Sink | Geschlossen |
pg_rewind hat dasselbe Überbleibsel bei create_target_symlink / open(). Dieses Lab treibt nur pg_basebackup an.
Ich habe postgres/postgres auf REL_18_6 festgelegt, nach der 18.6-Welle (28 CVEs, plus der bereits in diesem Baum vorhandenen 18.4/18.2-Satz). Zweiundzwanzig Suchläufe. Standard-Server, unprivilegiertes SQL, unauthentifiziertes Protokoll: nichts auf diesem Niveau. CVE-2026-6475 war der verwandte Fall, den es erneut zu lesen galt.
Member-Namen werden geprüft. Absolute Symlink-Ziele nicht:
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 ist weiterhin fopen(filename, "wb"). Der Kommentar bei astreamer_file.c:351-356 besagt, dass die Zuordnung angewendet wird, ohne zu prüfen, ob der Link innerhalb von pg_tblspc liegt.
Bereits festgehaltene Irrwege: 6475 als geschlossen zu behandeln und weiterzugehen; -D auf ein aktives Datenverzeichnis zu richten; die Shell-rc für Effekthascherei zu überschreiben. Ein ehrlicher 18.6-Server gibt nur pg_tblspc/<oid>-Symlinks aus und legt den Inhalt des Tablespace in einem separaten Archiv ab. Eine bösartige Quelle, die BASE_BACKUP spricht, kann das nachfolgende reguläre Member in dasselbe tar legen. Das ist der Rest.
python3 postgres-basebackup-symlink-Abraxas-Labs.py
oder
cd lab
./run.sh
postgres:18.6 als Quell-Image, das einen BASE_BACKUP-Speaker ausführt. Der Client ist das im Baum enthaltene pg_basebackup aus demselben Tag (pg_basebackup (PostgreSQL) 18.6). Loopback 127.0.0.1:19370. Compose-Projekt postgres-basebackup-symlink. Richten Sie -D nicht auf ein aktives Datenverzeichnis.
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
Behandeln Sie absolute Symlink-Ziele als unsicher, es sei denn, sie werden durch --tablespace-mapping umgeschrieben. Öffnen Sie Extraktionsdateien mit O_NOFOLLOW / lstat, damit einem platzierten Link nicht gefolgt werden kann. Wenden Sie path_is_safe_for_extraction an, um sowohl link als auch path zurückzusetzen. Lehnen Sie ein reguläres Mitglied ab, dessen Pfad durch einen Symlink verläuft, der -D verlassen hat.
724edf9bde9d356724ad384a2e196edc3c9f80f7)src/fe_utils/astreamer_file.c · src/fe_utils/astreamer_tar.csrc/bin/pg_rewind/file_ops.cGNU Affero GPL v3.0. Siehe LICENSE. Nur Loopback-Lab. Keine Gewährleistung.