├── pyimp.JPG ├── screen.JPG ├── sleep-09202002582419-x86.dll ├── sleep-09202002582419-amd64.dll ├── README.md ├── http-telerik-vuln.nse └── telerik_rce_scan.py /pyimp.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThanHuuTuan/Telerik_CVE-2019-18935/HEAD/pyimp.JPG -------------------------------------------------------------------------------- /screen.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThanHuuTuan/Telerik_CVE-2019-18935/HEAD/screen.JPG -------------------------------------------------------------------------------- /sleep-09202002582419-x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThanHuuTuan/Telerik_CVE-2019-18935/HEAD/sleep-09202002582419-x86.dll -------------------------------------------------------------------------------- /sleep-09202002582419-amd64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThanHuuTuan/Telerik_CVE-2019-18935/HEAD/sleep-09202002582419-amd64.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TelerikUI Python Scanner 2 | (telerik_rce_scan.py) 3 | 4 | 5 | # Examples 6 | Assess an IP for CVE-2019-18935
7 | $ python3 telerik_rce_scan.py -t 192.168.44.21 8 | 9 | Assess a hostname for CVE-2019-18935
10 | $ python3 telerik_rce_scan.py -t vulnerable.telerik.net 11 | 12 | Assess a CIDR network range for CVE-2019-18935
13 | $ python3 telerik_rce_scan.py -r 23.253.4.0/24 14 | 15 | Assess a list of targerts
16 | $ python3 telerik_rce_scan.py -iL hosts.txt 17 | 18 | ------------------------------------------------------------------------------------------------------ 19 | 20 | # TelerikUI NSE Scanner 21 | (http-telerik-vuln.nse) 22 | 23 | # Installation 24 | Download to your nmap scripts directory (/usr/share/nmap/scripts/) 25 | 26 | # Update the nmap scripts database 27 | $ nmap --script-updatedb 28 | 29 | # Sample execution: 30 | nmap -sT -p443 --script=http-telerik-vuln 23.253.4.115 31 | 32 | # Screen: 33 | 34 | 35 | ## Thanks 36 | 37 | [@mwulftange](https://twitter.com/mwulftange) initially [discovered](https://codewhitesec.blogspot.com/2019/02/telerik-revisited.html) this vulnerability. [@bao7uo](https://github.com/bao7uo) wrote all of the logic for [breaking RadAsyncUpload encryption](https://github.com/bao7uo/RAU_crypto), which enabled manipulating the file upload configuration object in `rauPostData` and subsequently exploiting insecure deserialization of that object. And thanks to Noperator (@BishopFox) from whom I _copped_ this language and the Legal Disclaimer below. 38 | 39 | ## Legal Disclaimer 40 | 41 | 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. 42 | -------------------------------------------------------------------------------- /http-telerik-vuln.nse: -------------------------------------------------------------------------------- 1 | local http = require "http" 2 | local stdnse = require "stdnse" 3 | local string = require "string" 4 | local table = require "table" 5 | local vulns = require "vulns" 6 | local shortport = require "shortport" 7 | 8 | 9 | local catch = function() 10 | client_ident:close() 11 | client_service:close() 12 | end 13 | 14 | description = [[ 15 | The insecure deserialization of JSON objects in Telerik UI for ASP.NET 16 | results in arbitrary remote code execution. An attacker can break the 17 | RadAsyncUpload encryption (or have prior knowledge of your custom 18 | encryption keys) and stage a malicious request. 19 | 20 | Affects: v2011.1.315 - 2017.2.621 without keys 21 | v2011.1.315 - 2020.1.114 with encryption keys 22 | 23 | Big Ups: Markus Wulftange (@mwulftange) && Paul Taylor (@bao7uo) 24 | Ref: https://github.com/noperator/CVE-2019-18935 25 | See: https://github.com/bao7uo/RAU_crypto 26 | See: https://www.telerik.com/support/kb/aspnet-ajax/details/allows-javascriptserializer-deserialization 27 | ]] 28 | 29 | 30 | -- @changelog 31 | -- 2020-05-15 - hacked together by Brent 'becrevex' Chambers - `support free info` 32 | -- 2020-05-18 - added root path DLL check and version output on fail 33 | 34 | author = "Brent 'becrevex' Chambers" 35 | license = "Same as Nmap--See https://nmap.org/book/man-legal.html" 36 | categories = {"safe", "discovery"} 37 | 38 | portrule = shortport.port_or_service (443, "https", "tcp") 39 | 40 | local result = {} 41 | local path = {"/Telerik.Web.UI.WebResource.axd?type=rau"} 42 | local pattern = "20[0-9]{2}(%.[0-9]*)+" 43 | 44 | action = function(host, port) 45 | 46 | local vuln_table = { 47 | title = "CVE-2019-18935 - Telerik UI Javascript Deserialization RCE", 48 | state = vulns.STATE.NOT_VULN, 49 | risk_factor = "High", 50 | references = { 51 | 'https://nvd.nist.gov/vuln/detail/CVE-2019-18935', 52 | }, 53 | IDS = { 54 | CVE = ' CVE-2019-18935', 55 | CWE = ' CWE-913' 56 | }, 57 | scores = { 58 | CVSS2 = '8.5' 59 | }, 60 | description = [[ 61 | Telerik UI for ASP.NET AJAX through 2019.3.1023 contains a 62 | .NET deserialization RCE vulnerability in the RadAsyncUpload function. ]] 63 | 64 | -- (As of 2020.1.114, a default setting prevents the exploit. 65 | -- In 2019.3.1023, but not earlier versions, a non-default 66 | -- setting can prevent exploitation.)]] 67 | 68 | -- This is exploitable 69 | -- when the encryption keys are known due to the presence of CVE-2017-11317 or 70 | -- CVE-2017-11357. Exploitation can result in remote code execution. 71 | } 72 | 73 | local report = vulns.Report:new(SCRIPT_NAME, host, port) 74 | 75 | 76 | stdnse.debug1("Connecting to %s:%s", host.targetname or host.ip, port.number) 77 | local data = http.get(host, port, "/aspnet-ajax/Telerik.Web.UI.WebResource.axd?type=rau") 78 | local data2 = http.get(host, port, "/Telerik.Web.UI.WebResource.axd?type=rau") 79 | local site1 = http.get(host, port, "/") 80 | 81 | if data and data.status then 82 | if string.match(data.body, "RadAsyncUpload handler is registered succesfully") then 83 | stdnse.debug1("Telerik file uploader is available.") 84 | table.insert(result, "\n[!] Possibly vulnerable to CVE-2019-18935 (Telerik UI RCE)") 85 | local response = http.get(host, port, "/aspnet-ajax") 86 | if response.body:match("201[0-9]%.[0-2]%.%d%d%d%.%d%d") then 87 | local version = response['body']:match("201[0-9]%.[0-2]%.%d%d%d%.%d%d") 88 | stdnse.print_debug(1, "%s:..VULNERABLE VERSION FOUND: " .. version, SCRIPT_NAME, response.body) 89 | vuln_table.state = vulns.STATE.VULN 90 | elseif response.body:match("2020%.[0-1]%.%d%d%d%.%d%d") then 91 | local version = response['body']:match("2020%.[0-2]%.%d%d%d%.%d%d") 92 | stdnse.print_debug(1, "%s:..VULERABLE VERSION FOUND (requires encryption key): " .. version, SCRIPT_NAME, response.body) 93 | vuln_table.state = vulns.STATE.VULN 94 | else 95 | local version = response['body']:match("20%d%d%.%d.%d%d%d%.%d%d") 96 | stdnse.debug1("Version discovery: "..version) 97 | stdnse.debug1("Not vulnerable CVE-2019-18935 (TelerikUI RCE)") 98 | end 99 | else 100 | 101 | table.insert(result, "\n[!] Not vulnerable CVE-2019-18935 (TelerikUI RCE)") 102 | end 103 | elseif data2 and data2.status then 104 | if string.match(data2.body, "RadAsyncUpload handler is registered succesfully") then 105 | stdnse.debug1("Telerik file uploader is available.") 106 | table.insert(result, "\n[!] Possibly vulnerable to CVE-2019-18935 (Telerik UI RCE)") 107 | local response = http.get(host, port, "/") 108 | if response.body:match("201[0-9]%.[0-2]%.%d%d%d%.%d%d") then 109 | local version = response['body']:match("201[0-9]%.[0-2]%.%d%d%d%.%d%d") 110 | stdnse.print_debug(1, "%s:..VULNERABLE VERSION FOUND: " .. version, SCRIPT_NAME, response.body) 111 | vuln_table.state = vulns.STATE.VULN 112 | elseif response.body:match("2020%.[0-1]%.%d%d%d%.%d%d") then 113 | local version = response['body']:match("2020%.[0-2]%.%d%d%d%.%d%d") 114 | stdnse.print_debug(1, "%s:..VULERABLE VERSION FOUND (requires encryption key): " .. version, SCRIPT_NAME, response.body) 115 | vuln_table.state = vulns.STATE.VULN 116 | else 117 | local version = response['body']:match("20%d%d%.%d.%d%d%d%.%d%d") 118 | stdnse.debug1("Version discovery: "..version) 119 | stdnse.debug1("Not vulnerable CVE-2019-18935 (TelerikUI RCE)") 120 | end 121 | else 122 | 123 | table.insert(result, "\n[!] Not vulnerable CVE-2019-18935 (TelerikUI RCE)") 124 | end 125 | end 126 | return report:make_output(vuln_table) 127 | end 128 | -------------------------------------------------------------------------------- /telerik_rce_scan.py: -------------------------------------------------------------------------------- 1 | # Programmer: Brent 'becrevex' Chambers 2 | # Date: May 24, 2020 3 | # Filename: telerik_rce_scan.py 4 | # Description: TelerikUI CVE-2019-18935 vulnerability scanner 5 | 6 | import re 7 | import requests 8 | import argparse 9 | import random 10 | import time 11 | import ipaddress 12 | import traceback 13 | import datetime 14 | requests.packages.urllib3.disable_warnings() # disable lame SSL warnings 15 | 16 | help_example = "EXAMPLE: telerik_rce_check -t 104.28.18.139" 17 | parser = argparse.ArgumentParser(description='Telerik RAU RCE Detection'+'\n\n'+ help_example, formatter_class=argparse.RawTextHelpFormatter) 18 | parser.add_argument('-t', '--target') 19 | parser.add_argument('-r', '--range') 20 | parser.add_argument('-iL', '--inputfile', help='Specify a filename for bulk target scanning.') 21 | parser.add_argument('-search', action='store_true', help='Searches IPv4 space for vulnerable hosts. (2 Second delay)') 22 | args = parser.parse_args() 23 | 24 | vuln_checks = ['/Telerik.Web.UI.WebResource.axd?type=rau', 25 | '/aspnet-ajax/Telerik.Web.UI.WebResource.axd?type=rau'] 26 | 27 | def print_vuln_table(): 28 | print(" [!] VULNERABLE") 29 | print(""" 30 | Risk: HIGH CVE: CVE-2019-18935 CWE: CWE-913 31 | --------------------------------------------------------------------- 32 | Telerik UI for ASP.NET AJAX through 2019.3.1023 contains a 33 | .NET deserialization RCE vulnerability in the RadAsyncUpload function. 34 | 35 | -- As of 2020.1.114, a default setting prevents the exploit. 36 | -- In 2019.3.1023, but not earlier versions, a non-default 37 | -- setting can prevent exploitation. 38 | 39 | -- This is exploitable when the encryption keys are known due 40 | -- to the presence of CVE-2017-11317 or CVE-2017-11357. 41 | -- Exploitation can result in remote code execution. 42 | """) 43 | 44 | 45 | def execution_header(): 46 | print("TelerikUI RCE Scan ( github.com/becrevex/Telerik_CVE-2019-18935 ) ") 47 | print(help_example) 48 | stamp = datetime.datetime.now() 49 | print("Starting CVE-2019-18935 (Telerik RCE) scan at " + str(stamp)) 50 | print() 51 | 52 | 53 | def is_valid_ip(ip): 54 | """Checks if IP is valid""" 55 | test = re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",ip) 56 | if test: 57 | return True 58 | else: 59 | return False 60 | 61 | 62 | def is_valid_hostname(hostname): 63 | """Checks if hostname is valid for scanning """ 64 | if hostname[-1] == ".": 65 | # strip exactly one dot from the right, if present 66 | hostname = hostname[:-1] 67 | if len(hostname) > 253: 68 | return False 69 | labels = hostname.split(".") 70 | # the TLD must be not all-numeric 71 | if re.match(r"[0-9]+$", labels[-1]): 72 | return False 73 | allowed = re.compile(r"(?!-)[a-z0-9-]{1,63}(?= 2020 and int(sub) >= 3 and int(sub2) >= 1023): 102 | print("Patched. NOT VULNERABLE") 103 | return False 104 | elif (int(year) <= 2020) and (int(sub) <= 2): 105 | return True 106 | else: 107 | return False 108 | 109 | def check_for_patch(version): 110 | print(version) 111 | year = version.split(".")[0] 112 | sub = version.split(".")[1] 113 | sub2 = version.split(".")[2] 114 | if (int(year) >= 2020 and int(sub) >= 3 and int(sub2) >= 1023): 115 | print(version.split(".")) 116 | return True # found patched version 117 | else: 118 | return False 119 | 120 | def read_from_file(filepath): 121 | with open(filepath) as fd: 122 | targets = fd.read().splitlines() 123 | return targets 124 | 125 | def check_source_for_ver(target): 126 | print("Checking target for vulnerable versions...") 127 | s = '20[0-9]{2}(?:\.[0-9]*)+' 128 | source = requests.get("https://"+target, verify=False) 129 | result = re.search(s, source.text) 130 | results = re.findall(s, source.text) 131 | #print(results) 132 | status = False 133 | #print(len(results)) 134 | print("Identified version matches:") 135 | for i in list(dict.fromkeys(results)): 136 | if (len(i.split(".")) >= 3): 137 | if check_version_vuln(i): 138 | status = True 139 | #elif check_for_patch(i): 140 | # status = False # if it comes back as patched, return to call and label the version not vulnerable 141 | return status 142 | 143 | def check_vuln(target): 144 | status = "" 145 | string_text = "RadAsyncUpload handler is registered succesfully" 146 | print("Checking: " + target) 147 | for uri in vuln_checks: 148 | try: 149 | r = requests.get('https://'+ target + uri, verify=False) 150 | status = r.status_code 151 | if status == 200: 152 | # if r.body contains "RadAsyncUpload handler is registered succesfully" 153 | if string_text in r.text: 154 | print("[!] RAU Module Found [ " + target + uri + " ]!") 155 | if (check_source_for_ver(target)): 156 | print_vuln_table() 157 | return 158 | return 159 | else: 160 | pass 161 | #print("Telerik RAU Module not found on " + target + ":Status " + str(status)) 162 | except Exception as ex: 163 | traceback.print_exc() 164 | 165 | 166 | def check_vuln_bulk(target): 167 | status = "" 168 | string_text = "RadAsyncUpload handler is registered succesfully" 169 | print("Checking: " + target) 170 | for uri in vuln_checks: 171 | try: 172 | r = requests.get('https://'+ target + uri, timeout=0.5, verify=False) 173 | status = r.status_code 174 | if status == 200: 175 | # if r.body contains "RadAsyncUpload handler is registered succesfully" 176 | if string_text in r.text: 177 | print("[!] RAU Module Found [ " + target + uri + " ]!") 178 | if (check_source_for_ver(target)): 179 | print_vuln_table() 180 | return 181 | return 182 | else: 183 | print("Telerik RAU Module not found on " + target + ". Status (" + str(status) + ")") 184 | except Exception as ex: 185 | pass 186 | 187 | 188 | if __name__=='__main__': 189 | if args.inputfile: 190 | execution_header() 191 | targets = read_from_file(args.inputfile) 192 | for host in targets: 193 | check_vuln_bulk(host) 194 | 195 | elif args.search: 196 | execution_header() 197 | search() 198 | 199 | elif args.target: 200 | execution_header() 201 | if is_valid_ip(args.target): 202 | check_vuln(args.target) 203 | 204 | elif is_valid_hostname(args.target): 205 | check_vuln(args.target) 206 | 207 | elif args.range: 208 | execution_header() 209 | range_scan(args.range) 210 | 211 | else: 212 | parser.print_help() 213 | else: 214 | parser.print_help() 215 | 216 | 217 | 218 | --------------------------------------------------------------------------------