def test_scan_url(self): vt = PublicApi(API_KEY) try: print(json.dumps(vt.scan_url('www.wired.com'), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def analyze_domain(domain): if domain in os.listdir(SCAN_RESULT_DIR): return print(domain) vt = VirusTotalPublicApi(API_KEY) domain_response = vt.get_domain_report(domain) if 'results' not in domain_response.keys(): print(' - ERROR results not in domain_response keys') return True if domain_response['results']['verbose_msg'] == 'Domain not found': print(' - ERROR Domain not found') return True url_response = vt.get_url_report(domain) if 'results' not in url_response.keys(): print(' - ERROR results not in url_response keys') return True if 'verbose_msg' in url_response['results'].keys() and url_response['results']['verbose_msg'] == 'Resource does not exist in the dataset': vt.scan_url(domain) print(' - resource does not exist: asking scan') return False results = domain_response['results'] if 'Websense ThreatSeeker category' in results.keys(): url_response['Websense ThreatSeeker category'] = results['Websense ThreatSeeker category'] if 'categories' in results.keys(): url_response['categories'] = results['categories'] if 'TrendMicro category' in results.keys(): url_response['TrendMicro category'] = results['TrendMicro category'] with open(os.path.join(SCAN_RESULT_DIR, domain), 'w') as data_file: data_file.write(json.dumps(url_response)) return True
def analize_url(url: str) -> json: """ Peticion a la API de vt para que analize una url asociada a un fichero :param url: :return: """ vt = VirusTotalPublicApi(VIRUSTOTAL_API_KEY) response = vt.scan_url(url) return json.dumps(response, sort_keys=False)
def test_scan_url(self): vt = PublicApi(API_KEY) try: print json.dumps(vt.scan_url('www.wired.com'), sort_keys=False, indent=4) except Exception as e: self.fail(e)
def link_to_virustotal(link, pkt): ''' IN CASE WE FOUND GET link, WE SCAN IT ''' print 'SCANNING %s'%link virus_total_instance = PublicApi('2e1d7b6e998ed0a9830269571ecffa110e41dd8bf34b88ad41e40b4351165d18') REQ = virus_total_instance.scan_url(link) print 'Waiting for virustotal' while True: if 'Scan finished' in str(virus_total_instance.get_url_report(link)): print 'Scan finished!' REP = virus_total_instance.get_url_report(link)['results']['positives'] break else: print 'Naaa not yet' if REP == '0' or REP == 0: print 'SCANNED %s - VERDICT OK [REP=%s]'%(link,REP) pkt.accept() else: print 'SCANNED %s - VERDICT KO [REP=%s]'%(link,REP) pkt.drop() '''
def main(url): apikey = fetchapikey() vt = VirusTotalPublicApi(apikey) response = vt.scan_url(url) reply = [] if "error" in response.keys(): respcode="0x01" permlink="Report permalink could not be fetched due to an error" resource="Resource could not be fetched due to an error" scandate="Scan date could not be fetched due to an error" scanidty="Scan ID could not be fetched due to an error" verbmesg="Please check your internet connection and the URL for typos and try again" reply=[respcode,permlink,resource,scandate,scanidty,verbmesg] else: respcode=str(response["response_code"]) permlink=str(response["results"]["permalink"]) resource=str(response["results"]["resource"]) scandate=str(response["results"]["scan_date"]) scanidty=str(response["results"]["scan_id"]) verbmesg=str(response["results"]["verbose_msg"]) reply=[respcode,permlink,resource,scandate,scanidty,verbmesg] return reply
def _virustotal_function(self, event, *args, **kwargs): """Function: perform different scans on the following types: ip addresses hash - this will attempt to find an existing file report on the hash domain url - this will attempt to find an existing file report on the url. If none exist, a new scan is queued file - this will start a new scan for the file and queue for a report later. """ try: validateFields(('incident_id', 'vt_type'), kwargs) # required # Init RequestsCommon with app.config options rc = RequestsCommon(opts=self.opts, function_opts=self.options) # Create a VirusTotal instance with the API Token and any proxies gathered by RequestsCommon vt = VirusTotal(self.options['api_token'], rc.get_proxies()) # Get the function parameters: incident_id = kwargs.get("incident_id") # number artifact_id = kwargs.get("artifact_id") # number attachment_id = kwargs.get("attachment_id") # number vt_type = kwargs.get("vt_type") # text vt_data = kwargs.get("vt_data") # text self.log = logging.getLogger(__name__) self.log.info("incident_id: %s", incident_id) self.log.info("artifact_id: %s", artifact_id) self.log.info("attachment_id: %s", attachment_id) self.log.info("vt_type: %s", vt_type) self.log.info("vt_data: %s", vt_data) yield StatusMessage("starting...") # determine next steps based on the API call to make if vt_type.lower() == 'file': entity = get_input_entity(get_resilient_client(self.resilient), incident_id, attachment_id, artifact_id) # Create a temporary file to write the binary data to. with tempfile.NamedTemporaryFile( 'w+b', delete=False) as temp_file_binary: # Write binary data to a temporary file. Make sure to close the file here...this # code must work on Windows and on Windows the file cannot be opened a second time # While open. Floss will open the file again to read the data, so close before # calling Floss. temp_file_binary.write(entity["data"]) temp_file_binary.close() try: response = vt.scan_file(temp_file_binary.name, filename=entity["name"]) except Exception as err: raise err finally: os.unlink(temp_file_binary.name) file_result = self.return_response(response, vt.get_file_report, time.time()) ## was a sha-256 returned? try an existing report first if file_result.get("sha256"): response = vt.get_file_report(file_result.get("sha256")) report_result = self.return_response( response, None, time.time()) if report_result.get( "response_code") and report_result.get( "response_code") == 1: result = report_result else: result = file_result elif vt_type.lower() == 'url': # attempt to see if a report already exists response = vt.get_url_report(vt_data) result = self.return_response(response, None, time.time()) # check if result is not found, meaning no report exists if result['response_code'] == RC_NOT_FOUND: response = vt.scan_url(vt_data) result = self.return_response(response, vt.get_url_report, time.time()) elif vt_type.lower() == 'ip': response = vt.get_ip_report(vt_data) result = self.return_response(response, None, time.time()) elif vt_type.lower() == 'domain': response = vt.get_domain_report(vt_data) result = self.return_response(response, None, time.time()) elif vt_type.lower() == 'hash': response = vt.get_file_report(vt_data) result = self.return_response(response, None, time.time()) else: raise ValueError( "Unknown type field: {}. Check workflow pre-processor script." .format(vt_type)) results = {"scan": result} self.log.debug("scan: {}".format(results)) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: yield FunctionError()
class VirusTotalAnalyzer(Analyzer): def __init__(self): Analyzer.__init__(self) self.service = self.get_param('config.service', None, 'Service parameter is missing') self.virustotal_key = self.get_param('config.key', None, 'Missing VirusTotal API key') self.polling_interval = self.get_param('config.polling_interval', 60) self.proxies = self.get_param('config.proxy', None) self.vt = VirusTotalPublicApi(self.virustotal_key, self.proxies) def wait_file_report(self, id): results = self.check_response(self.vt.get_file_report(id)) code = results.get('response_code', None) if code == 1: self.report(results) else: time.sleep(self.polling_interval) self.wait_file_report(id) def wait_url_report(self, id): results = self.check_response(self.vt.get_url_report(id)) code = results.get('response_code', None) if code == 1 and (results.get('scan_id') == id): self.report(results) else: time.sleep(self.polling_interval) self.wait_url_report(id) def check_response(self, response): if type(response) is not dict: self.error('Bad response : ' + str(response)) status = response.get('response_code', -1) if status == 204: self.error('VirusTotal api rate limit exceeded (Status 204).') if status != 200: self.error('Bad status : ' + str(status)) results = response.get('results', {}) if 'Missing IP address' in results.get('verbose_msg', ''): results['verbose_msg'] = 'IP address not available in VirusTotal' return results # 0 => not found # -2 => in queue # 1 => ready def read_scan_response(self, response, func): results = self.check_response(response) code = results.get('response_code', None) scan_id = results.get('scan_id', None) if code == 1 and scan_id is not None: func(scan_id) else: self.error('Scan not found') def summary(self, raw): taxonomies = [] level = "info" namespace = "VT" predicate = "GetReport" value = "0" if self.service == "scan": predicate = "Scan" result = { "has_result": True } if raw["response_code"] != 1: result["has_result"] = False result["positives"] = raw.get("positives", 0) result["total"] = raw.get("total", 0) if "scan_date" in raw: result["scan_date"] = raw["scan_date"] if self.service == "get": if "scans" in raw: result["scans"] = len(raw["scans"]) value = "{}/{}".format(result["positives"], result["total"]) if result["positives"] == 0: level = "safe" elif result["positives"] < 5: level = "suspicious" else: level = "malicious" if "resolutions" in raw: result["resolutions"] = len(raw["resolutions"]) value = "{} resolution(s)".format(result["resolutions"]) if result["resolutions"] == 0: level = "safe" elif result["resolutions"] < 5: level = "suspicious" else: level = "malicious" if "detected_urls" in raw: result["detected_urls"] = len(raw["detected_urls"]) value = "{} detected_url(s)".format(result["detected_urls"]) if result["detected_urls"] == 0: level = "safe" elif result["detected_urls"] < 5: level = "suspicious" else: level = "malicious" if "detected_downloaded_samples" in raw: result["detected_downloaded_samples"] = len( raw["detected_downloaded_samples"]) if self.service == "scan": if "scans" in raw: result["scans"] = len(raw["scans"]) value = "{}/{}".format(result["positives"], result["total"]) if result["positives"] == 0: level = "safe" elif result["positives"] < 5: level = "suspicious" else: level = "malicious" taxonomies.append(self.build_taxonomy(level, namespace, predicate, value)) return {"taxonomies": taxonomies} def run(self): if self.service == 'scan': if self.data_type == 'file': filename = self.get_param('filename', 'noname.ext') filepath = self.get_param('file', None, 'File is missing') self.read_scan_response( self.vt.scan_file(filepath, from_disk=True, filename=filename), self.wait_file_report ) elif self.data_type == 'url': data = self.get_param('data', None, 'Data is missing') self.read_scan_response( self.vt.scan_url(data), self.wait_url_report) else: self.error('Invalid data type') elif self.service == 'get': if self.data_type == 'domain': data = self.get_param('data', None, 'Data is missing') self.report(self.check_response( self.vt.get_domain_report(data))) elif self.data_type == 'fqdn': data = self.get_param('data', None, 'Data is missing') self.report(self.check_response( self.vt.get_domain_report(data))) elif self.data_type == 'ip': data = self.get_param('data', None, 'Data is missing') self.report(self.check_response(self.vt.get_ip_report(data))) elif self.data_type == 'file': hashes = self.get_param('attachment.hashes', None) if hashes is None: filepath = self.get_param('file', None, 'File is missing') hash = hashlib.sha256(open(filepath, 'rb').read()).hexdigest() else: # find SHA256 hash hash = next(h for h in hashes if len(h) == 64) self.report(self.check_response(self.vt.get_file_report(hash))) elif self.data_type == 'hash': data = self.get_param('data', None, 'Data is missing') self.report(self.check_response(self.vt.get_file_report(data))) elif self.data_type == 'url': data = self.get_param('data', None, 'Data is missing') self.report(self.check_response(self.vt.get_url_report(data))) else: self.error('Invalid data type') else: self.error('Invalid service')
class VirusTotalAnalyzer(Analyzer): def __init__(self): Analyzer.__init__(self) self.service = self.get_param("config.service", None, "Service parameter is missing") self.virustotal_key = self.get_param("config.key", None, "Missing VirusTotal API key") self.polling_interval = self.get_param("config.polling_interval", 60) self.rescan_hash_older_than_days = self.get_param( "config.rescan_hash_older_than_days", None) self.highlighted_antivirus = self.get_param( "config.highlighted_antivirus", None) self.download_sample = self.get_param("config.download_sample", False) self.download_sample_if_highlighted = self.get_param( "config.download_sample_if_highlighted", False) self.obs_path = None self.proxies = self.get_param("config.proxy", None) if (self.download_sample or self.download_sample_if_highlighted or self.service == "download"): self.vt_pay = PrivateApi(self.virustotal_key, self.proxies) self.vt = PublicApi(self.virustotal_key, self.proxies) def get_file(self, hash): self.obs_path = "{}/{}".format(tempfile.gettempdir(), hash) response = self.vt_pay.get_file(hash) if response.get("response_code", None) == 200: with open(self.obs_path, "wb") as f: f.write(response["results"]) kind = filetype.guess(self.obs_path) if kind and kind.extension != None: os.rename(self.obs_path, "{}.{}".format(self.obs_path, kind.extension)) self.obs_path = "{}.{}".format(self.obs_path, kind.extension) def wait_file_report(self, id): results = self.check_response(self.vt.get_file_report(id)) code = results.get("response_code", None) if code == 1: if self.data_type == "hash" and ( self.download_sample or (self.download_sample_if_highlighted and self.highlighted_antivirus and any([ results.get("scans", {}).get(av, {}).get( "detected", None) == False for av in self.highlighted_antivirus ]))): self.get_file(self.get_param("data", None, "Data is missing")) self.report(results) else: time.sleep(self.polling_interval) self.wait_file_report(id) def wait_url_report(self, id): results = self.check_response(self.vt.get_url_report(id)) code = results.get("response_code", None) if code == 1 and (results.get("scan_id") == id): self.report(results) else: time.sleep(self.polling_interval) self.wait_url_report(id) def check_response(self, response): if type(response) is not dict: self.error("Bad response : " + str(response)) status = response.get("response_code", -1) if status == 204: self.error("VirusTotal api rate limit exceeded (Status 204).") if status != 200: self.error("Bad status : " + str(status)) results = response.get("results", {}) if "Missing IP address" in results.get("verbose_msg", ""): results["verbose_msg"] = "IP address not available in VirusTotal" return results # 0 => not found # -2 => in queue # 1 => ready def read_scan_response(self, response, func): results = self.check_response(response) code = results.get("response_code", None) scan_id = results.get("scan_id", None) if code == 1 and scan_id is not None: func(scan_id) else: self.error("Scan not found") def artifacts(self, raw): artifacts = [] if self.obs_path: tags = [] # This will work only in scan/rescan workflow, not in download only if self.highlighted_antivirus: for av in self.highlighted_antivirus: detected = raw.get("scans", {}).get(av, {}).get("detected", None) if detected == False: tags.append("to_{}".format(av)) artifacts.append( self.build_artifact("file", self.obs_path, tags=tags)) return artifacts def summary(self, raw): taxonomies = [] level = "info" namespace = "VT" predicate = "GetReport" value = "0" if self.service == "scan": predicate = "Scan" elif self.service == "rescan": predicate = "Rescan" elif self.service == "download": return {"taxonomies": taxonomies} result = {"has_result": True} if raw["response_code"] != 1: result["has_result"] = False result["positives"] = raw.get("positives", 0) result["total"] = raw.get("total", 0) if "scan_date" in raw: result["scan_date"] = raw["scan_date"] if self.service == "get": if "scans" in raw: result["scans"] = len(raw["scans"]) value = "{}/{}".format(result["positives"], result["total"]) if result["positives"] == 0: level = "safe" elif result["positives"] < 5: level = "suspicious" else: level = "malicious" if "resolutions" in raw: result["resolutions"] = len(raw["resolutions"]) value = "{} resolution(s)".format(result["resolutions"]) if result["resolutions"] == 0: level = "safe" elif result["resolutions"] < 5: level = "suspicious" else: level = "malicious" if "detected_urls" in raw: result["detected_urls"] = len(raw["detected_urls"]) value = "{} detected_url(s)".format(result["detected_urls"]) if result["detected_urls"] == 0: level = "safe" elif result["detected_urls"] < 5: level = "suspicious" else: level = "malicious" if "detected_downloaded_samples" in raw: result["detected_downloaded_samples"] = len( raw["detected_downloaded_samples"]) if self.service in ["scan", "rescan"]: if "scans" in raw: result["scans"] = len(raw["scans"]) value = "{}/{}".format(result["positives"], result["total"]) if result["positives"] == 0: level = "safe" elif result["positives"] < 5: level = "suspicious" else: level = "malicious" taxonomies.append( self.build_taxonomy(level, namespace, predicate, value)) if self.highlighted_antivirus: for av in self.highlighted_antivirus: detected = raw.get("scans", {}).get(av, {}).get("detected", None) if detected == False: taxonomies.append( self.build_taxonomy("info", namespace, av, "Not detected!")) return {"taxonomies": taxonomies} def run(self): if self.service == "scan": if self.data_type == "file": filename = self.get_param("filename", "noname.ext") filepath = self.get_param("file", None, "File is missing") self.read_scan_response( self.vt.scan_file(filepath, from_disk=True, filename=filename), self.wait_file_report, ) elif self.data_type == "url": data = self.get_param("data", None, "Data is missing") self.read_scan_response(self.vt.scan_url(data), self.wait_url_report) else: self.error("Invalid data type") elif self.service == "rescan": if self.data_type == "hash": data = self.get_param("data", None, "Data is missing") self.read_scan_response(self.vt.rescan_file(data), self.wait_file_report) else: self.error("Invalid data type") elif self.service == "download": if self.data_type == "hash": data = self.get_param("data", None, "Data is missing") self.get_file(data) self.report({"message": "file downloaded"}) elif self.service == "get": if self.data_type == "domain": data = self.get_param("data", None, "Data is missing") results = self.check_response(self.vt.get_domain_report(data)) elif self.data_type == "fqdn": data = self.get_param("data", None, "Data is missing") results = self.check_response(self.vt.get_domain_report(data)) elif self.data_type == "ip": data = self.get_param("data", None, "Data is missing") results = self.check_response(self.vt.get_ip_report(data)) elif self.data_type == "file": hashes = self.get_param("attachment.hashes", None) if hashes is None: filepath = self.get_param("file", None, "File is missing") hash = hashlib.sha256(open(filepath, "rb").read()).hexdigest() else: hash = next(h for h in hashes if len(h) == 64) results = self.check_response(self.vt.get_file_report(hash)) elif self.data_type == "hash": data = self.get_param("data", None, "Data is missing") results = self.check_response(self.vt.get_file_report(data)) elif self.data_type == "url": data = self.get_param("data", None, "Data is missing") results = self.check_response(self.vt.get_url_report(data)) else: self.error("Invalid data type") # if aged and enabled rescan if self.data_type == "hash" and self.rescan_hash_older_than_days: if (datetime.strptime(results["scan_date"], "%Y-%m-%d %H:%M:%S") - datetime.now() ).days > self.rescan_hash_older_than_days: self.read_scan_response(self.vt.rescan_file(data), self.wait_file_report) # download if hash, dangerous and not seen by av if (self.data_type == "hash" and (results.get("response_code", None) == 1) and (results.get("positives", 0) >= 5) and (self.download_sample or (self.download_sample_if_highlighted and self.highlighted_antivirus and any([ results.get("scans", {}).get(av, {}).get( "detected", None) == False for av in self.highlighted_antivirus ])))): self.get_file(data) self.report(results) else: self.error("Invalid service")