def do_transform(self, request, response, config): be = BinaryEdge(config['binaryedge.local.api_key']) domain = request.entity.value try: # Only consider the fist page res = be.domain_dns(domain) except BinaryEdgeException as e: raise MaltegoException('BinaryEdge error: %s' % e.msg) else: already = [domain] for event in res['events']: if 'A' in event: for ip in event['A']: if ip not in already: response += IPv4Address(ip) already.append(ip) if 'domain' in event: if event['domain'] not in already: response += Domain(event['domain']) already.append(event['domain']) if 'MX' in event: for mx in event['MX']: if mx not in already: response += MXRecord(mx) already.append(mx) if 'NS' in event: for ns in event['NS']: if ns not in already: response += NSRecord(ns) already.append(ns) return response return response
def find_http_sha256(hash, count=False): be = BinaryEdge(API_KEY) search = "http.sha256:%s" %(hash) results = be.host_search(search) if count == True: print "Results: %d" %(results['total']) return for ip in results['events']: print "%s:%s" %(ip['target']['ip'], ip['target']['port'])
def do_transform(self, request, response, config): be = BinaryEdge(config['binaryedge.local.api_key']) domain = request.entity.value try: # Only consider the fist page res = be.domain_subdomains(domain) except BinaryEdgeException as e: raise MaltegoException('BinaryEdge error: %s' % e.msg) else: for e in res["events"]: if e != domain: response += Domain(e) return response
def do_transform(self, request, response, config): ip = request.entity.value be = BinaryEdge(config['binaryedge.local.api_key']) try: res = be.domain_ip(ip) except BinaryEdgeException as e: raise MaltegoException('BinaryEdge error: %s' % e.msg) else: already = [] for e in res['events']: if e['domain'] not in already: response += Domain(e['domain']) already.append(e['domain']) return response
def binaryedge(self): conf = configparser.ConfigParser() conf.read('config.ini') key = conf.get("binaryedge","key") be = BinaryEdge(key) search = self.lineEdit.text() page = self.lineEdit_2.text() print('[*]搜索关键词:'+search) print('[*]搜索页数:'+page) for mun in range(int(page)): results = be.host_search(search,str(mun)) for ip in results['events']: ipi =results ['events'][ip]['target']['ip'] porti=results ['events'][ip]['target']['port'] #print(str(ipi) +':'+ str(porti)) self.textEdit.append(str(ipi) +':'+ str(porti))
def binary_edge_scan(id): key = keys['keys']['binaryedge'] device1 = Device.objects.get(id=id) be = BinaryEdge(key) results = be.host_score(device1.ip) normalized_ip_score = results['normalized_ip_score'] cve = {} if 'cve' in results['results_detailed']: for cc in results['results_detailed']['cve']['result']: if isinstance(cc['cve'], list): for i in cc['cve']: cve[i['cpe']] = i['cve_list'] if isinstance(cc['cve'], dict): if 'cpe' in cc['cve']: cve[cc['cve']['cpe'][0]] = cc['cve']['cve_list'] device2 = BinaryEdgeScore(device=device1, grades=results['ip_score_detailed'], cve=cve, score=normalized_ip_score) device2.save()
def do_transform(self, request, response, config): be = BinaryEdge(config['binaryedge.local.api_key']) ip = request.entity.value try: res = be.host(ip) except BinaryEdgeException as e: raise MaltegoException('BinaryEdge error: %s' % e.msg) else: already = [] for port in res['events']: response += Port(port['port']) for result in port['results']: if result['origin']['type'] == 'ssl': cert = result['result']['data']['cert_info'][ 'certificate_chain'][0] # How to return a certificate ? if 'commonName' in cert['as_dict']['subject']: d = cert['as_dict']['subject']['commonName'] if d not in already: response += Domain(d) already.append(d) if 'extensions' in cert['as_dict']: if 'X509v3 Subject Alternative Name' in cert[ 'as_dict']['extensions']: for domain in cert['as_dict']['extensions'][ 'X509v3 Subject Alternative Name'][ 'DNS']: if domain not in already: response += Domain(domain) already.append(domain) if result['origin']['type'] in ['http', 'grabber']: if 'server' in result['result']['data']['response'][ 'headers']: banner = result['result']['data']['response'][ 'headers']['server'] if banner not in already: response += Banner(banner) already.append(banner) return response
def intel(self, type, query, data, conf): if type == "domain": print("[+] Downloading BinaryEdge information....") try: be = BinaryEdge(conf["BinaryEdge"]["key"]) res = be.domain_dns(query) for d in res["events"]: if "A" in d: for a in d["A"]: data["passive_dns"].append({ "ip": a, "first": parse(d["updated_at"]).astimezone(pytz.utc), "last": parse(d["updated_at"]).astimezone(pytz.utc), "source": "BinaryEdge", }) except BinaryEdgeException: print( "You need a paid BinaryEdge subscription for this request") elif type == "ip": print("[+] Downloading BinaryEdge information....") try: be = BinaryEdge(conf["BinaryEdge"]["key"]) res = be.domain_ip(query) for d in res["events"]: data["passive_dns"].append({ "domain": d["domain"], "first": parse(d["updated_at"]).astimezone(pytz.utc), "last": "", "source": "BinaryEdge", }) res = be.host(query) for d in res["events"]: data["ports"].append({ "port": d["port"], "info": "", "source": "BinaryEdge" }) except BinaryEdgeException: print( "You need a paid BinaryEdge subscription for this request")
def query_binary_edge(jarm): """ Query Binary Edge and parse the results """ raw_result = BinaryEdge( config.BINARY_EDGE_KEY).host_search(f'jarm.jarm_hash:"{jarm}"') ips = set() ports = set() protocols = set() for r in raw_result['events']: ips.add(get_key(r, 'target.ip', default='')) ports.add(get_key(r, 'target.port', default='')) protocols.add(get_key(r, 'target.protocol', default='')) parsed_results = { 'total': raw_result['total'], 'ips': list(ips), 'ports': list(ports), 'protocols': list(protocols), } return raw_result, parsed_results
def run(self, conf, args, plugins): if 'subcommand' in args: if args.subcommand == "intel": # Start with MISP and OTX to get Intelligence Reports print('###################### %s ###################' % args.DOMAIN) passive_dns = [] urls = [] malware = [] files = [] # MISP misp_e = plugins['misp'].test_config(conf) if misp_e: print('[+] Downloading MISP information...') server = ExpandedPyMISP(conf['Misp']['url'], conf['Misp']['key']) misp_results = server.search('attributes', value=unbracket(args.DOMAIN)) # OTX otx_e = plugins['otx'].test_config(conf) if otx_e: print('[+] Downloading OTX information....') try: otx = OTXv2(conf["AlienVaultOtx"]["key"]) res = otx.get_indicator_details_full(IndicatorTypes.DOMAIN, unbracket(args.DOMAIN)) otx_pulses = res["general"]["pulse_info"]["pulses"] # Get Passive DNS if "passive_dns" in res: for r in res["passive_dns"]["passive_dns"]: passive_dns.append({ "ip": r['hostname'], "first": parse(r["first"]).astimezone(pytz.utc), "last": parse(r["last"]).astimezone(pytz.utc), "source" : "OTX" }) if "url_list" in res: for r in res["url_list"]["url_list"]: if "result" in r: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": r["result"]["urlworker"]["ip"] if "ip" in r["result"]["urlworker"] else "" , "source": "OTX" }) else: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": "", "source": "OTX" }) except AttributeError: print('OTX crashed ¯\_(ツ)_/¯') # UrlScan us = UrlScan() print('[+] Downloading UrlScan information....') res = us.search(args.DOMAIN) for r in res['results']: urls.append({ "date": parse(r["task"]["time"]).astimezone(pytz.utc), "url": r["page"]["url"], "ip": r["page"]["ip"] if "ip" in r["page"] else "", "source": "UrlScan" }) # UrlHaus uh_e = plugins['urlhaus'].test_config(conf) if uh_e: print("[+] Checking urlhaus...") try: urlhaus = UrlHaus(conf["UrlHaus"]["key"]) res = urlhaus.get_host(unbracket(args.DOMAIN)) except UrlHausError: print("Error with the query") else: if "urls" in res: for r in res['urls']: urls.append({ "date": parse(r["date_added"]).astimezone(pytz.utc), "url": r["url"], "ip":"", "source": "UrlHaus" }) # CIRCL circl_e = plugins['circl'].test_config(conf) if circl_e: print('[+] Downloading CIRCL passive DNS information....') x = pypdns.PyPDNS( basic_auth=( conf['Circl']['user'], conf['Circl']['pass'] ) ) res = x.query(unbracket(args.DOMAIN)) for answer in res: passive_dns.append({ "ip": answer['rdata'], "first": answer['time_first'].astimezone(pytz.utc), "last": answer['time_last'].astimezone(pytz.utc), "source" : "CIRCL" }) # BinaryEdge be_e = plugins['binaryedge'].test_config(conf) if be_e: print('[+] Downloading BinaryEdge information....') try: be = BinaryEdge(conf['BinaryEdge']['key']) res = be.domain_dns(unbracket(args.DOMAIN)) for d in res['events']: if "A" in d: for a in d['A']: passive_dns.append({ "ip": a, "first": parse(d['updated_at']).astimezone(pytz.utc), "last": parse(d['updated_at']).astimezone(pytz.utc), "source" : "BinaryEdge" }) except BinaryEdgeException: print('You need a paid BinaryEdge subscription for this request') # RobTex print('[+] Downloading Robtex information....') try: rob = Robtex() res = rob.get_pdns_domain(args.DOMAIN) for d in res: if d['rrtype'] in ['A', 'AAAA']: passive_dns.append({ 'first': d['time_first_o'].astimezone(pytz.utc), 'last': d['time_last_o'].astimezone(pytz.utc), 'ip': d['rrdata'], 'source': 'Robtex' }) except RobtexError: print("Robtex query failed") # PT pt_e = plugins['pt'].test_config(conf) if pt_e: try: pt_osint = {} ptout = False print('[+] Downloading Passive Total information....') client = DnsRequest(conf['PassiveTotal']['username'], conf['PassiveTotal']['key']) raw_results = client.get_passive_dns(query=unbracket(args.DOMAIN)) if "results" in raw_results: for res in raw_results["results"]: passive_dns.append({ "first": parse(res["firstSeen"]).astimezone(pytz.utc), "last": parse(res["lastSeen"]).astimezone(pytz.utc), "ip": res["resolve"], "source": "PT" }) if "message" in raw_results: if "quota_exceeded" in raw_results["message"]: print("PT quota exceeded") ptout = True if not ptout: client2 = EnrichmentRequest(conf["PassiveTotal"]["username"], conf["PassiveTotal"]['key']) # Get OSINT # TODO: add PT projects here pt_osint = client2.get_osint(query=unbracket(args.DOMAIN)) # Get malware raw_results = client2.get_malware(query=unbracket(args.DOMAIN)) if "results" in raw_results: for r in raw_results["results"]: malware.append({ 'hash': r["sample"], 'date': parse(r['collectionDate']).astimezone(pytz.utc), 'source' : 'PT (%s)' % r["source"] }) except requests.exceptions.ReadTimeout: print("PT: Time Out") # VT vt_e = plugins['vt'].test_config(conf) if vt_e: if conf["VirusTotal"]["type"] != "public": print('[+] Downloading VT information....') vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_domain_report(unbracket(args.DOMAIN)) if "results" in res: if "resolutions" in res['results']: for r in res["results"]["resolutions"]: passive_dns.append({ "first": parse(r["last_resolved"]).astimezone(pytz.utc), "last": parse(r["last_resolved"]).astimezone(pytz.utc), "ip": r["ip_address"], "source": "VT" }) if "undetected_downloaded_samples" in res['results']: for r in res['results']['undetected_downloaded_samples']: files.append({ 'hash': r['sha256'], 'date': parse(r['date']).astimezone(pytz.utc) if 'date' in r else '', 'source' : 'VT' }) if "undetected_referrer_samples" in res['results']: for r in res['results']['undetected_referrer_samples']: files.append({ 'hash': r['sha256'], 'date': parse(r['date']).astimezone(pytz.utc) if 'date' in r else '', 'source' : 'VT' }) if "detected_downloaded_samples" in res['results']: for r in res['results']['detected_downloaded_samples']: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']).astimezone(pytz.utc), 'source' : 'VT' }) if "detected_referrer_samples" in res['results']: for r in res['results']['detected_referrer_samples']: if "date" in r: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']).astimezone(pytz.utc), 'source' : 'VT' }) if "detected_urls" in res['results']: for r in res['results']['detected_urls']: urls.append({ 'date': parse(r['scan_date']).astimezone(pytz.utc), 'url': r['url'], 'ip': '', 'source': 'VT' }) else: vt_e = False tg_e = plugins['threatgrid'].test_config(conf) if tg_e: try: print('[+] Downloading Threat Grid....') tg = ThreatGrid(conf['ThreatGrid']['key']) res = tg.search_samples(unbracket(args.DOMAIN), type='domain') already = [] if 'items' in res: for r in res['items']: if r['sample_sha256'] not in already: d = parse(r['ts']).astimezone(pytz.utc) malware.append({ 'hash': r["sample_sha256"], 'date': d, 'source' : 'ThreatGrid' }) already.append(r['sample_sha256']) except ThreatGridError as e: print("Failed to connect to Threat Grid: %s" % e.message) print('[+] Downloading ThreatMiner....') tm = ThreatMiner() response = tm.get_report(unbracket(args.DOMAIN)) if response['status_code'] == '200': tmm = response['results'] else: tmm = [] if response['status_code'] == '404': print("Request to ThreatMiner failed: {}".format(response['status_message'])) response = tm.get_related_samples(unbracket(args.DOMAIN)) if response['status_code'] == '200': for r in response['results']: malware.append({ 'hash': r, 'date': None, 'source': 'ThreatMiner' }) print('----------------- Intelligence Report') if misp_e: if len(misp_results['Attribute']) > 0: print('MISP:') for event in misp_results['Attribute']: print("- {} - {}".format( event['Event']['id'], event['Event']['info'] )) if otx_e: if len(otx_pulses): print('OTX:') for p in otx_pulses: print('- %s (%s - %s)' % ( p['name'], p['created'][:10], "https://otx.alienvault.com/pulse/" + p['id'] ) ) else: print('OTX: Not found in any pulse') if pt_e: if "results" in pt_osint: if len(pt_osint["results"]): if len(pt_osint["results"]) == 1: if "name" in pt_osint["results"][0]: print("PT: %s %s" % (pt_osint["results"][0]["name"], pt_osint["results"][0]["sourceUrl"])) else: print("PT: %s" % (pt_osint["results"][0]["sourceUrl"])) else: print("PT:") for r in pt_osint["results"]: if "name" in r: print("- %s %s" % (r["name"], r["sourceUrl"])) else: print("- %s" % (r["sourceUrl"])) else: print("PT: Nothing found!") else: print("PT: Nothing found!") # ThreatMiner if len(tmm) > 0: print("ThreatMiner:") for r in tmm: print("- {} {} - {}".format( r['year'], r['filename'], r['URL'] )) if len(malware) > 0: print('----------------- Malware') for r in malware: print("[%s] %s %s" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") if r["date"] else "" ) ) if len(files) > 0: print('----------------- Files') for r in files: if r['date'] != '': print("[%s] %s (%s)" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") ) ) else: print("[%s] %s" % ( r["source"], r["hash"], ) ) if len(urls) > 0: print('----------------- Urls') for r in sorted(urls, key=lambda x: x["date"], reverse=True): print("[%s] %s - %s %s" % ( r["source"], r["url"], r["ip"], r["date"].strftime("%Y-%m-%d") ) ) # TODO: add ASN + location info here if len(passive_dns) > 0: print('----------------- Passive DNS') for r in sorted(passive_dns, key=lambda x: x["first"], reverse=True): print("[+] %-40s (%s -> %s)(%s)" % ( r["ip"], r["first"].strftime("%Y-%m-%d"), r["last"].strftime("%Y-%m-%d"), r["source"] ) ) else: self.parser.print_help() else: self.parser.print_help()
from pybinaryedge import BinaryEdge import os key= os.environ['BINARYEDGE_API_KEY'] binaryEdge = BinaryEdge(key) search_domain = 'www.python.org' results = binaryEdge.host_search(search_domain) for ip in results['events']: print("%s" %(ip['target']['ip']))
def scan(query): print('[-] Searching now in BinaryEdge..') be = BinaryEdge('<your_token>') results = be.domain_subdomains(query) subdom_list = results.get('events') return subdom_list
def run(self, conf, args, plugins): be = BinaryEdge(conf['BinaryEdge']['key']) try: if hasattr(args, 'which'): if args.which == 'ip': if args.score: res = be.host_score(unbracket(args.IP)) elif args.image: res = be.image_ip(unbracket(args.IP)) elif args.torrent: if args.historical: res = be.torrent_historical_ip(unbracket(args.IP)) else: res = be.torrent_ip(unbracket(args.IP)) elif args.historical: res = be.host_historical(unbracket(args.IP)) elif args.dns: res = be.domain_ip(args.IP, page=args.page) else: res = be.host(unbracket(args.IP)) print(json.dumps(res, sort_keys=True, indent=4)) elif args.which == 'search': if args.image: res = be.image_search(args.SEARCH, page=args.page) else: res = be.host_search(args.SEARCH, page=args.page) print(json.dumps(res, sort_keys=True, indent=4)) elif args.which == 'dataleaks': if args.domain: res = be.dataleaks_organization(args.EMAIL) else: res = be.dataleaks_email(args.EMAIL) print(json.dumps(res, sort_keys=True, indent=4)) elif args.which == 'domain': if args.subdomains: res = be.domain_subdomains(args.DOMAIN, page=args.page) else: res = be.domain_dns(args.DOMAIN, page=args.page) print(json.dumps(res, sort_keys=True, indent=4)) else: self.parser.print_help() else: self.parser.print_help() except ValueError as e: print('Invalid Value: %s' % e.message) except BinaryEdgeNotFound: print('Search term not found') except BinaryEdgeException as e: print('Error: %s' % e.message)
last = last + 1 elastic_query = "type:%22elasticsearch%22" mongodb_query = "type:%22mongodb%22" couchdb_query = "product:%22couchdb%22" rsync_query = "rsync port:%22873%22" sonarqube_query = "%22Title: SonarQube%22" jenkins_query = "%22Dashboard [Jenkins]%22" gitlab_query = "%22Sign in GitLab%22" kibana_query = "product:%22kibana%22" listing_query = '%22Index of /%22' cassandra_query = "type:%22cassandra%22" rethink_query = "type:%22rethinkdb%22" BINARYEDGE_API_KEY = args.key be = BinaryEdge(BINARYEDGE_API_KEY) buckets = set() def parse_bucket(bucket): parsed = urlparse(bucket) path = parsed.path.split('/') try: if parsed.netloc.startswith("s3"): if len(path) > 1: if path[1] not in buckets: print("https://" + parsed.netloc + "/" + path[1]) amazon_req = requests.get("https://" + parsed.netloc + "/" + path[1],
def binaryedgeQuery(query, limit): from pybinaryedge import BinaryEdge import ODBconfig BEkey = ODBconfig.BINARY_API_KEY requestleft = binaryedgecheck(BEkey) if requestleft > 0: limit = int(limit) #params country:us port pages = int(limit / 20) + ( limit % 20 > 0 ) #20 results per page, see how many pages need to grab by rounding up if pages > 999: pages = 1000 print("Max pages is 1000") be = BinaryEdge(BEkey) counter = 0 BEres = [] results = be.host_search(query) total = results["total"] maxpages = int(total / 20) + ( total % 20 > 0 ) #20 results per page, see how many pages need to grab by rounding up if pages > maxpages: pages = maxpages if results["events"]: for x in results["events"]: if "error" in x["result"]: if not x["result"][ "error"]: #one more step to get rid of crap BEres.append((x["target"]["ip"], x["origin"]["type"], x["target"]["port"])) else: BEres.append((x["target"]["ip"], x["origin"]["type"], x["target"]["port"])) try: for i in range(2, maxpages + 1): results = be.host_search(query, i) if not results["events"]: break for x in results["events"]: if "error" in x["result"]: if not x["result"]["error"]: BEres.append( (x["origin"]["ip"], x["origin"]["type"], x["target"]["port"])) else: BEres.append((x["target"]["ip"], x["origin"]["type"], x["target"]["port"])) except Exception as e: print(str(e)) BEres = list(set(BEres)) #for some reason return sdupe records BEres = BEres[:limit] return BEres elif requestleft == 0: print( f"{Fore.RED}ERROR! {Fore.RESET}Your {Fore.CYAN}BinaryEdge{Fore.RESET} plans has {Fore.GREEN}no more queries left{Fore.RESET}. Wait til requests cycle or pay for a plan" ) sys.exit()
def run(self, conf, args, plugins): if 'subcommand' in args: if args.subcommand == 'info': if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # FIXME: move code here in a library ip = unbracket(args.IP) try: ipy = IP(ip) except ValueError: print('Invalid IP format, quitting...') return ipinfo = self.ipinfo(ip) print('MaxMind: Located in %s, %s' % (ipinfo['city'], ipinfo['country'])) if ipinfo['asn'] == 0: print("MaxMind: IP not found in the ASN database") else: print('MaxMind: ASN%i, %s' % (ipinfo['asn'], ipinfo['asn_name'])) print('CAIDA Type: %s' % ipinfo['asn_type']) asndb2 = pyasn.pyasn(self.asncidr) res = asndb2.lookup(ip) if res[1] is None: print("IP not found in ASN database") else: # Search for name f = open(self.asnname, 'r') found = False line = f.readline() name = '' while not found and line != '': s = line.split('|') if s[0] == str(res[0]): name = s[1].strip() found = True line = f.readline() print('ASN %i - %s (range %s)' % (res[0], name, res[1])) if ipinfo['hostname'] != '': print('Hostname: %s' % ipinfo['hostname']) if ipinfo['specific'] != '': print("Specific: %s" % ipinfo['specific']) if ipy.iptype() == "PRIVATE": "Private IP" print("") if ipy.version() == 4: print("Censys:\t\thttps://censys.io/ipv4/%s" % ip) print("Shodan:\t\thttps://www.shodan.io/host/%s" % ip) print("IP Info:\thttp://ipinfo.io/%s" % ip) print("BGP HE:\t\thttps://bgp.he.net/ip/%s" % ip) print( "IP Location:\thttps://www.iplocation.net/?query=%s" % ip) elif args.subcommand == "intel": if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # Start with MISP and OTX to get Intelligence Reports print('###################### %s ###################' % unbracket(args.IP)) passive_dns = [] urls = [] malware = [] files = [] # MISP misp_e = plugins['misp'].test_config(conf) if misp_e: print('[+] Downloading MISP information...') server = MispServer(url=conf['Misp']['url'], apikey=conf['Misp']['key']) misp_results = server.attributes.search( value=unbracket(args.IP)) # Binary Edge be_e = plugins['binaryedge'].test_config(conf) if be_e: try: print('[+] Downloading BinaryEdge information...') be = BinaryEdge(conf['BinaryEdge']['key']) # FIXME: this only get the first page res = be.domain_ip(unbracket(args.IP)) for d in res["events"]: passive_dns.append({ "domain": d['domain'], "first": parse(d['updated_at']).astimezone(pytz.utc), "last": parse(d['updated_at']).astimezone(pytz.utc), "source": "BinaryEdge" }) except BinaryEdgeException: print( 'BinaryEdge request failed, you need a paid subscription' ) # OTX otx_e = plugins['otx'].test_config(conf) if otx_e: print('[+] Downloading OTX information....') otx = OTXv2(conf["AlienVaultOtx"]["key"]) res = otx.get_indicator_details_full( IndicatorTypes.IPv4, unbracket(args.IP)) otx_pulses = res["general"]["pulse_info"]["pulses"] # Get Passive DNS if "passive_dns" in res: for r in res["passive_dns"]["passive_dns"]: passive_dns.append({ "domain": r['hostname'], "first": parse(r["first"]).astimezone(pytz.utc), "last": parse(r["last"]).astimezone(pytz.utc), "source": "OTX" }) if "url_list" in res: for r in res["url_list"]["url_list"]: urls.append(r) # RobTex print('[+] Downloading Robtex information....') rob = Robtex() try: res = rob.get_ip_info(unbracket(args.IP)) except RobtexError: print("Error with Robtex") else: for d in ["pas", "pash", "act", "acth"]: if d in res: for a in res[d]: passive_dns.append({ 'first': a['date'].astimezone(pytz.utc), 'last': a['date'].astimezone(pytz.utc), 'domain': a['o'], 'source': 'Robtex' }) # PT pt_e = plugins['pt'].test_config(conf) if pt_e: out_pt = False print('[+] Downloading Passive Total information....') client = DnsRequest(conf['PassiveTotal']['username'], conf['PassiveTotal']['key']) try: raw_results = client.get_passive_dns( query=unbracket(args.IP)) if "results" in raw_results: for res in raw_results["results"]: passive_dns.append({ "first": parse(res["firstSeen"]).astimezone( pytz.utc), "last": parse(res["lastSeen"]).astimezone( pytz.utc), "domain": res["resolve"], "source": "PT" }) if "message" in raw_results: if "quota_exceeded" in raw_results["message"]: print("Quota exceeded for Passive Total") out_pt = True pt_osint = {} except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") if not out_pt: try: client2 = EnrichmentRequest( conf["PassiveTotal"]["username"], conf["PassiveTotal"]['key']) # Get OSINT # TODO: add PT projects here pt_osint = client2.get_osint( query=unbracket(args.IP)) # Get malware raw_results = client2.get_malware( query=unbracket(args.IP)) if "results" in raw_results: for r in raw_results["results"]: malware.append({ 'hash': r["sample"], 'date': parse(r['collectionDate']), 'source': 'PT (%s)' % r["source"] }) except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") # VT vt_e = plugins['vt'].test_config(conf) if vt_e: if conf["VirusTotal"]["type"] != "public": print('[+] Downloading VT information....') vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_ip_report(unbracket(args.IP)) if "results" in res: if "resolutions" in res['results']: for r in res["results"]["resolutions"]: passive_dns.append({ "first": parse(r["last_resolved"]).astimezone( pytz.utc), "last": parse(r["last_resolved"]).astimezone( pytz.utc), "domain": r["hostname"], "source": "VT" }) if "undetected_downloaded_samples" in res[ 'results']: for r in res['results'][ 'undetected_downloaded_samples']: files.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source': 'VT' }) if "undetected_referrer_samples" in res['results']: for r in res['results'][ 'undetected_referrer_samples']: if 'date' in r: files.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source': 'VT' }) else: #FIXME : should consider data without dates files.append({ 'hash': r['sha256'], 'date': datetime.datetime(1970, 1, 1), 'source': 'VT' }) if "detected_downloaded_samples" in res['results']: for r in res['results'][ 'detected_downloaded_samples']: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source': 'VT' }) if "detected_referrer_samples" in res['results']: for r in res['results'][ 'detected_referrer_samples']: if "date" in r: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source': 'VT' }) else: vt_e = False print('[+] Downloading GreyNoise information....') gn = GreyNoise() try: greynoise = gn.query_ip(unbracket(args.IP)) except GreyNoiseError: greynoise = [] tg_e = plugins['threatgrid'].test_config(conf) if tg_e: print('[+] Downloading Threat Grid....') tg = ThreatGrid(conf['ThreatGrid']['key']) res = tg.search_samples(unbracket(args.IP), type='ip') already = [] if 'items' in res: for r in res['items']: if r['sample_sha256'] not in already: d = parse(r['ts']) d = d.replace(tzinfo=None) malware.append({ 'hash': r["sample_sha256"], 'date': d, 'source': 'TG' }) already.append(r['sample_sha256']) print('----------------- Intelligence Report') if otx_e: if len(otx_pulses): print('OTX:') for p in otx_pulses: print(' -%s (%s - %s)' % (p['name'], p['created'][:10], "https://otx.alienvault.com/pulse/" + p['id'])) else: print('OTX: Not found in any pulse') if misp_e: if len(misp_results) > 0: print('MISP:') for event in misp_results: print(" -%i - %s" % (event.id, event.info)) if len(greynoise) > 0: print("GreyNoise: IP identified as") for r in greynoise: print("\t%s (%s -> %s)" % (r["name"], r["first_seen"], r["last_updated"])) else: print("GreyNoise: Not found") if pt_e: if "results" in pt_osint: if len(pt_osint["results"]): if len(pt_osint["results"]) == 1: if "name" in pt_osint["results"][0]: print( "PT: %s %s" % (pt_osint["results"][0]["name"], pt_osint["results"][0]["sourceUrl"])) else: print("PT: %s" % pt_osint["results"][0]["sourceUrl"]) else: print("PT:") for r in pt_osint["results"]: if "name" in r: print("-%s %s" % (r["name"], r["sourceUrl"])) else: print("-%s" % r["sourceUrl"]) else: print("PT: Nothing found!") else: print("PT: Nothing found!") if len(malware) > 0: print('----------------- Malware') for r in sorted(malware, key=lambda x: x["date"]): print("[%s] %s %s" % (r["source"], r["hash"], r["date"].strftime("%Y-%m-%d"))) if len(files) > 0: print('----------------- Files') for r in sorted(files, key=lambda x: x["date"]): print("[%s] %s %s" % (r["source"], r["hash"], r["date"].strftime("%Y-%m-%d"))) if len(passive_dns) > 0: print('----------------- Passive DNS') for r in sorted(passive_dns, key=lambda x: x["first"], reverse=True): print("[+] %-40s (%s -> %s)(%s)" % (r["domain"], r["first"].strftime("%Y-%m-%d"), r["last"].strftime("%Y-%m-%d"), r["source"])) else: self.parser.print_help() else: self.parser.print_help()
def run(self, conf, args, plugins): if 'subcommand' in args: if args.subcommand == 'info': print("Not implemented yet") elif args.subcommand == "intel": # Start with MISP and OTX to get Intelligence Reports print('###################### %s ###################' % args.DOMAIN) passive_dns = [] urls = [] malware = [] files = [] # OTX otx_e = plugins['otx'].test_config(conf) if otx_e: print('[+] Downloading OTX information....') otx = OTXv2(conf["AlienVaultOtx"]["key"]) res = otx.get_indicator_details_full(IndicatorTypes.DOMAIN, unbracket(args.DOMAIN)) otx_pulses = res["general"]["pulse_info"]["pulses"] # Get Passive DNS if "passive_dns" in res: for r in res["passive_dns"]["passive_dns"]: passive_dns.append({ "ip": r['hostname'], "first": parse(r["first"]), "last": parse(r["last"]), "source" : "OTX" }) if "url_list" in res: for r in res["url_list"]["url_list"]: if "result" in r: urls.append({ "date": parse(r["date"]), "url": r["url"], "ip": r["result"]["urlworker"]["ip"] if "ip" in r["result"]["urlworker"] else "" , "source": "OTX" }) else: urls.append({ "date": parse(r["date"]), "url": r["url"], "ip": "", "source": "OTX" }) # CIRCL circl_e = plugins['circl'].test_config(conf) if circl_e: print('[+] Downloading CIRCL passive DNS information....') x = pypdns.PyPDNS( basic_auth=( conf['Circl']['user'], conf['Circl']['pass'] ) ) res = x.query(unbracket(args.DOMAIN)) for answer in res: passive_dns.append({ "ip": answer['rdata'], "first": answer['time_first'], "last": answer['time_last'], "source" : "CIRCL" }) # BinaryEdge be_e = plugins['binaryedge'].test_config(conf) if be_e: print('[+] Downloading BinaryEdge information....') be = BinaryEdge(conf['BinaryEdge']['key']) res = be.domain_dns(unbracket(args.DOMAIN)) for d in res['events']: if "A" in d: for a in d['A']: passive_dns.append({ "ip": a, "first": parse(d['updated_at']), "last": parse(d['updated_at']), "source" : "BinaryEdge" }) # RobTex print('[+] Downloading Robtex information....') rob = Robtex() res = rob.get_pdns_domain(args.DOMAIN) for d in res: if d['rrtype'] in ['A', 'AAAA']: passive_dns.append({ 'first': d['time_first_o'], 'last': d['time_last_o'], 'ip': d['rrdata'], 'source': 'Robtex' }) # PT pt_e = plugins['pt'].test_config(conf) if pt_e: try: pt_osint = {} ptout = False print('[+] Downloading Passive Total information....') client = DnsRequest(conf['PassiveTotal']['username'], conf['PassiveTotal']['key']) raw_results = client.get_passive_dns(query=unbracket(args.DOMAIN)) if "results" in raw_results: for res in raw_results["results"]: passive_dns.append({ "first": parse(res["firstSeen"]), "last": parse(res["lastSeen"]), "ip": res["resolve"], "source": "PT" }) if "message" in raw_results: if "quota_exceeded" in raw_results["message"]: print("PT quota exceeded") ptout = True if not ptout: client2 = EnrichmentRequest(conf["PassiveTotal"]["username"], conf["PassiveTotal"]['key']) # Get OSINT # TODO: add PT projects here pt_osint = client2.get_osint(query=unbracket(args.DOMAIN)) # Get malware raw_results = client2.get_malware(query=unbracket(args.DOMAIN)) if "results" in raw_results: for r in raw_results["results"]: malware.append({ 'hash': r["sample"], 'date': parse(r['collectionDate']), 'source' : 'PT (%s)' % r["source"] }) except requests.exceptions.ReadTimeout: print("PT: Time Out") # VT vt_e = plugins['vt'].test_config(conf) if vt_e: if conf["VirusTotal"]["type"] != "public": print('[+] Downloading VT information....') vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_domain_report(unbracket(args.DOMAIN)) if "results" in res: if "resolutions" in res['results']: for r in res["results"]["resolutions"]: passive_dns.append({ "first": parse(r["last_resolved"]), "last": parse(r["last_resolved"]), "ip": r["ip_address"], "source": "VT" }) if "undetected_downloaded_samples" in res['results']: for r in res['results']['undetected_downloaded_samples']: files.append({ 'hash': r['sha256'], 'date': parse(r['date']) if 'date' in r else '', 'source' : 'VT' }) if "undetected_referrer_samples" in res['results']: for r in res['results']['undetected_referrer_samples']: files.append({ 'hash': r['sha256'], 'date': parse(r['date']) if 'date' in r else '', 'source' : 'VT' }) if "detected_downloaded_samples" in res['results']: for r in res['results']['detected_downloaded_samples']: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source' : 'VT' }) if "detected_referrer_samples" in res['results']: for r in res['results']['detected_referrer_samples']: if "date" in r: malware.append({ 'hash': r['sha256'], 'date': parse(r['date']), 'source' : 'VT' }) if "detected_urls" in res['results']: for r in res['results']['detected_urls']: urls.append({ 'date': parse(r['scan_date']), 'url': r['url'], 'ip': '', 'source': 'VT' }) else: vt_e = False tg_e = plugins['threatgrid'].test_config(conf) if tg_e: try: print('[+] Downloading Threat Grid....') tg = ThreatGrid(conf['ThreatGrid']['key']) res = tg.search_samples(unbracket(args.DOMAIN), type='domain') already = [] if 'items' in res: for r in res['items']: if r['sample_sha256'] not in already: d = parse(r['ts']) d = d.replace(tzinfo=None) malware.append({ 'hash': r["sample_sha256"], 'date': d, 'source' : 'ThreatGrid' }) already.append(r['sample_sha256']) except ThreatGridError as e: print("Failed to connect to Threat Grid: %s" % e.message) # TODO: Add MISP print('----------------- Intelligence Report') if otx_e: if len(otx_pulses): print('OTX:') for p in otx_pulses: print(' -%s (%s - %s)' % ( p['name'], p['created'][:10], "https://otx.alienvault.com/pulse/" + p['id'] ) ) else: print('OTX: Not found in any pulse') if pt_e: if "results" in pt_osint: if len(pt_osint["results"]): if len(pt_osint["results"]) == 1: if "name" in pt_osint["results"][0]: print("PT: %s %s" % (pt_osint["results"][0]["name"], pt_osint["results"][0]["sourceUrl"])) else: print("PT: %s" % (pt_osint["results"][0]["sourceUrl"])) else: print("PT:") for r in pt_osint["results"]: if "name" in r: print("-%s %s" % (r["name"], r["sourceUrl"])) else: print("-%s" % (r["sourceUrl"])) else: print("PT: Nothing found!") else: print("PT: Nothing found!") if len(malware) > 0: print('----------------- Malware') for r in sorted(malware, key=lambda x: x["date"]): print("[%s] %s %s" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") ) ) if len(files) > 0: print('----------------- Files') for r in files: if r['date'] != '': print("[%s] %s (%s)" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") ) ) else: print("[%s] %s" % ( r["source"], r["hash"], ) ) if len(urls) > 0: print('----------------- Urls') for r in sorted(urls, key=lambda x: x["date"], reverse=True): print("[%s] %s - %s %s" % ( r["source"], r["url"], r["ip"], r["date"].strftime("%Y-%m-%d") ) ) # TODO: add ASN + location info here if len(passive_dns) > 0: print('----------------- Passive DNS') for r in sorted(passive_dns, key=lambda x: x["first"], reverse=True): print("[+] %-40s (%s -> %s)(%s)" % ( r["ip"], r["first"].strftime("%Y-%m-%d"), r["last"].strftime("%Y-%m-%d"), r["source"] ) ) else: self.parser.print_help() else: self.parser.print_help()
def run(self, conf, args, plugins): if "subcommand" in args: if args.subcommand == "info": if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # FIXME: move code here in a library ip = unbracket(args.IP) try: ipy = IP(ip) except ValueError: print("Invalid IP format, quitting...") return ipinfo = self.ipinfo(ip) print("MaxMind: Located in %s, %s" % (ipinfo["city"], ipinfo["country"])) if ipinfo["asn"] == 0: print("MaxMind: IP not found in the ASN database") else: print("MaxMind: ASN%i, %s" % (ipinfo["asn"], ipinfo["asn_name"])) print("CAIDA Type: %s" % ipinfo["asn_type"]) try: asndb2 = pyasn.pyasn(self.asncidr) res = asndb2.lookup(ip) except OSError: print("Configuration files are not available") print("Please run harpoon update before using harpoon") sys.exit(1) if res[1] is None: print("IP not found in ASN database") else: # Search for name f = open(self.asnname, "r") found = False line = f.readline() name = "" while not found and line != "": s = line.split("|") if s[0] == str(res[0]): name = s[1].strip() found = True line = f.readline() print("ASN %i - %s (range %s)" % (res[0], name, res[1])) if ipinfo["hostname"] != "": print("Hostname: %s" % ipinfo["hostname"]) if ipinfo["specific"] != "": print("Specific: %s" % ipinfo["specific"]) if ipy.iptype() == "PRIVATE": "Private IP" print("") if ipy.version() == 4: print("Censys:\t\thttps://censys.io/ipv4/%s" % ip) print("Shodan:\t\thttps://www.shodan.io/host/%s" % ip) print("IP Info:\thttp://ipinfo.io/%s" % ip) print("BGP HE:\t\thttps://bgp.he.net/ip/%s" % ip) print( "IP Location:\thttps://www.iplocation.net/?query=%s" % ip) elif args.subcommand == "intel": if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # Start with MISP and OTX to get Intelligence Reports print("###################### %s ###################" % unbracket(args.IP)) passive_dns = [] urls = [] malware = [] files = [] # MISP misp_e = plugins["misp"].test_config(conf) if misp_e: print("[+] Downloading MISP information...") server = ExpandedPyMISP(conf["Misp"]["url"], conf["Misp"]["key"]) misp_results = server.search("attributes", value=unbracket(args.IP)) # Binary Edge be_e = plugins["binaryedge"].test_config(conf) if be_e: try: print("[+] Downloading BinaryEdge information...") be = BinaryEdge(conf["BinaryEdge"]["key"]) # FIXME: this only get the first page res = be.domain_ip(unbracket(args.IP)) for d in res["events"]: passive_dns.append({ "domain": d["domain"], "first": parse(d["updated_at"]).astimezone(pytz.utc), "last": parse(d["updated_at"]).astimezone(pytz.utc), "source": "BinaryEdge", }) except BinaryEdgeException: print( "BinaryEdge request failed, you need a paid subscription" ) # OTX otx_e = plugins["otx"].test_config(conf) if otx_e: print("[+] Downloading OTX information....") otx = OTXv2(conf["AlienVaultOtx"]["key"]) res = otx.get_indicator_details_full( IndicatorTypes.IPv4, unbracket(args.IP)) otx_pulses = res["general"]["pulse_info"]["pulses"] # Get Passive DNS if "passive_dns" in res: for r in res["passive_dns"]["passive_dns"]: passive_dns.append({ "domain": r["hostname"], "first": parse(r["first"]).astimezone(pytz.utc), "last": parse(r["last"]).astimezone(pytz.utc), "source": "OTX", }) if "url_list" in res: for r in res["url_list"]["url_list"]: if "result" in r: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": r["result"]["urlworker"]["ip"] if "ip" in r["result"]["urlworker"] else "", "source": "OTX", }) else: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": "", "source": "OTX", }) # RobTex print("[+] Downloading Robtex information....") rob = Robtex() try: res = rob.get_ip_info(unbracket(args.IP)) except RobtexError: print("Error with Robtex") else: for d in ["pas", "pash", "act", "acth"]: if d in res: for a in res[d]: passive_dns.append({ "first": a["date"].astimezone(pytz.utc), "last": a["date"].astimezone(pytz.utc), "domain": a["o"], "source": "Robtex", }) # PT pt_e = plugins["pt"].test_config(conf) if pt_e: out_pt = False print("[+] Downloading Passive Total information....") client = DnsRequest(conf["PassiveTotal"]["username"], conf["PassiveTotal"]["key"]) try: raw_results = client.get_passive_dns( query=unbracket(args.IP)) if "results" in raw_results: for res in raw_results["results"]: passive_dns.append({ "first": parse(res["firstSeen"]).astimezone( pytz.utc), "last": parse(res["lastSeen"]).astimezone( pytz.utc), "domain": res["resolve"], "source": "PT", }) if "message" in raw_results: if "quota_exceeded" in raw_results["message"]: print("Quota exceeded for Passive Total") out_pt = True pt_osint = {} except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") if not out_pt: try: client2 = EnrichmentRequest( conf["PassiveTotal"]["username"], conf["PassiveTotal"]["key"], ) # Get OSINT # TODO: add PT projects here pt_osint = client2.get_osint( query=unbracket(args.IP)) # Get malware raw_results = client2.get_malware( query=unbracket(args.IP)) if "results" in raw_results: for r in raw_results["results"]: malware.append({ "hash": r["sample"], "date": parse(r["collectionDate"]), "source": "PT (%s)" % r["source"], }) except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") # Urlhaus uh_e = plugins["urlhaus"].test_config(conf) if uh_e: print("[+] Checking urlhaus data...") try: urlhaus = UrlHaus(conf["UrlHaus"]["key"]) res = urlhaus.get_host(unbracket(args.IP)) except UrlHausError: print("Error with the query") else: if "urls" in res: for r in res["urls"]: urls.append({ "date": parse(r["date_added"]).astimezone( pytz.utc), "url": r["url"], "source": "UrlHaus", }) # VT vt_e = plugins["vt"].test_config(conf) if vt_e: if conf["VirusTotal"]["type"] != "public": print("[+] Downloading VT information....") vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_ip_report(unbracket(args.IP)) if "results" in res: if "resolutions" in res["results"]: for r in res["results"]["resolutions"]: passive_dns.append({ "first": parse(r["last_resolved"]).astimezone( pytz.utc), "last": parse(r["last_resolved"]).astimezone( pytz.utc), "domain": r["hostname"], "source": "VT", }) if "undetected_downloaded_samples" in res[ "results"]: for r in res["results"][ "undetected_downloaded_samples"]: files.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) if "undetected_referrer_samples" in res["results"]: for r in res["results"][ "undetected_referrer_samples"]: if "date" in r: files.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) else: # FIXME : should consider data without dates files.append({ "hash": r["sha256"], "date": datetime.datetime(1970, 1, 1), "source": "VT", }) if "detected_downloaded_samples" in res["results"]: for r in res["results"][ "detected_downloaded_samples"]: malware.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) if "detected_referrer_samples" in res["results"]: for r in res["results"][ "detected_referrer_samples"]: if "date" in r: malware.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) else: vt_e = False print("[+] Downloading GreyNoise information....") gn = GreyNoise(conf["GreyNoise"]["key"]) if gn == "": print("Greynoise API key is not set up.") greynoise = gn.ip(unbracket(args.IP)) tg_e = plugins["threatgrid"].test_config(conf) if tg_e: print("[+] Downloading Threat Grid....") try: tg = ThreatGrid(conf["ThreatGrid"]["key"]) res = tg.search_samples(unbracket(args.IP), type="ip") already = [] if "items" in res: for r in res["items"]: if r["sample_sha256"] not in already: d = parse(r["ts"]) d = d.replace(tzinfo=None) malware.append({ "hash": r["sample_sha256"], "date": d, "source": "TG", }) already.append(r["sample_sha256"]) except ThreatGridError as e: print("Error with threat grid: {}".format(e.message)) # ThreatMiner print("[+] Downloading ThreatMiner....") tm = ThreatMiner() response = tm.get_report(unbracket(args.IP)) if response["status_code"] == "200": tmm = response["results"] else: tmm = [] if response["status_code"] != "404": print("Request to ThreatMiner failed: {}".format( response["status_message"])) response = tm.get_related_samples(unbracket(args.IP)) if response["status_code"] == "200": for r in response["results"]: malware.append({ "hash": r, "date": None, "source": "ThreatMiner" }) print("----------------- Intelligence Report") ctor = CommandTor() tor_list = ctor.get_list() if tor_list: if unbracket(args.IP) in tor_list: print("{} is a Tor Exit node".format(unbracket( args.IP))) else: print("Impossible to reach the Tor Exit Node list") if otx_e: if len(otx_pulses): print("OTX:") for p in otx_pulses: print("- %s (%s - %s)" % ( p["name"], p["created"][:10], "https://otx.alienvault.com/pulse/" + p["id"], )) else: print("OTX: Not found in any pulse") if misp_e: if len(misp_results["Attribute"]) > 0: print("MISP:") for event in misp_results["Attribute"]: print("- {} - {}".format(event["Event"]["id"], event["Event"]["info"])) if len(greynoise) > 0: print("GreyNoise: IP identified as") for key, value in greynoise.items(): print(key, "->", value) else: print("GreyNoise: Not found") if pt_e: if "results" in pt_osint: if len(pt_osint["results"]): if len(pt_osint["results"]) == 1: if "name" in pt_osint["results"][0]: print("PT: %s %s" % ( pt_osint["results"][0]["name"], pt_osint["results"][0]["sourceUrl"], )) else: print("PT: %s" % pt_osint["results"][0]["sourceUrl"]) else: print("PT:") for r in pt_osint["results"]: if "name" in r: print("-%s %s" % (r["name"], r["sourceUrl"])) else: print("-%s" % r["sourceUrl"]) else: print("PT: Nothing found!") else: print("PT: Nothing found!") # ThreatMiner if len(tmm) > 0: print("ThreatMiner:") for r in tmm: print("- {} {} - {}".format(r["year"], r["filename"], r["URL"])) if len(malware) > 0: print("----------------- Malware") for r in malware: print("[%s] %s %s" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") if r["date"] else "", )) if len(files) > 0: print("----------------- Files") for r in sorted(files, key=lambda x: x["date"]): print("[%s] %s %s" % (r["source"], r["hash"], r["date"].strftime("%Y-%m-%d"))) if len(passive_dns) > 0: print("----------------- Passive DNS") for r in sorted(passive_dns, key=lambda x: x["first"], reverse=True): print("[+] %-40s (%s -> %s)(%s)" % ( r["domain"], r["first"].strftime("%Y-%m-%d"), r["last"].strftime("%Y-%m-%d"), r["source"], )) if len(urls) > 0: print("----------------- Urls") for r in sorted(urls, key=lambda x: x["date"], reverse=True): print("[%s] %s - %s" % (r["source"], r["url"], r["date"].strftime("%Y-%m-%d"))) else: self.parser.print_help() else: self.parser.print_help()