February 7, 2019

Telerik Revisited

In 2017, several vulnerabilities were discovered in Telerik UI, a popular UI component library for .NET web applications. Although details and working exploits are public, it often proves to be a good idea to take a closer look at it. Because sometimes it allows you to explore new avenues of exploitation.


Telerik UI for ASP.NET is a popular UI component library for ASP.NET web applications. In 2017, several vulnerabilities were discovered, potentially resulting in remote code execution:

CVE-2017-9248: Cryptographic Weakness
A cryptographic weakness allows the disclosure of the encryption key (Telerik.Web.UI.DialogParametersEncryptionKey and/or the MachineKey) used to protect the DialogParameters via an oracle attack. It can be exploited to forge a functional file manager dialog and upload arbitrary files and/or compromise the ASP.NET ViewState in case of the latter.
CVE-2017-11317: Hard-coded default key
A hard-coded default key is used to encrypt/decrypt the AsyncUploadConfiguration, which holds the path where uploaded files are stored temporarily. It can be exploited to upload files to arbitrary locations.
CVE-2017-11357: Insecure Direct Object Reference
The name of the file stored in the location specified in AsyncUploadConfiguration is taken from the request and thus allows the upload of files with arbitrary extension.

The vulnerabilities were fixed in R2 2017 SP1 (2017.2.621) and R2 2017 SP2 (2017.2.711), respectively. As for CVE-2017-9248, there is an analysis by PatchAdvisor[1] that gives some insights and exploitation hints. And regarding CVE-2017-11317, the detailed writeup by @straight_blast seems to have been published even half a year before Telerik published an updated version. It describes in detail how the vulnerability was discovered and how it can be exploited to upload an arbitrary file to an arbitrary location. If you're unfamiliar with these vulnerabilities, you may want to read the linked advisories first to get a better understanding.

The Catch

Although the vulnerabilities sound promising, they all have their catch: exploiting CVE-2017-9248 requires many thousands of requests, which can be pretty noticeable and suspicious. And unless it is actually possible to leak the MachineKey (which would allow an exploitation via deserialization of arbitrary ObjectStateFormatter stream), a file upload to an arbitrary location (i. e., CVE-2017-11317) is still limited to the knowledge of an appropriate location with sufficient write permissions.

The problem here is that by default the account that the IIS worker process w3wp.exe runs with is a special account like IIS AppPool\DefaultAppPool. And such an account usually does not have write permissions to the web document root directory like C:\inetpub\wwwroot or similar. Additionally, the web document root of the web application can also be somewhere else and may not be known. So simply writing an ASP.NET web shell probably won't work in many cases.

The Dead End

This was exactly the case when we faced Managed Workplace RMM by Avast Business in a red team assessment where we didn't want to make too much noise. Additionally, unauthenticated access to all *.aspx pages except for Login.aspx was denied, i. e., the handler Telerik.Web.UI.DialogHandler.aspx for exploiting CVE-2017-9248 was not reachable, and the other one, Telerik.Web.UI.SpellCheckHandler.axd, was not registered. So, CVE-2017-11317 seemed to be the only option left.

By enumerating known versions of Telerik Web UI, one request to upload to C:\Windows\Temp was finally successful. But an upload to C:\inetpub\wwwroot did not succeed. And since we did not have access to an installation of Managed Workplace, we had no insights into its directory structure. So this seemed to be a dead end.

The New Avenue

While tracing the path of the provided rauPostData through the Telerik code, there was one aspect that became apparent that was never mentioned before by anyone else: The exploitation of CVE-2017-11317 was always advertised as an arbitrary upload. This seems obvious as the handler's name is AsyncUploadHandler and rauPostData contains the upload configuration.

But after taking a closer look at the code that processes the rauPostData, it showed that the rauPostData is expected to consist of two parts separated by a &.

// Telerik.Web.UI.AsyncUpload.SerializationService
internal static object Deserialize(string obj, Type type)
 JavaScriptSerializer serializer = SerializationService.GetSerializer(obj.Length);
 SerializationService.ApplyConverters(type, serializer);
 MethodInfo methodInfo = typeof(JavaScriptSerializer).GetMethod("Deserialize", new Type[]
 }, null).MakeGenericMethod(new Type[]
 return methodInfo.Invoke(serializer, new object[]

The first part is the JSON data (line 9). And the second part is the assembly qualified type name (line 10) that the JSON data should be deserialize to. The call in line 11 then ends up in SerializationService.Deserialize(string, Type).

// Telerik.Web.UI.AsyncUploadHandler
internal IAsyncUploadConfiguration GetConfiguration(string rawData)
 string[] array = rawData.Split(new char[]
 string obj = array[0];
 Type type = Type.GetType(CryptoService.GetService().Decrypt(array[1]));
 IAsyncUploadConfiguration asyncUploadConfiguration = (IAsyncUploadConfiguration)SerializationService.Deserialize(obj, type, true);
 if (!this.IsValidHMac(asyncUploadConfiguration.TargetFolder) || !this.IsValidHMac(asyncUploadConfiguration.TempTargetFolder))
  throw new CryptographicException("The hash is not valid!");
 asyncUploadConfiguration.TargetFolder = AsyncUploadHandler.DecryptFolder(this.GetEncryptedText(asyncUploadConfiguration.TargetFolder));
 asyncUploadConfiguration.TempTargetFolder = AsyncUploadHandler.DecryptFolder(this.GetEncryptedText(asyncUploadConfiguration.TempTargetFolder));
 return asyncUploadConfiguration;

Here a JavaScriptSerializer gets parameterized with the type provided in the rauPostData. That means this is an arbitrary JavaScriptSerializer deserialization!

From the research Friday the 13th JSON Attacks by Alvaro Muñoz & Oleksandr Mirosh it is known that arbitrary JavaScriptSerializer deserialization can be harmful if the expected type can be specified by the attacker. During deserialization, appropriate setter methods get called. A suitable gadget is the System.Configuration.Install.AssemblyInstaller, which allows the loading of a DLL by specifying its path. If the DLL is a mixed mode assembly, its DllMain() entry point gets called on load, which allows the execution of arbitrary code in the context of the w3wp.exe process.

This allowed the remote code execution on Managed Workplace without authentication. The issue has been addressed and should be fixed in Managed Workplace 11 SP4 MR2.


So CVE-2017-11317 can be exploited even without the requirement of being able to write to the web document root:

  1. Upload a mixed mode assembly DLL to a writable location using the regular AsyncUploadConfiguration exploit.
  2. Load the uploaded DLL and thereby trigger its DllMain() function using the AssemblyInstaller exploit described above.

This is an excellent example that revisiting old vulnerabilities can be worthwhile and result in new ways out of a supposed dead end.