def vturl(vt, client, urlstring, stringvt): """ vturl request vt api for url and return mardown string with informations from vt. :param vt:virus total import :param client:virustotal client api :param urlstring:string with the url to request :param stringvt:string to concatenate return """ url_id = vt.url_id(urlstring) url = client.get_object("/urls/{}".format(url_id)) stringvt = '\n'.join([ stringvt, "* first_submission_date: {}".format(url.first_submission_date) ]) stringvt = '\n'.join( [stringvt, "* last_analysis_date: {}".format(url.last_analysis_date)]) stringvt = '\n'.join([stringvt, "* categories: {}".format(url.categories)]) stringvt = '\n'.join([ stringvt, "* last_analysis_stats: {}".format(url.last_analysis_stats) ]) stringvt = '\n'.join( [stringvt, "* total_votes: {}".format(url.total_votes)]) stringvt = '\n'.join([ stringvt, "* [VirusTotal source link](https://www.virustotal.com/gui/url/{}/detection)" .format(url_id) ]) return stringvt, url.last_analysis_stats
def get_url_lookup(self, url: str) -> Optional[Dict[str, Any]]: url_storage_dir = get_cache_directory(self.storage_dir_vt, vt.url_id(url)) if not url_storage_dir.exists(): return None cached_entries = sorted(url_storage_dir.glob('*'), reverse=True) if not cached_entries: return None with cached_entries[0].open() as f: return json.load(f)
def run(self, indicators, indicator_type, maximum): """ Utilises the vt-py library to query and store results relating to threat intelligence observables from the VirusTotal v3 API. """ if maximum > 500: print(f'[VirusTotal] {maximum} > 500 | maximum of 500 API calls a day for free accounts') maximum = 500 if indicator_type not in self.supported_indicators: print(f'[VirusTotal] does not support {indicator_type}') exit() if indicator_type not in indicators: print(f'[VirusTotal] {indicator_type} not found in provided observables') exit() print(f'[VirusTotal] Querying a maximum of {maximum} out of {len(indicators[indicator_type])} {indicator_type}') count = 0 for i in indicators[indicator_type]: if count == maximum: break # used to get an indicator when in format {value, source} if isinstance(i, dict): i = i['value'] # required from vt-py if indicator_type == "urls": i = vt.url_id(i) try: req = f'/{self.supported_indicators[indicator_type]}/{i}' res = self.vt_client.get_object(req) print(f"[VirusTotal] Success! {i}") self.output[indicator_type][i] = {} self.output[indicator_type][i]['last_analysis_stats'] = res.last_analysis_stats self.output[indicator_type][i]['last_analysis_results'] = res.last_analysis_results # note: according to the docs, virustotal has a 4req/min limit, but I have not encountered any rate limit # if this becomes an issue in the future, put a sleep() here except vt.error.APIError as e: if e.code == 'NotFoundError': print(f"[VirsTotal] Failure! {i}") pass else: print("[VirusTotal] API Error:", e) continue except Exception as e: print("[VirusTotal] Something unexpected went wrong: ", e) count += 1 self.vt_client.close() print("[VirusTotal] complete")
def send_url(self, string): try: url_id = vt.url_id(string) url = self.client.get_object(f"/urls/{url_id}") return self.get_data(url.last_analysis_stats) except Exception as e: try: if 'NotFoundError' in str(e): analysis = self.client.scan_url(string) return self._wait(analysis) except Exception as e: if 'InvalidArgumentError' in str(e): return {"type":"error","message":'not valid url', 'name' : self.__class__.__name__ }
def url_lookup(self, url: str, force: bool = False) -> None: '''Lookup an URL on VT Note: force means 2 things: * (re)scan of the URL * re fetch the object from VT even if we already did it today Note: the URL will only be sent for scan if autosubmit is set to true in the config ''' if not self.available: raise ConfigError('VirusTotal not available, probably no API key') url_storage_dir = get_cache_directory(self.storage_dir_vt, vt.url_id(url)) url_storage_dir.mkdir(parents=True, exist_ok=True) vt_file = url_storage_dir / date.today().isoformat() scan_requested = False if self.autosubmit and force: self.client.scan_url(url) scan_requested = True if not force and vt_file.exists(): return url_id = vt.url_id(url) for _ in range(3): try: url_information = self.client.get_object(f"/urls/{url_id}") with vt_file.open('w') as _f: json.dump(url_information.to_dict(), _f) break except APIError as e: if not self.autosubmit: break if not scan_requested and e.code == 'NotFoundError': self.client.scan_url(url) scan_requested = True time.sleep(5)
def scanning(URL): import vt import nest_asyncio flag=0 nest_asyncio.apply() client = vt.Client("<API KEY>") url_id = vt.url_id(URL) url = client.get_object("/urls/{}".format(url_id)) result = url.last_analysis_stats for i in result: if i==1 and result[i]>0: flag = 1 if i==2 and result[i]>0: flag=1 return flag
def url_lookup(self, url: str): if not self.available: raise ConfigError('VirusTotal not available, probably no API key') url_id = vt.url_id(url) m = hashlib.md5() m.update(url_id.encode()) url_storage_dir = self.storage_dir_vt / m.hexdigest() url_storage_dir.mkdir(parents=True, exist_ok=True) vt_file = url_storage_dir / date.today().isoformat() if vt_file.exists(): return try: url_information = self.client.get_object(f"/urls/{url_id}") with vt_file.open('w') as _f: json.dump(url_information.to_dict(), _f) except vt.APIError as e: if self.autosubmit and e.code == 'NotFoundError': self.client.scan_url(url)
def __get_cache_directory(self, url: str) -> Path: url_id = vt.url_id(url) m = hashlib.md5() m.update(url_id.encode()) return self.storage_dir_vt / m.hexdigest()
if is_ioc_hash: # Convert hash to lower-case for consistency ioc = ioc.lower() args['ioc'] = ioc.lower() print( "[*] Use VT API to get info on hash ioc: {ioc}".format(**args)) ioc_info = client.get_object("/files/" + ioc) else: args['ioc'] = ioc print( "[*] Use VT API to get info on url ioc: {ioc}".format(**args)) url_id = vt.url_id(ioc) ioc_info = client.get_object("/urls/{}", url_id) print("[+] IOC: {ioc} Analysis".format(**args)) print(json.dumps(ioc_info.last_analysis_stats, indent=4)) if args['avs']: print("[+] IOC: {ioc} AV detections".format(**args)) print(json.dumps(ioc_info.last_analysis_results, indent=4)) if args['all']: print("[+] IOC: {ioc} All Info".format(**args)) print(json.dumps(ioc_info.to_dict(), indent=4)) except Exception as e: args['err'] = str(e)