def dns_zonetransfer(self): print("Testing for zone transfers") zonetransfers = [] resolver = dns.resolver.Resolver() try: answers = resolver.query(self.options["TARGET"], 'NS') except Exception as e: self.handle_exception(e, "Error checking for Zone Transfers") return resolved_ips = [] for ns in answers: ns = str(ns).rstrip('.') resolved_ips.append(socket.gethostbyname(ns)) for ip in resolved_ips: try: zone = dns.zone.from_xfr( dns.query.xfr(ip, self.options["TARGET"])) for name, node in zone.nodes.items(): name = str(name) if name not in ["@", "*"]: zonetransfers.append(name + '.' + self.options["TARGET"]) except: pass if zonetransfers: print("\tZone transfers possible:") for zone in zonetransfers: ColorPrint.red(zone) else: print("\tNo zone transfers possible")
def init(self): if self.options["FILE"]: full_path = os.path.join(os.getcwd(), self.options["FILE"]) with open(full_path) as file: self.options["TARGET"] = list( filter(None, file.read().split('\n'))) else: self.options["TARGET"] = list( filter(None, self.options["TARGET"].split(","))) # Clean up targets for i in range(len(self.options["TARGET"])): url = self.options["TARGET"][i] # Inject protocol if not there if not re.match(r'http(s?):', url): url = 'http://' + url parsed = urlsplit(url) host = parsed.netloc self.options["TARGET"][i] = host try: domain_str = socket.gethostbyname(host) ColorPrint.green( f"Searching for subdomains for {domain_str} ({host})") except Exception as e: self.handle_exception( e, "Error connecting to target! Make sure you spelled it correctly and it is a resolvable address" ) raise e
def search_virustotal(self, target): print("Searching VirusTotal") headers = { 'dnt': '1', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'en-US,en;q=0.9,it;q=0.8', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'authority': 'www.virustotal.com', 'cookie': 'VT_PREFERRED_LANGUAGE=en', } res = requests.get('https://www.virustotal.com/en/domain/' + target + '/information/', headers=headers) if res.status_code == 403: ColorPrint.red( "VirusTotal is currently ratelimiting this IP - go to https://www.virustotal.com/en/domain/" + target + "/information/ and complete the captcha to continue.") return scraped = res.text try: trim_to_subdomain = scraped[scraped.find("observed-subdomains"):scraped .rfind("<script>")].split('\n') for domain in trim_to_subdomain: if domain.strip().endswith("." + target): if domain.strip() not in self.domains and domain.endswith( target): self.domains.append(domain.strip()) if self.options["--verbose"]: print("VirustTotal Found Domain:", domain.strip()) except Exception as e: self.handle_exception(e, "Error parsing virustotal") pass
def search_shodan(self): print("Scanning Shodan.io") try: from anubis.API import SHODAN_KEY except ImportError: ColorPrint.red( "Unable to import API keys - make sure API.py exists!") return if not SHODAN_KEY: print( "To run with additional information, you must set http://shodan.io's API key. You can either set it manually here, or set it within anubis/API.py\nKey: ", end='') key = input() api = shodan.Shodan(key) else: api = shodan.Shodan(SHODAN_KEY) if self.ip != "": try: results = api.host(self.ip) if self.options["--verbose"]: print(dumps(results, indent=2, sort_keys=True)) print('Server Location:', results['city'] + ", " + results['country_code'], '-', results['postal_code']) print("ISP: %s" % results['isp']) if results['os'] is not None: print("Possible OS: %s" % results['os']) except Exception as e: self.handle_exception(e, "Error retrieving additional info")
def search_shodan(self): print("Searching Shodan.io for additional information") try: from anubis.API import SHODAN_KEY except ImportError: ColorPrint.red("Unable to import API keys - make sure API.py exists!") return api = shodan.Shodan(SHODAN_KEY) for i in range(len(self.options["TARGET"])): try: results = api.host(socket.gethostbyname(self.options["TARGET"][i])) if self.options["--verbose"]: print(dumps(results, indent=2, sort_keys=True)) print('Server Location: ' + str(results['city']) + ", " + str(results['country_code']) + ' - ' + str(results['postal_code'])) print("ISP or Hosting Company: %s" % str(results['isp'])) if results['os'] is not None: print("Possible OS: %s" % str(results['os'])) except Exception as e: self.handle_exception(e, "Error retrieving additional info")
def search_virustotal(self, target): print("Searching VirusTotal") headers = { 'dnt': '1', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'en-US,en;q=0.9,it;q=0.8', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'authority': 'www.virustotal.com', 'cookie': 'VT_PREFERRED_LANGUAGE=en', } res = requests.get('https://www.virustotal.com/ui/domains/' + target + '/subdomains?relationships=resolutions', headers=headers) # VirusTotal rate limits aggressively to prevent botting - the user must # manually visit a URL and complete a captcha to continue if res.status_code == 403: ColorPrint.red( "VirusTotal is currently ratelimiting this IP - go to https://www.virustotal.com/en/domain/" + target + "/information/ and complete the captcha to continue.") return try: data = res.json() for entry in data['data']: domain = entry['id'] if domain.strip() not in self.domains and domain.endswith(target): self.domains.append(domain.strip()) if self.options["--verbose"]: print("VirustTotal Found Domain:", domain.strip()) except Exception as e: self.handle_exception(e, "Error parsing virustotal") pass
def init(self): self.options["TARGET"] = self.options["TARGET"].split(",") for i in range(len(self.options["TARGET"])): url = self.options["TARGET"][i] if not re.match(r'http(s?):', url): url = 'http://' + url parsed = urlsplit(url) host = parsed.netloc if host.startswith('www.'): host = host[4:] self.options["TARGET"][i] = host try: ColorPrint.green( "Searching for subdomains for " + socket.gethostbyname(self.options["TARGET"][i]) + " (" + self.options["TARGET"][i] + ")") except Exception as e: self.handle_exception( e, "Error connecting to target! Make sure you spelled it correctly and it is a resolvable address" ) raise e print("")
def send_to_anubisdb(self, target): print("Sending to AnubisDB") data = {'subdomains': dumps(self.domains)} res = requests.post("https://jonlu.ca/anubis/subdomains/" + target, data=data) if res.status_code != 200: ColorPrint.red("Error sending results to AnubisDB - Status Code: " + str(res.status_code))
def test_color_print(self): ColorPrint.red("red") self.assertIn("91m", sys.stdout.getvalue()) ColorPrint.green("green") self.assertIn("92m", sys.stdout.getvalue()) ColorPrint.light_purple("light_purple") self.assertIn("94m", sys.stdout.getvalue()) ColorPrint.purple("purple") self.assertIn("95m", sys.stdout.getvalue()) ColorPrint.yellow("yellow") self.assertIn("93m", sys.stdout.getvalue())
def send_to_anubisdb(self, target): if len(target) == 1: print("Sending to AnubisDB") data = {'subdomains': dumps(self.domains)} # Sends found subdomains to Anubis (max 10,000/post) res = requests.post("https://jonlu.ca/anubis/subdomains/" + target[0], data=data) if res.status_code != 200: ColorPrint.red("Error sending results to AnubisDB - Status Code: " + str( res.status_code)) else: print("Cannot send multiple domains to AnubisDB")
def resolve_ips(self): unique_ips = set() for domain in self.dedupe: try: resolved_ip = socket.gethostbyname(domain) # TODO - Align domains and ips in stdout ColorPrint.green(domain + ": " + resolved_ip) unique_ips.add(resolved_ip) except Exception as e: self.handle_exception(e) print("Found %s unique IPs" % len(unique_ips)) for ip in unique_ips: ColorPrint.green(ip)
def search_censys(self, target): print("Searching Censys") try: from anubis.API import CENSYS_ID, CENSYS_SECRET except ImportError: ColorPrint.red( "To run a Censys scan, you must add your API keys to anubis/API.py") return if not CENSYS_SECRET or not CENSYS_ID: ColorPrint.red( "To run a Censys scan, you must add your API keys to anubis/API.py") return c = censys.certificates.CensysCertificates(CENSYS_ID, CENSYS_SECRET) for cert in c.search("." + target): print(cert)
def dnssecc_subdomain_enum(self, target): if os.getuid() == 0: print("Starting DNSSEC Enum") nm = nmap.PortScanner() arguments = '-sSU -p 53 --script dns-nsec-enum --script-args dns-nsec-enum.domains=' + target nm.scan(hosts=self.ip, arguments=arguments) for host in nm.all_hosts(): try: print(nm[host]['udp'][53]['script']['dns-nsec-enum']) except: pass else: ColorPrint.red( "To run a DNSSEC subdomain enumeration, Anubis must be run as root" )
def resolve_ips(self): unique_ips = set() for domain in self.dedupe: try: # Attempt to get IP resolved_ip = socket.gethostbyname(domain) except Exception as e: self.handle_exception(e) # If getting IP fails, fallback to empty string resolved_ip = "" # TODO - Align domains and ips in stdout ColorPrint.green(domain + ": " + resolved_ip) unique_ips.add(resolved_ip) print("Found %s unique IPs" % len(unique_ips)) for ip in unique_ips: # String truthiness ignores empty strings if ip: ColorPrint.green(ip)
def resolve_ips(self): unique_ips = set() for domain in self.dedupe: try: # Attempt to get IP resolved_ip = socket.gethostbyname(domain) except Exception as e: self.handle_exception(e) # If getting IP fails, fallback to empty string resolved_ip = "" # TODO - Align domains and ips in stdout ColorPrint.green(domain + ": " + resolved_ip) if self.options['--silent']: sys.stdout.write(domain + '\n', override=True) if resolved_ip: unique_ips.add(resolved_ip) print("Found %s unique IPs" % len(unique_ips)) for ip in unique_ips: # Ignore empty strings, final sanity check if ip: ColorPrint.green(ip)
def run(self): # Retrieve IP of target and run initial configurations self.init() # If multiple targets, create scans for each for i in range(len(self.options["TARGET"])): # Default scans that run every time target = self.options["TARGET"][i] ColorPrint.green(f"Working on target: {target}") threads = [ threading.Thread(target=dns_zonetransfer, args=(self, target)), threading.Thread(target=subdomain_hackertarget, args=(self, target)), threading.Thread(target=search_subject_alt_name, args=(self, target)), threading.Thread(target=search_netcraft, args=(self, target)), threading.Thread(target=search_crtsh, args=(self, target)), threading.Thread(target=search_dnsdumpster, args=(self, target)), threading.Thread(target=search_anubisdb, args=(self, target)) ] # Additional options - shodan.io scan if self.options["--additional-info"]: threads.append( threading.Thread(target=search_shodan, args=(self, ))) # Additional options - nmap scan of dnssec script and a host/port scan if self.options["--with-nmap"]: threads.append( threading.Thread(target=dnssecc_subdomain_enum, args=(self, target))) threads.append( threading.Thread(target=scan_host, args=(self, ))) # Start all threads and wait for them to finish for x in threads: x.start() for x in threads: x.join() # Run a recursive search on each subdomain - rarely useful, but nice to have # just in case if self.options["--recursive"]: recursive_search(self) # remove duplicates and clean up self.domains = self.clean_domains(self.domains) self.dedupe = set(self.domains) print("Found", len(self.dedupe), "subdomains") print("----------------") if self.options["--ip"]: self.resolve_ips() else: for domain in self.dedupe: cleaned_domain = domain.strip() ColorPrint.green(cleaned_domain) if self.options['--silent']: sys.stdout.write(cleaned_domain, override=True) if self.options["--send-to-anubis-db"]: send_to_anubisdb(self, [target]) # reset per domain self.domains = list()
def run(self): # Retrieve IP of target and run initial configurations self.init() ColorPrint.green("Searching for subdomains for " + self.ip + " (" + self.options["TARGET"] + ")\n") # Multithreaded scans threads = [ Thread(target=self.scan_subject_alt_name()), Thread(target=self.dns_zonetransfer()), Thread(target=self.subdomain_hackertarget()), Thread(target=self.search_virustotal()), Thread(target=self.search_pkey()), Thread(target=self.search_netcraft()), Thread(target=self.search_dnsdumpster()) ] # Default scans that run every time # If they want to send and receive results from Anubis DB if not self.options["--no-anubis-db"]: threads.append(Thread(target=self.scan_anubisdb())) # Additional options - ssl cert scan if self.options["--ssl"]: threads.append(Thread(target=self.ssl_scan())) # Additional options - shodan.io scan if self.options["--additional-info"]: threads.append(Thread(target=self.search_shodan())) # Additional options - nmap scan of dnssec script and a host/port scan if self.options["--with-nmap"]: threads.append(Thread(target=self.dnssecc_subdomain_enum())) threads.append(Thread(target=self.scan_host())) # Additional options - brute force common subdomains if self.options["--brute-force"]: threads.append(Thread(target=self.brute_force())) # Not sure what data we can get from censys yet, but might be useful in the future # self.search_censys() # Start all threads for x in threads: x.start() # Wait for all of them to finish for x in threads: x.join() # remove duplicates and clean up self.domains = self.clean_domains() self.dedupe = set(self.domains) print("Found", len(self.dedupe), "domains") print("----------------") if self.options["--ip"]: self.resolve_ips() else: for domain in self.dedupe: ColorPrint.green(domain.strip()) if not self.options["--no-anubis-db"]: self.send_to_anubisdb()
def handle_exception(self, e, message=""): if self.options["--verbose"]: print(e) if message: ColorPrint.red(message)
def run(self): # Retrieve IP of target and run initial configurations self.init() # If multiple targets, create scans for each for i in range(len(self.options["TARGET"])): # Default scans that run every time target = self.options["TARGET"][i] threads = [ threading.Thread(target=dns_zonetransfer, args=(self, target)), threading.Thread(target=subdomain_hackertarget, args=(self, target)), threading.Thread(target=search_subject_alt_name, args=(self, target)), threading.Thread(target=search_virustotal, args=(self, target)), # threading.Thread(target=search_pkey, args=(self, target)), # Removed pkey as of June 18 2018 due to issues on their end (not connecting) threading.Thread(target=search_netcraft, args=(self, target)), threading.Thread(target=search_crtsh, args=(self, target)), threading.Thread(target=search_dnsdumpster, args=(self, target)), threading.Thread(target=search_anubisdb, args=(self, target)) ] # Additional options - shodan.io scan if self.options["--additional-info"]: threads.append( threading.Thread(target=search_shodan, args=(self, ))) # Additional options - ssl if self.options["--ssl"]: threads.append( threading.Thread(target=ssl_scan, args=(self, target))) # Additional options - nmap scan of dnssec script and a host/port scan if self.options["--with-nmap"]: threads.append( threading.Thread(target=dnssecc_subdomain_enum, args=(self, target))) threads.append( threading.Thread(target=scan_host, args=(self, ))) # Start all threads and wait for them to finish for x in threads: x.start() for x in threads: x.join() # Run a recursive search on each subdomain - rarely useful, but nice to have # just in case if self.options["--recursive"]: recursive_search(self) # remove duplicates and clean up self.domains = self.clean_domains(self.domains) self.dedupe = set(self.domains) print("Found", len(self.dedupe), "subdomains") print("----------------") if self.options["--ip"]: self.resolve_ips() else: for domain in self.dedupe: ColorPrint.green(domain.strip()) if self.options["--send-to-anubis-db"]: send_to_anubisdb(self, self.options["TARGET"])
def run(self): # Retrieve IP of target and run initial configurations self.init() for i in range(len(self.options["TARGET"])): # Default scans that run every time target = self.options["TARGET"][i] threads = [ threading.Thread(target=dns_zonetransfer, args=(self, target)), threading.Thread(target=search_subject_alt_name, args=(self, target)), threading.Thread(target=subdomain_hackertarget, args=(self, target)), threading.Thread(target=search_virustotal, args=(self, target)), threading.Thread(target=search_pkey, args=(self, target)), threading.Thread(target=search_netcraft, args=(self, target)), threading.Thread(target=search_crtsh, args=(self, target)), threading.Thread(target=search_dnsdumpster, args=(self, target)), threading.Thread(target=search_anubisdb, args=(self, target)) ] print('test') # Additional options - ssl cert scan if self.options["--ssl"]: threads.append( threading.Thread(target=ssl_scan, args=(self, target))) # Additional options - shodan.io scan if self.options["--additional-info"]: threads.append( threading.Thread(target=search_shodan, args=(self, ))) # Additional options - nmap scan of dnssec script and a host/port scan if self.options["--with-nmap"]: threads.append( threading.Thread(target=dnssecc_subdomain_enum, args=(self, target))) threads.append( threading.Thread(target=scan_host, args=(self, ))) # Additional options - brute force common subdomains if self.options["--brute-force"]: threads.append( threading.Thread(target=brute_force, args=(self, target))) # Start all threads for x in threads: x.start() # Wait for all of them to finish for x in threads: x.join() # remove duplicates and clean up if self.options["--recursive"]: recursive_search(self) self.domains = self.clean_domains(self.domains) self.dedupe = set(self.domains) print("Found", len(self.dedupe), "subdomains") print("----------------") if self.options["--ip"]: self.resolve_ips() else: for domain in self.dedupe: ColorPrint.green(domain.strip()) if self.options["--send-to-anubis-db"]: send_to_anubisdb(self, self.options["TARGET"])
def run(self): # Retrieve IP of target and run initial configurations self.init() ColorPrint.green("Searching for subdomains for " + self.ip + " (" + self.options["TARGET"] + ")\n") # Default scans that run every time threads = [ Thread(target=dns_zonetransfer(self, self.options["TARGET"])), Thread( target=search_subject_alt_name(self, self.options["TARGET"])), Thread( target=subdomain_hackertarget(self, self.options["TARGET"])), Thread(target=search_virustotal(self, self.options["TARGET"])), Thread(target=search_pkey(self, self.options["TARGET"])), Thread(target=search_netcraft(self, self.options["TARGET"])), Thread(target=search_crtsh(self, self.options["TARGET"])), Thread(target=search_dnsdumpster(self, self.options["TARGET"])), Thread(target=search_anubisdb(self, self.options["TARGET"])) ] # Additional options - ssl cert scan if self.options["--ssl"]: threads.append( Thread(target=ssl_scan(self, self.options["TARGET"]))) # Additional options - shodan.io scan if self.options["--additional-info"]: threads.append(Thread(target=search_shodan(self))) # Additional options - nmap scan of dnssec script and a host/port scan if self.options["--with-nmap"]: threads.append( Thread(target=dnssecc_subdomain_enum(self, self.options["TARGET"]))) threads.append(Thread(target=scan_host(self))) # Additional options - brute force common subdomains if self.options["--brute-force"]: threads.append( Thread(target=brute_force(self, self.options["TARGET"]))) # Start all threads for x in threads: x.start() # Wait for all of them to finish for x in threads: x.join() # remove duplicates and clean up if self.options["--recursive"]: self.recursive_search() self.domains = self.clean_domains(self.domains) self.dedupe = set(self.domains) print("Found", len(self.dedupe), "subdomains") print("----------------") if self.options["--ip"]: self.resolve_ips() else: for domain in self.dedupe: ColorPrint.green(domain.strip()) if not self.options["--no-anubis-db"]: send_to_anubisdb(self, self.options["TARGET"])