
Preuve de concept pour CVE-2026-6471, démontrant une élévation de privilèges dans PostgreSQL via le décodage logique dlopen afin d'obtenir une exécution de code arbitraire et une porte dérobée superutilisateur.
Le décodage logique de PostgreSQL permet à un rôle non superutilisateur disposant du
privilège REPLICATION de créer un slot de réplication logique et de choisir le
plugin de sortie. Sur les versions concernées, aucun contrôle d'autorisation n'est
effectué sur ce choix, le serveur exécute donc dlopen() sur ce vers quoi pointe le
nom du plugin. Nommer un chemin de bibliothèque exécute le code de cette
bibliothèque dans le backend postgres, sous le compte du système d'exploitation qui
exécute le serveur. Cela constitue une exécution de code arbitraire en tant
qu'utilisateur OS du serveur de base de données, ce qui, pour une base de données
contenant les données applicatives, équivaut en pratique à une prise de contrôle du
serveur.
Corrigé dans PostgreSQL 18.6, 17.11, 16.15, 15.19 et 14.24 par la
liste blanche output_plugin_libraries (par défaut pgoutput, test_decoding).
Tout élément ne figurant pas sur cette liste génère désormais une erreur
library "X" may not be used as an output plugin avant tout dlopen.
Exécutez les mêmes étapes contre les deux builds et seule la version de PostgreSQL change. Un compte à faibles privilèges (LOGIN + REPLICATION, non superutilisateur, sans accès OS) fait ce qu'un abonné normal au décodage logique fait, puis demande au serveur de charger une bibliothèque arbitraire comme plugin de sortie. Sur le build vulnérable, cette bibliothèque s'exécute en tant qu'utilisateur OS postgres et installe un rôle backdoor superutilisateur persistant, de sorte qu'un compte uniquement dédié à la réplication termine l'exécution avec un accès superutilisateur fonctionnel.
cve-2026-6471-postgres-logical-decoding-dlopen.txt est une solution
Exploitmatic (.txt) : données plus assertions, sans code. Le runtime la rejoue
contre la machine. La solution fournit pwn.so au moment de l'exécution (base64
dans le fichier), pilote le SQL en tant que rôle de réplication à faibles
privilèges, puis se connecte en tant que rôle backdoor superutilisateur installé
par la charge utile.pwn.c est la source de la bibliothèque de charge utile et pwn.so son build :
un unique constructeur ELF qui s'exécute en tant qu'utilisateur OS postgres, se
connecte via le socket local en tant que superutilisateur de la base de données
(peer/trust), et crée le rôle persistant
cve6471_backdoor LOGIN SUPERUSER PASSWORD 'BackdoorPass1'. Il ne s'exécute que
si le serveur charge réellement la bibliothèque, c'est-à-dire uniquement sur un
build vulnérable. Compilez avec gcc -Os -shared -fPIC -o pwn.so pwn.c sur une
libc Linux correspondant à l'image du serveur.Prérequis : vous avez accès à docker.
Le dossier lab/ contient la réplique exacte utilisée pour vérifier ce PoC.
Construisez et exécutez les deux machines (vulnérable = postgres 16.14, corrigé =
postgres 16.15) :
docker build -t pg-6471-vuln -f lab/Dockerfile.vuln lab
docker build -t pg-6471-fixed -f lab/Dockerfile.fixed lab
docker run -d --name pg-6471-vuln -p 15432:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-vuln
docker run -d --name pg-6471-fixed -p 15433:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-fixed
Les deux machines exécutent l'image postgres officielle standard avec
wal_level=logical. Le script d'initialisation lab/01-repro.sh crée le rôle à
faibles privilèges utilisé par la solution, repro_rep LOGIN REPLICATION PASSWORD 'repropass', qui n'est pas superutilisateur.
Rejouez ensuite la solution :
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1
Visez la machine corrigée avec une surcharge de variable, sans modification de fichier :
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1 \
--var ctr=pg-6471-fixed
ctr est le conteneur docker, pw est le mot de passe du rôle de réplication.
| cible | résultat |
|---|---|
| postgres 16.14 (vulnérable), wal_level=logical | 4/4 vérifié, la connexion backdoor superutilisateur fonctionne |
| postgres 16.15 (corrigé), wal_level=logical | 3/4 non vérifié, aucun backdoor |
Pour les tests autorisés et la recherche uniquement, sur des systèmes que vous possédez ou pour lesquels vous avez la permission de tester. Ce PoC démontre une élévation de privilèges post-authentification : il nécessite un compte de base de données existant à faibles privilèges avec l'attribut REPLICATION, ainsi qu'un moyen de placer du code contrôlé par l'attaquant là où l'utilisateur OS postgres peut le charger. Il ne s'agit pas d'une attaque distante non authentifiée. Le code chargé atteint le superutilisateur de la base de données car le compte OS qui possède le serveur peut se connecter via le socket local en tant que superutilisateur (peer/trust), ce qui est une pratique de déploiement PostgreSQL standard.
| étape | vulnérable 16.14 | corrigé 16.15 |
|---|
| reconnaissance (le rôle est réplication, non superutilisateur) | réussit | réussit |
| référence (slot logique avec pgoutput intégré) | réussit | réussit |
| déclenchement (plugin du slot = chemin de la bibliothèque attaquante) | le serveur la charge | rejeté avant chargement |
| prise de contrôle (connexion en tant que backdoor superutilisateur installé) | superutilisateur | aucun rôle de ce type |