def check_file(key, file): msg() # prints scanning message scanner = Virustotal(key) # passing api key to Virustotal class scanner.file_scan(file) # scans the file for virus with open(file, 'rb') as f: # opens file in read binary mode read = f.read() # reads opened file file_hash = hashlib.sha256(read).hexdigest() # Get sha256 hash of file report = scanner.file_report([file_hash]) # passing hash value of file to file_report function and returns report try: print('\n\nREPORT:\nStatus code:', report['status_code']) # Prints all the reports print('Scan date:', report['json_resp']['scan_date']) print('Verbose msg:', report['json_resp']['verbose_msg']) print('Antivirus Scanned:', report['json_resp']['total']) print('Positives:', report['json_resp']['positives']) print('sha256:', report['json_resp']['sha256']) print('md5:', report['json_resp']['md5']) except KeyError: print('\n""Maximum four scans per minute""')
from virustotal_python import Virustotal from pprint import pprint from json2html import * import json vtotal = Virustotal( "50473a41f47913496c613e67dee646f6a36ebf434ce4e99fec30198f5014d29c") resp = vtotal.file_report( ["09de776902ca7d32abdab8a7ccd177fb917addf502bd4bd5aa25a93ab41cc869"]) data = json.dumps(resp) data = data.replace("'", '"') html_parser = json2html.convert(json=data) with open("./templates/program/data_tep.html", "w") as f: f.write(html_parser)
class StartModule(): def __init__(self): self._main_gui_func_ = 'isBadFile' self.__gui_label__ = 'Virustotal Search' def help(self): Logger.printMessage( message=ht.getFunctionsNamesFromModule('ht_virustotal'), debug_module=True) def isBadFileHash(self, fileHash, virustotal_api=None, session_id=None): try: if not virustotal_api: virustotal_api = ht.Config.getAPIKey('virustotal_api', session_id) self.vtotal = Virustotal(virustotal_api) resp = self.vtotal.file_report([fileHash]) if resp["status_code"] in (200, 204): if resp["status_code"] == 204: Logger.printMessage( message="isBadFileHash", description="Testing - {hash} - Waiting 2 seconds...". format(hash=fileHash), debug_module=True) time.sleep(2) return self.isBadFileHash(fileHash, virustotal_api) while resp["json_resp"]["response_code"] == -2: Logger.printMessage( message="isBadFileHash", description="Testing - {hash} - Waiting 2 seconds...". format(hash=fileHash), debug_module=True) time.sleep(2) return self.isBadFileHash(fileHash, virustotal_api) no_detected_list = [] detected_list = [] detected_types = [] for antivirus in resp["json_resp"]["scans"]: if resp["json_resp"]["scans"][antivirus]["detected"]: detected_list.append( (antivirus, resp["json_resp"]["scans"][antivirus]["version"])) if not resp["json_resp"]["scans"][antivirus][ "result"] in detected_types: detected_types.append(resp["json_resp"]["scans"] [antivirus]["result"]) else: no_detected_list.append( (antivirus, resp["json_resp"]["scans"][antivirus]["version"])) if detected_list: data = {} data["detected_list"] = detected_list data["detected_types"] = detected_types data["no_detected_list"] = no_detected_list return json.dumps({"Detected": data}, indent=4, sort_keys=True) return json.dumps({"No detected": no_detected_list}, indent=4, sort_keys=True) return resp except Exception as e: Logger.printMessage(message="isBadFileHash", description=str(e), is_error=True) return str(e) def isBadFile(self, filename, virustotal_api=None): try: if not virustotal_api: virustotal_api = ht.Config.config['API']['virustotal'] Logger.printMessage(message="isBadFile", description=filename, debug_module=True) self.vtotal = Virustotal(virustotal_api) response = self.vtotal.file_scan(filename) if response["status_code"] == 200: scan_id = str(response["json_resp"]["scan_id"]) time.sleep(2) resp = self.isBadFileHash(scan_id, virustotal_api) return resp except Exception as e: Logger.printMessage(message="isBadFile", description=str(e), is_error=True) return str(e)
def main(): parser = argparse.ArgumentParser( description= "Scan a single file in VirusTotal and waits until report is complete") parser.add_argument('file', help='File to be scanned') args = parser.parse_args() if 'VT_API_KEY' not in os.environ: LOGGER.error('VT_API_KEY environment variable not set.') sys.exit(SCAN_ERROR) LOGGER.debug('Initialzing VirusTotal API') vt_api_key = os.environ['VT_API_KEY'] vt = Virustotal(vt_api_key) # Hash file LOGGER.info('Checking if report already exists via file hash.') file_hash = sha256sum(args.file) try: response = vt.file_report([file_hash]) except ConnectionError as e: err_str = str(e) LOGGER.error(f"Connection error to VT: {err_str}.") sys.exit(SCAN_ERROR) ret = parse_response(response) # If report is available, just exit with the appropriate RC if ret != SCAN_NOT_FOUND: ret_str = RET_STR_INFECTED if ret else RET_STR_CLEAN LOGGER.info(f"Report found. Status: {ret_str}.") sys.exit(ret) # Send file to VT for scanning try: LOGGER.info( 'Report not found. Sending file to VirusTotal for scanning.') vt.file_scan(args.file) except ConnectionError as e: err_str = str(e) LOGGER.error(f"Connection error to VT: {err_str}") sys.exit(SCAN_ERROR) while ret == SCAN_NOT_FOUND: LOGGER.info(f"Scan still running, sleeping for {WAIT_TIME} seconds.") sleep(WAIT_TIME) # Try again try: response = vt.file_report([file_hash]) except ConnectionError as e: err_str = str(e) LOGGER.error( f"Temporary connection error to VT: {err_str}... Retrying in {WAIT_TIME} seconds." ) continue ret = parse_response(response) ret_str = RET_STR_INFECTED if ret else RET_STR_CLEAN LOGGER.info(f"Scan finished. Status: {ret_str}.") sys.exit(ret)
class ExternalTesting: # This requires a virustotal API key VIRUSTOTAL = 4 # This requires the installation of the Malice multiscanner along with installed scanner plugins MALICE = 2 NONE = 0 MALICE_SCANNERS = [ 'malice/avast', 'malice/avg', 'malice/clamav', 'malice/comodo', 'malice/escan', 'malice/fprot', 'malice/fsecure', 'malice/mcafee', 'malice/sophos', 'malice/zoner' ] # Initialize module logfile and tool output file to STDOUT, initialize output headers def __init__(self): self.logfile = stdout self.output = False self.virus_total = None self.virus_total_output_path = '' self.malice_output_path = '' self.scanners = ExternalTesting.NONE @staticmethod def check_or_make_path(target_path): if not path.isdir(target_path): mkdir(target_path) def get_scanners(self): return self.MALICE_SCANNERS # Specify module logfile manually def set_logfile(self, logfile_path): self.logfile = open(logfile_path, 'w') # Specify module logfile directory, but use default name for logfile def set_logfile_by_directory(self, logfile_directory): self.logfile = open( path.join(logfile_directory, 'external_scanner.log'), 'w') # Flush module logfile def flush_logfile(self): self.logfile.flush() # Close module logfile def close_logfile(self): if self.logfile != stdout: self.logfile.close() # Specify tool output file def set_output_directory(self, output_path): self.check_or_make_path(output_path) if self.scanners and self.VIRUSTOTAL: self.virus_total_output_path = path.join(output_path, 'VirusTotal') ExternalTesting.check_or_make_path(self.virus_total_output_path) if self.scanners and self.MALICE: self.malice_output_path = path.join(output_path, 'Malice') ExternalTesting.check_or_make_path(self.malice_output_path) self.output = True # Flush tool output file def flush_output(self): self.output.flush() # Close tool output file def close_output(self): if self.output != stdout: self.output.close() # Close all logfiles (tool output, module logs) def close(self): self.close_logfile() self.close_output() def set_virus_total_key(self, key): self.virus_total = Virustotal(key) def set_external_scanners(self, setting): if setting in [ ExternalTesting.NONE, ExternalTesting.MALICE, ExternalTesting.VIRUSTOTAL, ExternalTesting.MALICE | ExternalTesting.VIRUSTOTAL ]: self.scanners = setting return True else: return False def check_virus_total(self): if self.virus_total: return True else: return False # This function expects input in the form of destination filename, md5 sum, and path to file to scan. The output is # a .json file (if the VirusTotal api is enabled) and an .md file (if the Malice command is enabled). def process_file_list_multiscanner(self, md5_list): if (self.scanners == self.NONE): return False if (self.scanners and self.VIRUSTOTAL) and not (self.check_virus_total()): raise AttributeError( 'VirusTotal API invoked without providing a key using the virus_total_key(key) method' ) for entry in md5_list: if self.scanners and self.VIRUSTOTAL: self.logfile.write('Invoking VirusTotal on {}.'.format( entry[2])) destination_file_path = path.join(self.virus_total_output_path, '{}.json'.format(entry[0])) print(destination_file_path) virus_total_report = self.virus_total.file_report([entry[1]]) if self.output: with open(destination_file_path, 'w') as write_file: pprint(virus_total_report, write_file) self.logfile.write( "Wrote VirusTotal report for {} to {}".format( entry[2], destination_file_path)) else: pprint(virus_total_report) if self.scanners and self.MALICE: self.logfile.write('Invoking Malice Scanner on {}.'.format( entry[2])) destination_file_path = path.join(self.malice_output_path, '{}.md'.format(entry[0])) malice_output = "" for scanner in self.MALICE_SCANNERS: print(entry[2], scanner) command = "docker run --rm -v {}:/malware:ro {} -t " \ "/malware/{}".format(path.dirname(entry[2]), scanner, path.basename(entry[2])) malice = run(command, shell=True, encoding=getfilesystemencoding(), stdout=PIPE) malice_output += malice.stdout if self.output: with open(destination_file_path, 'w') as write_file: write_file.write(malice_output) self.logfile.write( "Wrote Malice output {} to {}".format( entry[2], destination_file_path)) else: print(malice_output) return True
if "virustotal" in report_json and "sha256" in report_json[ "virustotal"]: # If VirusTotal report fetching was correctly conducted in cuckoo, use it c.execute('INSERT INTO samples (sha256, mark_count) VALUES (?, ?)', (report_json["virustotal"]["sha256"], report_json["virustotal"]["positives"])) sample_id = c.lastrowid else: # If not, fetch report now sha256_hash = hashlib.sha256() with open( os.path.join(cwd, "storage/analyses", analysis_dir, "binary"), "rb") as f: # Read and update hash string value in blocks of 4K for byte_block in iter(lambda: f.read(4096), b""): sha256_hash.update(byte_block) resp = vtotal.file_report([sha256_hash.hexdigest()])["json_resp"] if resp["response_code"] is 0: unknown_from_virustotal.append(analysis_dir) c.execute( 'INSERT INTO samples (sha256, mark_count) VALUES (?, ?)', (sha256_hash.hexdigest(), -1)) else: c.execute( 'INSERT INTO samples (sha256, mark_count) VALUES (?, ?)', (resp["sha256"], resp["positives"])) sample_id = c.lastrowid snapshots_fp = open( os.path.join(cwd, "storage/analyses", analysis_dir, "files", "metrics.json")) snapshots_json = json.load(snapshots_fp)