def dotransform(request, response, config): try: url = request.fields['url'] except KeyError: url = request.value try: indicators = search_indicator(url) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') else: try: for indicator in indicators: if indicator.get('tcScore'): weight = int(indicator.get('tcScore')) else: weight = 1 indicator = indicator.get('resource') e = Indicator(encode_to_utf8(indicator.get('title')), weight=weight) e.title = encode_to_utf8(indicator.get('title')) # e.resourceId = indicator.get('resourceId') e.resourceId = indicator.get('resourceId') if indicator.get('severity'): e += Label( 'Severity', indicator.get('severity', dict()).get('displayName')) e.severity = indicator.get('severity', dict()).get('displayName') if indicator.get('confidence'): e += Label( 'Confidence', indicator.get('confidence', dict()).get('displayName')) e.confidence = indicator.get('confidence', dict()).get('displayName') if indicator.get('indicatorType'): e += Label( 'Indicator Type', indicator.get('indicatorType', dict()).get('displayName')) e.indicatorType = indicator.get('indicatorType', dict()).get('displayName') if indicator.get('description'): e += Label( 'Description', '<br/>'.join( encode_to_utf8( indicator.get('description')).split('\n'))) response += e except AttributeError as err: response += UIMessage('Error: {}'.format(err), type='PartialError') except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') except TypeError: return response return response
def dotransform(request, response): msg = 'Enter Start & End Date' title = 'Kippo search for sessions by date range' fieldNames = ["Start Date", "End Date"] fieldValues = [] fieldValues = multenterbox(msg, title, fieldNames) if fieldValues[0] or fieldValues[1] != '': s_date = datetime.strptime(fieldValues[0], '%Y-%m-%d') e_date = datetime.strptime(fieldValues[1], '%Y-%m-%d') else: return response + UIMessage('Specify a start & end date') host = request.fields['kippodatabase'] x = db_connect(host) try: cursor = x.cursor() query = "select * from sessions where starttime between %s and %s" cursor.execute(query, (s_date,e_date)) for (id, starttime, endtime, sensor, ip, termsize, client) in cursor: e = KippoSession('%s' %(id)) e.starttime = ('%s' %(starttime)) e.endtime = ('%s' %(endtime)) e.sensor = ('%s' %(sensor)) e.ipaddr = ('%s' %(ip)) e.termsize = ('%s' %(termsize)) e.client = ('%s' %(client)) e += Field('kippodatabase', host, displayname='Kippo Databse') response += e return response except Exception as e: return response + UIMessage(str(e))
def dotransform(request, response): pcap = request.value usedb = config['working/usedb'] # Check to see if we are using the database or not if usedb == 0: return response + UIMessage('No database support configured, check your config file') else: pass x = mongo_connect() try: r = x.STREAMS.find({"File Name": pcap}).count() if r > 0: p = x.STREAMS.find({"File Name": pcap}, {"Stream ID": 1, "_id": 0}) for i in p: sessionid = i['Stream ID'] else: return response + UIMessage('This needs to be run from a TCP/UDP stream') except Exception as e: return response + UIMessage(str(e)) try: t = x.DNS.find({"Stream ID": sessionid}).count() if t > 0: p = x.DNS.find({"Stream ID": sessionid}, {"Request Details.Query Name": 1, "_id": 0}) for i in p: e = Website(i['Request Details']['Query Name']) response += e return response else: return response + UIMessage('No DNS records found') except Exception as e: return response + UIMessage(str(e))
def dotransform(request, response, config): try: cases = get_linked_cases(request.fields['ThreatCentral.resourceId']) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') return response except KeyError: response += UIMessage("No resourceId!", type='PartialError') return response else: try: for case in cases: if case.get('tcScore'): weight = int(case.get('tcScore')) else: weight = 1 e = Case(encode_to_utf8(case.get('title')), weight=weight) e.title = encode_to_utf8(case.get('title')) e.resourceId = case.get('resourceId') if case.get('importanceScore'): e.importanceScore = case.get('importanceScore') e += Label('Importance Score', case.get('importanceScore')) if case.get('importanceLevel'): e.importanceLevel = case.get('importanceLevel') e += Label('Importance Level', case.get('importanceLevel')) # Show comments if len(case.get('comments', list())) is not 0: e += Label( 'Comments', '<br/>'.join([ '{}<br/>'.format(_.get('text')) for _ in encode_to_utf8(case.get('comments')) ]))
def do_transform(self, request, response, config): response += check_update(config) maltego_misp_attribute = request.entity # skip MISP Events (value = int) try: int(maltego_misp_attribute.value) return response except Exception: pass # Check if valid MISP ID is specified if not 'EventID' in maltego_misp_attribute.fields: response += UIMessage("Error: Add MISP EventID Property 'EventID' to Maltego Entity!", type=UIMessageType.Fatal) return response elif int(maltego_misp_attribute.fields['EventID'].value) == 0: response += UIMessage("Error: Enter MISP EventID to Property 'EventID' of Maltego Entity!", type=UIMessageType.Fatal) return response eventID = maltego_misp_attribute.fields['EventID'].value misp = get_misp_connection(config, request.parameters) JSON_resp = misp.freetext(eventID, maltego_misp_attribute.value, adhereToWarninglists=True, distribution=0, returnMetaAttributes=False, pythonify=True,) if 'errors' in JSON_resp: if JSON_resp['errors'][0] == 403: error_response = JSON_resp['errors'][1] if not error_response['saved']: error_reason = error_response['errors']['value'][0] response += UIMessage("Error: %s" % error_reason, type=UIMessageType.Fatal) return response
def dotransform(request, response): pcap = request.value usedb = config['working/usedb'] # Check to see if we are using the database or not if usedb == 0: return response + UIMessage( 'No database support configured, check your config file') else: pass x = mongo_connect() ipaddr = [] try: r = x.STREAMS.find({"File Name": pcap}).count() if r > 0: p = x.STREAMS.find({"File Name": pcap}, { "Packet.Source IP": 1, "Packet.Destination IP": 1, "_id": 0 }) for i in p: sip = i['Packet']['Source IP'] dip = i['Packet']['Destination IP'] ipaddr.append(sip) ipaddr.append(dip) else: return response + UIMessage( 'This needs to be run from a TCP/UDP stream') except Exception as e: return response + UIMessage(str(e)) for t in ipaddr: e = IPv4Address(t) response += e return response
def dotransform(request, response, config): msg = 'Enter Search Criteria' title = 'Kippo search for sessions by IP' fieldNames = ["IP"] fieldValues = [] fieldValues = multenterbox(msg, title, fieldNames) if fieldValues[0] != '': s_ip = fieldValues[0] else: return response + UIMessage('You need to type an IP address!!') host = request.value x = db_connect(host) try: cursor = x.cursor() query = ("select * from sessions where ip like %s") cursor.execute(query, (s_ip, )) for (id, starttime, endtime, sensor, ip, termsize, client) in cursor: e = KippoSession('%s' % (id)) e.starttime = ('%s' % (starttime)) e.endtime = ('%s' % (endtime)) e.sensor = ('%s' % (sensor)) e.ipaddr = ('%s' % (ip)) e.termsize = ('%s' % (termsize)) e.client = ('%s' % (client)) e += Field('kippoip', host, displayname='Kippo IP') response += e return response except: return response + UIMessage(x)
def xfr(ns, domain, response, type_='AXFR', fallback_to_ixfr=True, discovered_names=None): if discovered_names is None: discovered_names = [] try: for msg in dns.query.xfr(ns, domain, type_): for ans in msg.answer: name = ans.name.to_text(True) if ans.rdtype in [1, 5] and name not in discovered_names: discovered_names.append(name) response += DNSName(domain if name == '@' else '.'.join([name, domain])) except dns.resolver.NXDOMAIN: response += UIMessage("DNS records for %s do not exist on %s." % (repr(domain), repr(ns))) except dns.resolver.Timeout: response += UIMessage("DNS request for %s timed out on %s." % (repr(domain), repr(ns))) except dns.exception.FormError: if type_ != 'IXFR' and fallback_to_ixfr: xfr(ns, domain, response, 'IXFR', discovered_names=discovered_names) else: response += UIMessage( "Could not transfer DNS zone for %s from %s." % (repr(domain), repr(ns))) return discovered_names
def dotransform(request, response, config): try: ttps = search_ttp(request.value) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') return response else: try: for ttp in ttps: if ttp.get('tcScore'): weight = int(ttp.get('tcScore')) else: weight = 1 e = TTP(encode_to_utf8(ttp.get('title')), weight=weight) e.title = encode_to_utf8(ttp.get('title')) e.resourceId = ttp.get('id') response += e except AttributeError as err: response += UIMessage('Error: {}'.format(err), type='PartialError') except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') except TypeError: return response return response
def dotransform(request, response, config): if 'ThreatCentral.resourceId' in request.fields: try: incident = get_incident(request.fields['ThreatCentral.resourceId']) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') else: try: # Show linked TTP's if len(incident.get('tacticsTechniquesAndProcedures', list())) is not 0: for ttp in incident.get('tacticsTechniquesAndProcedures'): if ttp.get('tcScore'): weight = int(ttp.get('tcScore')) else: weight = 1 e = TTP(encode_to_utf8(ttp.get('title')), weight=weight) e.title = encode_to_utf8(ttp.get('title')) e.resourceId = ttp.get('resourceId') response += e except AttributeError as err: response += UIMessage('Error: {}'.format(err), type='PartialError') except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') except TypeError: return response return response
def check_update(config): # Do not check updates if running as remote transform if is_remote_exec_mode(): return None # only raise the alert once a day/reboot to the user. try: if time.time() - os.path.getmtime(local_path_version) > 60 * 60 * 24: # check the timestamp of the file recheck = True else: recheck = False except Exception: # file does not exist, so check version recheck = True if not recheck: return None # remember we checked the version from pathlib import Path Path(local_path_version).touch() # UIMessageType must be Fatal as otherwise it is not shown to the user. if 'MISP_maltego.local.check_updates' not in config: return UIMessage("'check_updates' parameter missing in '.canari/MISP_maltego.conf'. Please set 'check_updates = True/False'.", type=UIMessageType.Fatal) if config['MISP_maltego.local.check_updates']: # check the version r = requests.get(update_url) for l in r.text.splitlines(): if 'version=' in l: online_ver = l.strip().strip(',').split('=').pop().strip("'") if StrictVersion(online_ver) > StrictVersion(__version__): message = ('A new version of MISP-Maltego is available.\n' 'To upgrade, please:\n' ' pip3 --upgrade MISP-maltego' ' canari create-profile MISP_maltego\n' ' And import the newly generated .mtz bundle in Maltego (Import > Import Configuration)') return UIMessage(message, type=UIMessageType.Fatal) break return None
def dotransform(request, response): filename = request.value usedb = config['working/usedb'] # Check to see if we are using the database or not if usedb == 0: return response + UIMessage( 'No database support configured, check your config file') else: pass # Connect to the database so we can search for IP addresses. x = mongo_connect() c = x['STREAMS'] try: hosts = [] r = x.STREAMS.find({'File Name': {'$regex': filename}}) if r > 0: for x in r: hosts.append(x['Packet']['Source IP']) hosts.append(x['Packet']['Destination IP']) # streamid = x['Stream ID'] else: return response + UIMessage( 'No records found, please make sure the pcap stream file is indexed' ) for h in hosts: e = IPv4Address(h) # e += Field('streamid', streamid, displayname='Stream ID', MatchingRule='Loose') response += e return response except Exception as e: return response + UIMessage(str(e))
def dotransform(request, response): pcap = request.value try: cmd = 'wireshark ' + pcap os.system(cmd) except Exception as e: return response + UIMessage(str(e)) return response + UIMessage('Wireshark has closed!')
def dotransform(request, response, config): try: results = search(request.value, size=10, pages=1) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') else: try: for result in results: rtype = lower(result.get('type')) if result.get('tcScore'): weight = int(result.get('tcScore')) else: weight = 1 # Title ID Description if rtype == 'actor': # Check Title, if no title get resource > name # Actor entity can have an empty title field if result.get('title'): e = Actor(encode_to_utf8(result.get('title')), weight=weight) else: e = Actor(encode_to_utf8(result.get('resource', dict()).get('name')), weight=weight) e.name = encode_to_utf8(result.get('resource', dict()).get('name')) e.actor = encode_to_utf8(result.get('resource', dict()).get('name')) elif rtype == 'case': e = Case(encode_to_utf8(result.get('title')), weight=weight) elif rtype == 'coursesofactions': e = CoursesOfAction(encode_to_utf8(result.get('title')), weight=weight) elif rtype == 'indicator': e = Indicator(encode_to_utf8(result.get('title')), weight=weight) elif rtype == 'incident': e = Incident(encode_to_utf8(result.get('title')), weight=weight) # elif rtype == 'tacticstechniquesandprocedures': elif rtype == 'ttp': e = TTP(encode_to_utf8(result.get('title')), weight=weight) else: # To be safe e = Phrase(encode_to_utf8(result.get('title')), weight=weight) debug(rtype) e.title = encode_to_utf8(result.get('title')) e.resourceId = result.get('id') if result.get('description'): e += Label('Description', '<br/>'.join(encode_to_utf8(result.get('description', '')).split('\n'))) response += e except AttributeError as err: response += UIMessage('Error: {}'.format(err), type='PartialError') except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') except TypeError: return response return response
def dotransform(request, response, config): try: incidents = search_incident(request.value) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') return response else: try: for incident in incidents: if incident.get('tcScore'): weight = int(incident.get('tcScore')) else: weight = 1 incident = incident.get('resource') if incident: e = Incident(encode_to_utf8(incident.get('title')), weight=weight) e.title = encode_to_utf8(incident.get('title')) e.resourceId = incident.get('resourceId') # e.resourceId = incident.get('id') e.reportedOn = incident.get('reportedOn') e += Label('Reported On', incident.get('reportedOn')) if len(incident.get('incidentCategory', list())) is not 0: e += Label('Incident Category', '<br/>'.join([encode_to_utf8(_.get('displayName')) for _ in incident.get('incidentCategory', list())])) if len(incident.get('affectedAsset', list())) is not 0: e += Label('Affected Asset', '<br/>'.join([encode_to_utf8(_.get('displayName')) for _ in incident.get('affectedAsset', list())])) if len(incident.get('incidentEffect', list())) is not 0: e += Label('Incident Effect', '<br/>'.join([encode_to_utf8(_.get('displayName')) for _ in incident.get('incidentEffect', list())])) if len(incident.get('discoveryMethod', list())) is not 0: e += Label('Discovery Method', '<br/>'.join([encode_to_utf8(_.get('displayName')) for _ in incident.get('discoveryMethod', list())])) if incident.get('description'): e += Label('Description', '<br/>'.join(encode_to_utf8(incident.get('description') ).split('\n'))) response += e except AttributeError as err: response += UIMessage('Error: {}'.format(err), type='PartialError') except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError') except TypeError: return response return response
def run(args): [transform, params, value, fields] = parseargs(['canari %s' % cmd_name(__name__)] + args) transform_module = None fix_binpath(config['default/path']) try: transform_module = import_transform(transform) if os.name == 'posix' and hasattr(transform_module.dotransform, 'privileged') and os.geteuid(): rc = sudo(sys.argv) if rc == 1: message(MaltegoTransformResponseMessage() + UIMessage('User cancelled transform.')) elif rc == 2: message(MaltegoTransformResponseMessage() + UIMessage('Too many incorrect password attempts.')) elif rc: message(MaltegoTransformResponseMessage() + UIMessage('Unknown error occurred.')) exit(0) if hasattr(transform_module, 'onterminate'): onterminate(transform_module.onterminate) else: transform_module.__setattr__('onterminate', lambda *args: exit(-1)) input_entity = to_entity(guess_entity_type(transform_module, fields), value, fields) msg = transform_module.dotransform( MaltegoTransformRequestMessage(value, fields, params, input_entity), MaltegoTransformResponseMessage()) if get_transform_version( transform_module.dotransform ) == 2 else transform_module.dotransform( MaltegoTransformRequestMessage(value, fields, params, input_entity), MaltegoTransformResponseMessage(), config) if isinstance(msg, MaltegoTransformResponseMessage): message(msg) elif isinstance(msg, basestring): raise MaltegoException(msg) else: raise MaltegoException( 'Could not resolve message type returned by transform.') except MaltegoException, me: croak(str(me))
def dotransform(request, response): watcher_db = 'Watcher/resources/databases/watcher.db' try: if os.path.isfile(watcher_db) == False: return response + UIMessage( 'Database doesnt exist, please run Watcher - Create Database transform' ) else: os.remove(watcher_db) return response + UIMessage('Database deleted...!!!') except: pass
def dotransform(request, response): iface = request.value cmd = 'airmon-ng stop ' + iface + ' && service network-manager start' s = os.popen(cmd).readlines() return response + UIMessage('Monitor mode disabled..!!')
def dotransform(request, response): nameserver = request.value if nslookup_raw('www.google.ca', resolver=nameserver).answer: for site in config['dnscachesnoop/wordlist']: debug('Resolving %s' % site) msg = nslookup_raw(site, resolver=nameserver, recursive=False) if not msg.answer: msg = nslookup_raw('www.%s' % site, resolver=nameserver, recursive=False) if msg.answer: e = DNSName(site) t = Table(['Name', 'Query Class', 'Query Type', 'Data', 'TTL'], 'Cached Answers') for rrset in msg.answer: for rr in rrset: t.addrow([ rrset.name.to_text(), dns.rdataclass.to_text(rr.rdclass), dns.rdatatype.to_text(rr.rdtype), rr.to_text(), rrset.ttl ]) e += Label('Cached Answers from %s' % nameserver, t, type='text/html') response += e else: response += UIMessage( 'DNS server did not respond to initial DNS request.') return response
def dotransform(request, response): r = geoip(request.value) if r is not None: if 'error' in r: response += UIMessage(r['error']) return response locname = '' cityf = None countryf = None if 'city' in r: locname += r['city'] cityf = r['city'] if 'countryName' in r: locname += ', %s' % r['countryName'] countryf = r['countryName'] e = Location(locname) if 'longitude' in r and 'latitude' in r: e.longitude = r['longitude'] e.latitude = r['latitude'] link = maplink(r) e += Label('Map It', A(link, link), type='text/html') if 'region' in r: e.area = r['region'] if cityf is not None: e.city = cityf if countryf is not None: e.country = countryf e.iconurl = flag(countryf) if 'countryCode' in r: e.countrycode = r['countryCode'] if e.iconurl is None: e.iconurl = flag(r['countryCode']) response += e return response
def dotransform(request, response): devNull = open('/dev/null', 'w') pcap = request.value file_list = [] try: folder = request.fields['sniffMyPackets.outputfld'] except: return response + UIMessage( 'No output folder defined, run the L0 - Prepare pcap transform') # Use need to change the locations in sniffMyPackets.conf if they are different to the defaults for snort snort_path = config['locations/snort'] snort_conf = config['locations/snort_conf'] snort_folder = folder + '/snort' if not os.path.exists(snort_folder): os.makedirs(snort_folder) cmd = snort_path + ' -c ' + snort_conf + ' -r ' + pcap + ' -l ' + snort_folder + ' -D' subprocess.call(cmd, shell=True, stdout=devNull) file_list = glob.glob(snort_folder + '/*') for x in file_list: e = SnortFile(x) e += Field('pcapsrc', request.value, displayname='Original pcap File', matchingrule='loose') e += Field('sniffMyPackets.outputfld', folder, displayname='Folder Location') e += Field('disclaimer', 'Snort is a registered trademark of Sourcefire, Inc', displayname='Disclaimer') response += e return response
def dotransform(request, response, config): error, found = lookup_whois(request.value) if not error and found: if dict == type(found): for result, value in found.iteritems(): if set == type(value): if "whois_domains" == result: for d in value: if d: e = Domain(d) e.fqdn = d response += e if "whois_emails" == result: for em in value: if em: e = EmailAddress(em) response += e if "whois_nameservers" == result: for w in value: if w: e = NSRecord(w) response += e #Display error message in Transform Output response += UIMessage(error) return response
def dotransform(request, response, config): if 'ThreatCentral.resourceId' in request.fields: try: case = get_case(request.fields['ThreatCentral.resourceId']) except ThreatCentralError as err: response += UIMessage(err.value, type='PartialError')
def dotransform(request, response): ip = request.value ans = nslookup("www.google.ca", nameserver=ip) if ans is not None: for site in config['dnscachesnoop/wordlist']: debug('Resolving %s' % site) ans = nslookup(site, nameserver=ip, rd=0) if not ans[DNS].ancount: ans = nslookup('www.%s' % site, nameserver=ip, rd=0) if ans[DNS].ancount: e = DNSName(site) t = Table(['Name', 'Query Class', 'Query Type', 'Data', 'TTL'], 'Cached Answers') for i in range(0, ans[DNS].ancount): rr = ans[DNS].an[i] t.addrow([ rr.rrname.rstrip('.'), rr.sprintf('%rclass%'), rr.sprintf('%type%'), rr.rdata.rstrip('.'), rr.sprintf('%ttl%') ]) e += Label('Cached Answers', t, type='text/html') response += e else: response += UIMessage( 'DNS server did not respond to initial DNS request.') return response
def dotransform(request, response): s_ip = request.value layers = ['IP', 'ARP'] try: pcap = request.fields['pcapsrc'] except: return response + UIMessage('Sorry this isnt a SmP IP Address') mac_list = [] pkts = rdpcap(pcap) for x in pkts: for s in layers: if x.haslayer(s) and s == 'ARP': if x[ARP].psrc == s_ip: mac = x[Ether].src if mac not in mac_list: mac_list.append(mac) if x.haslayer(s) and s == 'IP': if x[IP].src == s_ip: mac = x[Ether].src if mac not in mac_list: mac_list.append(mac) for x in mac_list: e = MacAddress(x) e += Field('pcapsrc', pcap, displayname='Original pcap File') e += Field('ipaddrsrc', s_ip, displayname='Original IP Address') response += e return response
def dotransform(request, response): try: url = 'http://%s' % request.value urlopen(url) response += Website(request.value, iconurl=thumbnail(url)) except IOError, ioe: response += UIMessage(str(ioe))
def dotransform(request, response): folder = request.value file_list = [] file_ext = ['.pcap', '.cap'] try: if not os.path.exists(folder): return response + UIMessage('Whoops, that folder doesnt exist') except: pass file_list = glob.glob(folder+'/*') for x in file_list: sha1hash = '' md5hash = '' for s in file_ext: if s in x: fh = open(x, 'rb') sha1hash = hashlib.sha1(fh.read()).hexdigest() fh.close() fh = open(x, 'rb') md5hash = hashlib.md5(fh.read()).hexdigest() fh.close() e = pcapFile(x) e.sha1hash = sha1hash e.outputfld = folder e.md5hash = md5hash response += e else: pass return response
def dotransform(request, response): pcap = request.value usedb = config['working/usedb'] if usedb > 0: # Connect to the database so we can insert the record created below x = mongo_connect() c = x['STREAMS'] # Hash the pcap file try: md5hash = md5_for_file(pcap) except Exception as e: return response + UIMessage(str(e)) d = find_session(md5hash) folder = d[2] else: folder = config['working/directory'] l = len(folder) + 11 raw = pcap[l:-5] raw = raw.split('-') banner = 'Protocol:%s\nSource:%s\nDestination:%s' % (raw[0], raw[1], raw[2]) e = pcapStream(banner) response += e return response
def dotransform(request, response): watcher_db = 'Watcher/resources/databases/watcher.db' try: if os.path.isfile(watcher_db) == True: return response + UIMessage( 'Database already exists, please run "Watcher - Delete Database" transform' ) except: pass con = lite.connect(watcher_db) with con: cur = con.cursor() cur.execute( 'CREATE TABLE ssid(tdate TEXT, ttime TEXT, ssid TEXT, mac TEXT, iface TEXT);' ) cur.execute( "CREATE TABLE aplist(tdate TEXT, ttime TEXT, ssid TEXT, bssid TEXT, channel INT, enc TEXT, rssi TEXT, iface TEXT)" ) e = Database(watcher_db) response += e con.close() return response
def dotransform(request, response): domain = request.value wildcard_ips = set() found_subdomains = {} try: msg = nslookup_raw('%s.%s' % (str(uuid4()), domain)) if msg.answer: wildcard_ips = get_ip_addresses(msg) name = '*.%s' % domain response += DNSName(name) found_subdomains[name] = 1 except dns.exception.Timeout: pass if wildcard_ips: warning = 'Warning: wildcard domain is defined... results may not be accurate' debug(warning) response += UIMessage(warning) ncount = 0 nthreads = config['dnsdiscovery/numthreads'] subdomains = set(config['dnsdiscovery/wordlist']) threads = [] queue_send = Queue() queue_recv = Queue() for i in range(0, nthreads): t = DNSResolver(request.value, queue_send, queue_recv) t.start() threads.append(t) for s in subdomains: queue_send.put(s) for i in range(0, nthreads): queue_send.put(None) while True: msg = queue_recv.get() if not msg: ncount += 1 if ncount == nthreads: break elif msg.answer: ips = get_ip_addresses(msg) if wildcard_ips and wildcard_ips.issuperset(ips): continue for name in get_names(domain, msg): if name in found_subdomains: continue else: found_subdomains[name] = 1 response += DNSName(name) for t in threads: t.join() return response