PostgreSQL 18.6 - Alta - Remota - Escritura de archivos - pg_basebackup sigue un enlace simbólico tar absoluto remanente de CVE-2026-6475
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · postgres-basebackup-symlink
Clase: Escritura de archivos Alcance: Remoto
PostgreSQL 18.6 (724edf9) - PostgreSQL Global Development Group
CVE-2026-6475 añadió path_is_safe_for_extraction para los nombres de miembros de tar. Los destinos de symlink absolutos todavía omiten esa comprobación para que los tablespaces funcionen. astreamer_file.c luego hace symlink() del destino y después fopen(..., "wb") lo sigue. El formato predeterminado de pg_basebackup es plain (-F p). pg_rewind create_target_symlink comprueba la ruta y nunca enlaza.
Una fuente hostil que habla BASE_BACKUP puede plantar un symlink absoluto y sobrescribir cualquier archivo que el UID del backup pueda escribir. Mismo modelo de víctima que 6475. Esto no es un re-reporte de las comprobaciones de nombres de miembros.
| ID | sin CVE todavía |
| Clase | Escritura de archivos (residuo de symlink absoluto de tar de CVE-2026-6475) |
| Alcance | Remoto (UI:R cliente vs PostgreSQL hostil) |
| CWE | CWE-59, CWE-22 |
| CVSS | Alto: 8.8 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| Producto | PostgreSQL |
| Afectado | 18.6 tag REL_18_6 (724edf9bde9d356724ad384a2e196edc3c9f80f7), pg_basebackup / pg_rewind en el árbol |
| Auth | la víctima ejecuta pg_basebackup -D <dir> por defecto contra una fuente atacante |
| Licencia | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Alguien que pueda conseguir que un operador ejecute pg_basebackup -D contra su PostgreSQL (el mismo modelo UI:R que CVE-2026-6475) puede escribir fuera de -D.
| Privilegio | Método / sink | Probado en lab o inferido |
|---|---|---|
Integridad: escribir un archivo fuera de -D | Tar BASE_BACKUP hostil: miembro con typeflag '2' con un nombre relativo seguro (pg_tblspc/16384) y un destino de enlace absoluto, luego un miembro regular bajo ese nombre. extract_link y después create_file_for_extract fopen(..., "wb") sin O_NOFOLLOW | Probado en lab. Escribió POSTGRES-BASEBACKUP-SYMLINK-WITNESS en /work/oracle/. El destino contiene el symlink. El tar de control (sin symlink) dejó el oracle vacío y escribió PG_VERSION solo dentro de -D |
Integridad: sobrescribir shell rc, authorized_keys, una unidad de usuario systemd o crontab | Mismo sink, cualquier ruta que el UID del cliente pueda escribir | Inferido. Este lab no toca esos archivos |
| Disponibilidad: destrozar la configuración o las claves del cliente | Misma escritura | Inferido. No demostrado |
| Reconocimiento del disco del cliente | extract es escritura, no lectura | Cerrado |
Recorrer .. o nombres de miembros absolutos | path_is_safe_for_extraction | Cerrado. Eso es CVE-2026-6475 |
| SQL sin privilegios en el servidor / protocolo sin autenticación | servidor por defecto 18.6 | Cerrado. Este residuo es el cliente |
| Backup solo tar | pg_basebackup -F t almacena el tar sin extraer | Cerrado |
RCE dentro de postgres | no este sink | Cerrado |
pg_rewind tiene el mismo residuo de create_target_symlink / open(). Este lab solo ejecuta pg_basebackup.
Fijé postgres/postgres REL_18_6 después de la oleada de 18.6 (28 CVE, más el conjunto 18.4/18.2 ya presente en este árbol). Veintidós búsquedas. Servidor por defecto, SQL sin privilegios, protocolo sin autenticación: ninguno a este nivel. CVE-2026-6475 era el hermano que había que releer.
Los nombres de miembros se comprueban. Los destinos de symlink absolutos no:
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 sigue siendo fopen(filename, "wb"). El comentario en astreamer_file.c:351-356 dice que el mapeo se aplica sin comprobar que el enlace esté dentro de pg_tblspc.
Caminos equivocados ya registrados: tratar 6475 como cerrado y marcharse; apuntar -D a un directorio de datos en uso; sobrescribir shell rc para el espectáculo. Un servidor 18.6 honesto solo emite symlinks pg_tblspc/<oid> y coloca el contenido del tablespace en un archivo separado. Una fuente maliciosa que habla BASE_BACKUP puede colocar el miembro regular de seguimiento en el mismo tar. Ese es el residuo.
python3 postgres-basebackup-symlink-Abraxas-Labs.py
o
cd lab
./run.sh
postgres:18.6 como imagen de origen, ejecutando un hablante de BASE_BACKUP. El cliente es pg_basebackup en el árbol de la misma etiqueta (pg_basebackup (PostgreSQL) 18.6). Loopback 127.0.0.1:19370. Proyecto de compose postgres-basebackup-symlink. No apuntes -D a un directorio de datos en uso.
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
Tratar los destinos de symlink absolutos como inseguros a menos que sean reescritos por --tablespace-mapping. Abrir los archivos de extracción con O_NOFOLLOW / lstat para que un enlace plantado no pueda ser seguido. Aplicar path_is_safe_for_extraction a rewind link así como a path. Rechazar un miembro regular cuya ruta atraviese un symlink que salió 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. Ver LICENSE. Solo lab en loopback. Sin garantía.