PostgreSQL 18.6 - Élevé - À distance - Écriture de fichier - pg_basebackup suit un lien symbolique tar absolu, résidu de CVE-2026-6475
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · postgres-basebackup-symlink
Classe : Écriture de fichier Portée : Distante
PostgreSQL 18.6 (724edf9) - PostgreSQL Global Development Group
CVE-2026-6475 a ajouté path_is_safe_for_extraction pour les noms de membres tar. Les cibles de liens symboliques absolues échappent toujours à cette vérification afin que les tablespaces fonctionnent. astreamer_file.c fait ensuite un symlink() de la cible, puis un fopen(..., "wb") la suit. Le format par défaut de pg_basebackup est plain (-F p). pg_rewind create_target_symlink vérifie le chemin et ne crée jamais le lien.
Une source hostile qui parle BASE_BACKUP peut planter un lien symbolique absolu et écraser n'importe quel fichier que l'UID de sauvegarde peut écrire. Même modèle de victime que 6475. Il ne s'agit pas d'un nouveau signalement des vérifications de noms de membres.
| ID | pas encore de CVE |
| Classe | Écriture de fichier (reste de lien symbolique tar absolu de CVE-2026-6475) |
| Portée | Distante (UI:R client contre PostgreSQL hostile) |
| CWE | CWE-59, CWE-22 |
| CVSS | Élevé : 8.8 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| Produit | PostgreSQL |
| Affecté | tag 18.6 REL_18_6 (724edf9bde9d356724ad384a2e196edc3c9f80f7), pg_basebackup / pg_rewind in-tree |
| Auth | la victime exécute pg_basebackup -D <dir> par défaut contre une source attaquante |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Quelqu'un capable d'amener un opérateur à exécuter pg_basebackup -D contre son PostgreSQL (le même modèle UI:R que CVE-2026-6475) peut écrire en dehors de -D.
| Privilège | Méthode / sink | Prouvé en lab ou déduit |
|---|---|---|
Intégrité : écrire un fichier en dehors de -D | Tar BASE_BACKUP hostile : membre typeflag '2' avec un nom relatif sûr (pg_tblspc/16384) et une cible de lien absolue, puis un membre régulier sous ce nom. extract_link puis create_file_for_extract fopen(..., "wb") sans O_NOFOLLOW | Prouvé en lab. A écrit POSTGRES-BASEBACKUP-SYMLINK-WITNESS dans /work/oracle/. Dest contient le lien symbolique. Le tar de contrôle (sans lien symbolique) a laissé l'oracle vide et n'a écrit PG_VERSION qu'à l'intérieur de -D |
Intégrité : écraser un rc de shell, authorized_keys, une unité utilisateur systemd ou un crontab | Même sink, tout chemin que l'UID client peut écrire | Déduit. Ce lab ne touche pas à ces fichiers |
| Disponibilité : détruire la config ou les clés du client | Même écriture | Déduit. Non démontré |
| Reconnaissance du disque client | l'extraction est une écriture, pas une lecture | Fermé |
Remonter .. ou des noms de membres absolus | path_is_safe_for_extraction | Fermé. C'est CVE-2026-6475 |
| SQL non privilégié côté serveur / protocole non authentifié | serveur 18.6 par défaut | Fermé. Ce reste concerne le client |
| Sauvegarde tar uniquement | pg_basebackup -F t stocke le tar sans l'extraire | Fermé |
RCE dans postgres | pas ce sink | Fermé |
pg_rewind a le même reste create_target_symlink / open(). Ce lab ne pilote que pg_basebackup.
J'ai épinglé postgres/postgres REL_18_6 après la vague 18.6 (28 CVE, plus l'ensemble 18.4/18.2 déjà présent sur cet arbre). Vingt-deux chasses. Serveur par défaut, SQL non privilégié, protocole non authentifié : rien à ce niveau. CVE-2026-6475 était le frère à relire.
Les noms de membres sont vérifiés. Les cibles de liens symboliques absolues ne le sont pas :
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 est toujours fopen(filename, "wb"). Le commentaire à astreamer_file.c:351-356 indique que le mapping est appliqué sans vérifier que le lien est à l'intérieur de pg_tblspc.
Fausses pistes déjà consignées : considérer 6475 comme fermé et passer à autre chose ; pointer -D vers un répertoire de données actif ; écraser un rc de shell pour le spectacle. Un serveur 18.6 honnête n'émet que des liens symboliques pg_tblspc/<oid> et place le contenu des tablespaces dans une archive séparée. Une source malveillante qui parle BASE_BACKUP peut placer le membre régulier de suivi dans le même tar. C'est cela, le reste.
python3 postgres-basebackup-symlink-Abraxas-Labs.py
ou
cd lab
./run.sh
postgres:18.6 comme image source, exécutant un speaker BASE_BACKUP. Le client est le pg_basebackup in-tree du même tag (pg_basebackup (PostgreSQL) 18.6). Loopback 127.0.0.1:19370. Projet Compose postgres-basebackup-symlink. Ne pointez pas -D vers un répertoire de données actif.
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
Traiter les cibles de liens symboliques absolues comme non sûres, sauf si elles sont réécrites par --tablespace-mapping. Ouvrir les fichiers extraits avec O_NOFOLLOW / lstat afin qu'un lien planté ne puisse pas être suivi. Appliquer path_is_safe_for_extraction à la réécriture de link ainsi qu'à path. Rejeter un membre régulier dont le chemin traverse un lien symbolique sorti de -D.
724edf9bde9d356724ad384a2e196edc3c9f80f7)src/fe_utils/astreamer_file.c · src/fe_utils/astreamer_tar.csrc/bin/pg_rewind/file_ops.cGNU Affero GPL v3.0. Voir LICENSE. Lab en loopback uniquement. Aucune garantie.