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()
def run(self, conf, args, plugins): if 'subcommand' in args: if conf["VirusTotal"]["type"] != "public": vt = PrivateApi(conf["VirusTotal"]["key"]) if args.subcommand == "hash": response = vt.get_file_report(args.HASH) if args.raw: print(json.dumps(response, sort_keys=False, indent=4)) if args.extended: response = vt.get_network_traffic(args.HASH) print( json.dumps(response, sort_keys=False, indent=4)) response = vt.get_file_behaviour(args.HASH) print( json.dumps(response, sort_keys=False, indent=4)) else: self.print_file(response) elif args.subcommand == "dl": if os.path.isfile(args.HASH): print("File %s already exists" % args.HASH) sys.exit(0) data = vt.get_file(args.HASH) if isinstance(data, dict): if 'results' in data: with open(args.HASH, "wb") as f: f.write(data['results']) print("File downloaded as %s" % args.HASH) else: print('Invalid answer format') sys.exit(1) else: with open(args.HASH, "wb") as f: f.write(data) print("File downloaded as %s" % args.HASH) elif args.subcommand == "file": with open(args.FILE, "rb") as f: # FIXME : could be more efficient data = f.read() m = hashlib.sha256() m.update(data) h = m.hexdigest() response = vt.get_file_report(h) if args.raw: print(json.dumps(response, sort_keys=False, indent=4)) else: self.print_file(response) elif args.subcommand == "hashlist": with open(args.FILE, 'r') as infile: data = infile.read().split() hash_list = list(set([a.strip() for a in data])) print( "Hash;Found;Detection;Total AV;First Seen;Last Seen;Link" ) for h in hash_list: response = vt.get_file_report(h) if response["response_code"] != 200: print("Error with the request (reponse code %i)" % response["response_code"]) print( json.dumps(response, sort_keys=False, indent=4)) print("Quitting...") sys.exit(1) if "response_code" in response["results"]: if response["results"]["response_code"] == 0: print("%s;Not found;;;;;" % h) else: print("%s;Found;%i;%i;%s;%s;%s" % (h, response["results"]["positives"], response["results"]["total"], response["results"]["first_seen"], response["results"]["last_seen"], response["results"]["permalink"])) else: print("%s;Not found;;;;;" % h) elif args.subcommand == "domainlist": with open(args.FILE, 'r') as infile: data = infile.read().split() for d in data: print("################ Domain %s" % d.strip()) res = vt.get_domain_report(d.strip()) self.print_domaininfo(res) elif args.subcommand == "iplist": with open(args.FILE, 'r') as infile: data = infile.read().split() for d in data: print("################ IP %s" % d.strip()) res = vt.get_ip_report(unbracket(d.strip())) print(json.dumps(res, sort_keys=False, indent=4)) elif args.subcommand == "domain": res = vt.get_domain_report(unbracket(args.DOMAIN)) if args.json: print(json.dumps(res, sort_keys=False, indent=4)) else: self.print_domaininfo(res) elif args.subcommand == "ip": res = vt.get_ip_report(unbracket(args.IP)) print(json.dumps(res, sort_keys=False, indent=4)) elif args.subcommand == "url": res = vt.get_url_report(args.URL) print(json.dumps(res, sort_keys=False, indent=4)) else: self.parser.print_help() else: vt = PublicApi(conf["VirusTotal"]["key"]) if args.subcommand == "hash": response = vt.get_file_report(args.HASH) if args.raw: print(json.dumps(response, sort_keys=False, indent=4)) else: self.print_file(response) elif args.subcommand == "file": with open(args.FILE, "rb") as f: # FIXME : could be more efficient data = f.read() m = hashlib.sha256() m.update(data) response = vt.get_file_report(m.hexdigest()) if args.raw: print(json.dumps(response, sort_keys=False, indent=4)) else: self.print_file(response) elif args.subcommand == "hashlist": with open(args.FILE, 'r') as infile: data = infile.read().split() hash_list = list(set([a.strip() for a in data])) print("Hash;Found;Detection;Total AV;Link") for h in hash_list: response = vt.get_file_report(h) if response["response_code"] != 200: print("Error with the request (reponse code %i)" % response["response_code"]) print( json.dumps(response, sort_keys=False, indent=4)) print("Quitting...") sys.exit(1) if "response_code" in response["results"]: if response["results"]["response_code"] == 0: print("%s;Not found;;;" % h) else: print("%s;Found;%i;%i;%s" % (h, response["results"]["positives"], response["results"]["total"], response["results"]["permalink"])) else: print("%s;Not found;;;" % h) elif args.subcommand == "domain": res = vt.get_domain_report(unbracket(args.DOMAIN)) if args.json: print(json.dumps(res, sort_keys=False, indent=4)) else: self.print_domaininfo(res) elif args.subcommand == "ip": res = vt.get_ip_report(unbracket(args.IP)) print(json.dumps(res, sort_keys=False, indent=4)) elif args.subcommand == "url": res = vt.get_url_report(args.URL) print(json.dumps(res, sort_keys=False, indent=4)) elif args.subcommand == "domainlist": print( "Not implemented yet with public access, please propose PR if you need it" ) elif args.subcommand == "dl": print( "VirusTotal does not allow downloading files with a public feed, sorry" ) sys.exit(0) else: self.parser.print_help() else: self.parser.print_help()
def intel(self, type, query, data, conf): if type == "domain": if conf["VirusTotal"]["type"] != "public": print("[+] Checking VirusTotal....") vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_domain_report(query) if "results" in res: if "resolutions" in res["results"]: for r in res["results"]["resolutions"]: try: data["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", }) except TypeError: # Error with the date pass if "undetected_downloaded_samples" in res["results"]: for r in res["results"][ "undetected_downloaded_samples"]: data["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"]: data["files"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc) if "date" in r else "", "source": "VT", }) if "undetected_communicating_samples" in res["results"]: for r in res["results"][ "undetected_communicating_samples"]: data["malware"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc), "source": "VT" }) if "detected_communicating_samples" in res["results"]: for r in res["results"][ "detected_communicating_samples"]: data["malware"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc), "source": "VT" }) if "detected_downloaded_samples" in res["results"]: for r in res["results"]["detected_downloaded_samples"]: data["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: data["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"]: data["urls"].append({ "date": parse(r["scan_date"]).astimezone(pytz.utc), "url": r["url"], "ip": "", "source": "VT", }) elif type == "ip": if conf["VirusTotal"]["type"] != "public": print("[+] Checking VirusTotal...") vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_ip_report(query) if "results" in res: if "resolutions" in res["results"]: for r in res["results"]["resolutions"]: try: data["passive_dns"].append({ "first": parse(r["last_resolved"]).astimezone( pytz.utc), "last": parse(r["last_resolved"]).astimezone( pytz.utc), "domain": r["hostname"], "source": "VT", }) except TypeError: # Error with the date pass if "undetected_downloaded_samples" in res["results"]: for r in res["results"][ "undetected_downloaded_samples"]: data["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"]: data["files"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc) if "date" in r else "", "source": "VT", }) if "undetected_communicating_samples" in res["results"]: for r in res["results"][ "undetected_communicating_samples"]: data["malware"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc), "source": "VT", }) if "detected_communicating_samples" in res["results"]: for r in res["results"][ "detected_communicating_samples"]: data["malware"].append({ "hash": r["sha256"], "date": parse(r["date"]).astimezone(pytz.utc), "source": "VT", }) if "detected_downloaded_samples" in res["results"]: for r in res["results"]["detected_downloaded_samples"]: data["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"]: data["urls"].append({ "date": parse(r["scan_date"]).astimezone(pytz.utc), "url": r["url"], "ip": "", "source": "VT", }) elif type == "hash": if conf["VirusTotal"]["type"] != "public": print("[+] Checking VirusTotal...") vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_file_report(query) if res["results"]["response_code"] == 1: # Found data["samples"].append({ "date": parse(res['results']['scan_date']).astimezone( pytz.utc), "source": "VT", "url": res['results']['permalink'], "infos": { "AV Result": "{} / {}".format(res['results']['positives'], res['results']['total']), "First Seen": res['results']["first_seen"], "File Names": ", ".join(res['results']["submission_names"][:5]) } }) if "ITW_urls" in res["results"]: for url in res['results']["ITW_urls"]: data["urls"].append({ "url": url, "source": "VT", "link": res['results']['permalink'] }) if "additional_info" in res["results"]: if "behaviour-v1" in res["results"]["additional_info"]: if "network" in res['results']['additional_info'][ 'behaviour-v1']: for d in res['results']['additional_info'][ 'behaviour-v1']["network"]["dns"]: data["network"].append({ "source": "VT", "url": res['results']['permalink'], "host": d["hostname"], "ip": d["ip"] })
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()