
PoC di heap buffer overflow in pgcrypto di PostgreSQL che dimostra la CVE-2026-2005: RCE con privilegi limitati ed escalation dei privilegi a superuser tramite pacchetto OpenPGP appositamente predisposto.
Commit target: 4b324845ba5d24682b9b3708a769f00d160afbd7 (PostgreSQL 18.1 — vulnerabile)
| Campo | Dettaglio |
|---|---|
| CVE | CVE-2026-2005 |
| Tipo | Heap buffer overflow |
| Componente | contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey() |
| Impatto | RCE come utente del sistema operativo che esegue PostgreSQL |
| CVSS | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| Auth richiesta | Bassa — qualsiasi utente autenticato con privilegio CREATE |
| Versioni interessate | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| Corretto in | 14.21, 15.16, 16.12, 17.8, 18.2 (12 febbraio 2026) |
| Architettura | aarch64 (ARM64) — gli offset dell'heap e il layout MBuf sono specifici per architettura/glibc |
# Build e avvio di PostgreSQL 18.1 (vulnerabile)
docker compose up -d --build
# Attendi che sia pronto
docker compose logs -f postgres
# Premi Ctrl+C quando vedi "database system is ready to accept connections"
# Configurazione una tantum: copia il binario postgres per il parsing offline dei simboli
docker cp cve-2026-2005-poc:/usr/local/pgsql/bin/postgres ./postgres
# Installa le dipendenze Node
npm install
# Esegui la catena completa di exploit RCE (solo SQL — nessuna interazione con Docker)
node exploit.js --cmd "id"
# Con output verboso
node exploit.js --cmd "id" --verbose
# Esegui un comando personalizzato
node exploit.js --cmd "whoami"
Fase 1: Leak del puntatore heap
└─ Corrompi l'header del chunk mdst → analizza il messaggio di errore di pfree()
Fase 2: Lettura arbitraria (scansione multi-finestra)
└─ Sovrascrivi mdst->data → scansiona la memoria vicino al puntatore leakato
Fase 3: Raccolta dei candidati puntatore
└─ Scansiona i dump dell'heap per valori a 8 byte simili a puntatori
Fase 4: Risoluzione della base PIE
└─ Vota gli indirizzi leakati contro gli offset dei simboli ELF (raggruppati
per offset di pagina, offline — i simboli vengono analizzati dalla copia
locale del binario)
Fase 5: Validazione PIE
└─ Lettura arbitraria di CurrentUserId alla base candidata → confronto con l'OID della sessione
Fase 6: Scrittura arbitraria
└─ Forgia MBuf msrc + mdst → sovrascrivi CurrentUserId → 10 (superuser)
Fase 7: Esecuzione di comandi
└─ COPY FROM PROGRAM → comando OS arbitrario come utente postgres
CVE-2026-2005/
├── Dockerfile # Compila PostgreSQL 18.1 dal sorgente
├── docker-compose.yml # Servizio PostgreSQL con riavvio automatico
├── init.sh # Entrypoint — initdb + configurazione listen
├── README.md # Questo file
└── poc/
├── package.json # Dipendenze Node.js (pg)
├── exploit.js # Exploit RCE completo in 7 fasi (Node.js)
├── verify.sh # Verifica rapida basata su shell
└── test-pgcrypto.sql # Test solo SQL del caricamento di pgcrypto
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 (opzionale — necessario solo con il flag --gdb)Il bug si trova in pgp_parse_pubenc_sesskey() in contrib/pgcrypto/pgp-pubdec.c.
Durante il parsing di un pacchetto OpenPGP Public-Key Encrypted Session Key (tag 1):
memcpy dei dati della chiave di sessione in un buffer a dimensione fissa basato sulla lunghezza non validataLa memcpy può scrivere oltre il confine del buffer heap, corrompendo i metadati
o i dati adiacenti dell'heap, portando all'esecuzione arbitraria di codice.
pfree() per estrarre l'indirizzo heap di mdst->data./proc/<pid>/maps dal container Docker
per trovare l'indirizzo di caricamento del binario postgres in fase di esecuzione.msrc (sorgente) e mdst (destinazione)
tramite l'overflow dell'heap. msrc punta a un pacchetto symenc incorporato
contenente l'OID del superuser (10); mdst punta a CurrentUserId - 4
(tenendo conto dell'header SET_VARSIZE di 4 byte).CurrentUserId = 10 (superuser di bootstrap),
esegui COPY FROM PROGRAM per eseguire comandi OS arbitrari.pgcrypto è fidata — qualsiasi utente con privilegio CREATE
(non superuser) può installarla, rendendo questo exploit sfruttabile con privilegi bassi.--enable-debug per un debug più semplice con gdb.SRC_CHUNK_OFFSET=100, DST_CHUNK_OFFSET=172) sono specifici
per aarch64 + glibc — altre architetture/allocator richiedono offset diversi.CurrentUserId attraverso la stessa
primitiva di lettura arbitraria.| Flag | Default | Descrizione |
|---|
--cmd | id | Comando OS da eseguire dopo l'exploit riuscito |
--key-size | 3072 | Dimensione della chiave RSA in bit |
--host | 127.0.0.1 | Host PostgreSQL |
--port | 5432 | Porta PostgreSQL |
--user | postgres | Utente del database |
--password | (vuoto) | Password del database |
--dbname | postgres | Nome del database |
--binary | ./postgres | Percorso del binario ELF postgres per i simboli |
--scan-offset | auto | Sovrascrive l'offset di scansione dell'heap dal puntatore leakato |
--verbose | off | Abilita l'output di debug verboso |
--gdb | off | Collega GDB tramite tmux al punto di overflow |