def test_scan_file_binary(self): vt = PublicApi(API_KEY) vt.scan_file() try: print( json.dumps(vt.scan_file('virus_total_apis/test/test.exe'), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def test_scan_file_stream(self): vt = PublicApi(API_KEY) try: print json.dumps(vt.scan_file(EICAR), sort_keys=False, indent=4) except Exception as e: self.fail(e)
def test_scan_file_stringio(self): vt = PublicApi(API_KEY) try: print json.dumps(vt.scan_file(StringIO.StringIO(EICAR)), sort_keys=False, indent=4) except Exception as e: self.fail(e)
def submit2vt(filename): """Submit a new file to VT for scanning""" # Check VT score vt = VirusTotalPublicApi(config['apiKey']) response = vt.scan_file(filename) # DEBUG fp = open('/tmp/vt.debug', 'a') fp.write(json.dumps(response, sort_keys=False, indent=4)) fp.close() if response['response_code'] == 200: writeLog("VT Reply: %s" % response['results']['verbose_msg']) else: writeLog('VT Error: %s' % response['error']) if config['esServer']: # Save results to Elasticsearch try: response['@timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%S+01:00") res = es.index(index=config['esIndex'], doc_type="VTresult", body=json.dumps(response)) except: writeLog("Cannot index to Elasticsearch") return
def test_scan_file_stream(self): vt = PublicApi(API_KEY) try: print(json.dumps(vt.scan_file(EICAR, from_disk=False), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def test_scan_file_binary(self): vt = PublicApi(API_KEY) try: print(json.dumps(vt.scan_file('virus_total_apis/test/test.exe'), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def send_request(file, from_disk, original_path): logger.add(" " * 10) logger.add("File {0}".format(original_path)) api_key = str(config['Main']['ApiKey']) vt = VirusTotalPublicApi(api_key) scanned_file = {'response_code': 000} report = {'response_code': 000} while scanned_file['response_code'] != 200: scanned_file = json.loads( json.dumps(vt.scan_file(this_file=file, from_disk=from_disk), sort_keys=True, indent=4)) try: logger.add("Response: scan_file: {0}".format( scanned_file['results']['verbose_msg'])) except KeyError: logger.add("Error in scan_file: {0}".format(scanned_file)) pass while report['response_code'] != 200: report = vt.get_file_report(scanned_file['results']['resource']) if report['response_code'] == 204: logger.add("Sleeping for 15 seconds: {0}".format(report)) sleep(15) continue try: logger.add("Response: get_file_report: {0} & {1}".format( report['response_code'], report['results']['response_code'])) except KeyError: logger.add("Error in get_file_report: {0}".format(report)) pass if report['response_code'] == 200 and report['results'][ 'response_code'] != 1: logger.add("API bad Response. File lost in queue, rescanning") check_one_file_on_virustotal([file]) break try: ratio = round( report['results']['positives'] / report['results']['total'] * 100, 2) logger.add("Positives: {0} , Total {1}".format( report['results']['positives'], report['results']['total'])) logger.add("Ratio is: {0}".format(ratio)) if ratio < 85.0: add_to_whitelist(original_path) except KeyError: pass return 0
def test_scan_file_binary(self): vt = PublicApi(API_KEY) try: print json.dumps(vt.scan_file('test.exe'), sort_keys=False, indent=4) except Exception as e: self.fail(e)
def test_scan_file_stream_filename(self): vt = PublicApi(API_KEY) try: print( json.dumps(vt.scan_file(EICAR, from_disk=False, filename='my_eicar_file.txt'), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def test_scan_file_binary_filename(self): vt = PublicApi(API_KEY) try: print( json.dumps(vt.scan_file( 'C:\\Users\\YES24\\Desktop\\자료정리\\분류전\\cmd.exe', filename='othertest.exe'), sort_keys=False, indent=4)) except Exception as e: self.fail(e)
def scan(path): # Fill in your VirusTotal public api key api_key = '' if api_key != '': try: vt = PublicApi(api_key) res = vt.scan_file(path) if res["response_code"] == 200: print("Complete Requesting Scan", path) else: print("Error") except Exception as e: print("Error:", e) else: print("Need VirusTotal API Key")
def is_dangerous(con, file_to_scan, extract_mail, email_id, file_name): try: virus_total_scanner = PublicApi(API_KEY) response = virus_total_scanner.scan_file(file_to_scan, from_disk=False) time.sleep(1) f_md5 = hashlib.md5(file_to_scan).hexdigest() response = virus_total_scanner.get_file_report(f_md5) if response['results']['positives'] > 0: delete_email(con, email_id) print( "\n---> System filtered-out an email from {}. Reason: dangerous attachment detected\n" .format(extract_mail)) return True except Exception as e: print('Scan file Failed: {}'.format(e)) download_attachment(file_name, file_to_scan) return False
class VirusTotalEngine(BaseEngine): name = "VirusTotal" delay = 60 / 4 # 4 requests of any nature per minute def __init__(self): self.client = PublicApi(settings.VIRUSTOTAL_API_KEY) def send_scan(self, this_file, filename): resp = self.client.scan_file(this_file, from_disk=False, filename=filename) sleep(self.delay) return { "engine_id": resp["results"]["scan_id"], "engine_link": resp["results"]["permalink"], "status": Request.STATUS.queued, } def receive_result(self, engine_id): resp = self.client.get_file_report(engine_id) sleep(self.delay) results = resp["results"] if results["response_code"] not in [1, -2]: raise Exception( "Unknown response code of VirusTotal: {}".format(resp["response_code"]) ) if results["response_code"] == 1 and results["total"] < 10: raise Exception( "Low level of VirusTotal scanning: {}".format(resp["total"]) ) result = { "engine_id": results["resource"], } if results["response_code"] == -2: result["status"] = Request.STATUS.queued elif results["positives"] == 0: result["status"] = Request.STATUS.not_detected result["engine_report"] = results result["engine_link"] = results["permalink"] else: result["status"] = Request.STATUS.infected result["engine_report"] = results result["engine_link"] = results["permalink"] return result
def submit2vt(filename): """Submit a new file to VT for scanning""" # Check VT score vt = VirusTotalPublicApi(config['apiKey']) response = vt.scan_file(filename) # DEBUG fp = open('/tmp/vt.debug', 'a') fp.write(json.dumps(response, sort_keys=False, indent=4)) fp.close() if config['esServer']: # Save results to Elasticsearch try: response['@timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%S+01:00") res = es.index(index=config['esIndex'], doc_type="VTresult", body=json.dumps(response)) except: writeLog("Cannot index to Elasticsearch") return
print(colored('[+]', 'green')+ item +': ', colored('Limpio', 'green')) else: print(colored('[+]', 'red')+ item +': ', colored('detectado', 'red')) def menu(): cprint('\n ██ ██ ██ ██████ ██ ██ ███████ ███████ ██████ █████ ███ ██ ', 'green') cprint(' ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ', 'green') cprint(' ██ ██ ██ ██████ ██ ██ ███████ ███████ ██ ███████ ██ ██ ██ ', 'green') cprint(' ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ', 'green') cprint(' ████ ██ ██ ██ ██████ ███████ ███████ ██████ ██ ██ ██ ████ ', 'green') cprint('\n [+]By devkernnel', 'red') cprint(' [+]github: https://github.com/kenderperez', 'red') cprint(' [+]VirusTotal', 'red') API_KEY = "198bde2e7a2c6675b70a6bf02b1d3504d19d2e4df5ca9df329f10e502ac4ca80" api = PublicApi(API_KEY) menu() nombre_archivo = str(input(colored('\n [+]Ingrese el nombre del archivo que desea escanear!\n archivo: ', 'cyan'))) responsefile = api.scan_file(nombre_archivo) md5 = responsefile['results']['md5'] cprint('[+]Nuestros duendecitos estan trabajando en su archivo espere por favor a que obtengan un resultado...', 'magenta') time.sleep(200) consultarScan()
def detailGET(request): if request.POST: search_term = request.POST['search'] print(search_term) try: obj = File.objects.filter(SHA256=search_term).first() obj2 = Hash.objects.filter(SHA256=search_term).first() print(obj2.MD5) print(obj2.SHA256) """ AV Detection """ vt = VirusTotalPublicApi('38afdb6f1267ae26374823c5e80d84fc977ed7b326b152d21fedd15ca29f36dc') """Check if file is in VT's cache""" response = vt.get_file_report(obj2.MD5) json_dump = json.dumps(response, sort_keys=False, indent=4) json_list = json.loads(json_dump) verbose_msg = "" for item_key, item_values in json_list.items(): if 'results' in item_key: print("Scanning... ") verbose_msg = json_list['results']['verbose_msg'] print(verbose_msg) if verbose_msg != "Scan finished, information embedded": print("Uploading file..") path = "/root/Desktop/OmegaVirus/OmegaVirusWeb/core/uploads/" + obj.name print(path) vt.scan_file(path) verbose_msg = "" """Scanning file""" time_check = 0 while verbose_msg != "Scan finished, information embedded": """if verbose_msg == "Scan finished, information embedded": break""" response = vt.get_file_report(obj2.MD5) json_dump = json.dumps(response, sort_keys=False, indent=4) json_list = json.loads(json_dump) for item_key, item_values in json_list.items(): if 'results' in item_key: verbose_msg2 = verbose_msg verbose_msg = json_list['results']['verbose_msg'] if verbose_msg != verbose_msg2: if verbose_msg != "The requested resource is not among the finished, queued or pending scans": print(verbose_msg) # time.sleep(8) if time_check >= 120: print("Time limit surpassed") sys.exit(0) if verbose_msg == "Your resource is queued for analysis": """time_check += 8 print("Scanning... " + str(time_check) + " seconds elapsed..")""" print("outside while") response_code = json_list['response_code'] scan_id = json_list['results']['scan_id'] sha1 = json_list['results']['sha1'] resource = json_list['results']['resource'] scan_date = json_list['results']['scan_date'] permalink = json_list['results']['permalink'] sha256 = json_list['results']['sha256'] positives = json_list['results']['positives'] total = json_list['results']['total'] md5 = json_list['results']['md5'] # Liste AV -- Resultat liste_AV = [i for i in json_list["results"]["scans"]] liste_AV_result_html = [(str(i), str(json_list["results"]["scans"][i]["detected"])) for i in liste_AV] html = str() cptdetected = 0 cptnodetected = 0 for i, j in liste_AV_result_html: if j == "True": html += '<tr><th scope="row"><b>' + i + '</b></th><td style="color:red;"><b>' + "Detected" + '</b></td></tr>' cptdetected += 1 if j == "False": html += '<tr><th scope="row"><b>' + i + '</b></th><td style="color:green;"><b>' + "Not detected" + '</b></td></tr>' cptnodetected += 1 ########### # Liste Hash --- New Version liste_hash = [("MD5", obj2.MD5), ("SHA1", obj2.SHA1), ("SHA256", obj2.SHA256), ("SHA512", obj2.SHA512), ("SSDEEP", obj2.SSDEEP), ("TLSH", obj2.TLSH)] html_hash = str() for i, j in liste_hash: html_hash += '<tr><th scope="row" style="color:red;"><b>' + i + '</b></th><td style="color:blue;"><b>' + j + '</b></td></tr>' ############################## ## Yara ## html_yara = str() yara_matched = (("yararule1", "posay", "30"), ("yararule2", "posay", "80"), ("yararule2", "posay", "30"), ("yararule3", "posay", "80")) for nom_regle, j, k in yara_matched: html_yara += '<tr><th scope="row" style="color:red;"><b>' + nom_regle + '</b></th></tr>' ################# Json ############# with open("/root/Desktop/OmegaVirus/scripts/report.json") as json_cuckoo: data_cuckoo = json.load(json_cuckoo) cuckoo_score = float(data_cuckoo["info"]["score"]) html_cuckoo = str() for i in data_cuckoo["info"]: dico = data_cuckoo["info"][i] if i != "score": html_cuckoo += '<tr><th scope="row">' + str(i) + '</th><td>' + str(dico) + '</td></tr>' ############################################################### html_notation = str() av_notation = str(cptdetected) + "/" + str(cptdetected + cptnodetected) av_notation_pourcent = str(int((int(cptdetected) / int(cptdetected + cptnodetected)) * 100)) detection = (str(int((positives * 100 / total)))) obj.detection = str(int((positives * 100 / total))) File.objects.filter(name=obj.name).update(detection=detection) obj.refresh_from_db() if int(float(av_notation_pourcent)) > 80: progress_bar_color = "success" elif int(float(av_notation_pourcent)) > 40: progress_bar_color = "primary" else: progress_bar_color = "danger" cuckoo_note = str(float(cuckoo_score)) cuckoo_note_pourcent = str(int((float(cuckoo_score) / 10) * 100)) if int(float(cuckoo_note_pourcent)) > 80: progress_bar_color1 = "success" elif int(float(cuckoo_note_pourcent)) > 40: progress_bar_color1 = "primary" else: progress_bar_color1 = "danger" html_notation += '<tr><th scope="row">Antivirus Detection</th><td>' + av_notation + '</td><td><div class="d-flex align-items-center"><span class="mr-2">' + av_notation_pourcent + '%</span><div><div class="progress"><div class="progress-bar bg-gradient-' + progress_bar_color + '" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: ' + av_notation_pourcent + '%;"></div></div></div></div></td></tr>' html_notation += '<tr><th scope="row">Cuckoo Detection</th><td>' + cuckoo_note + '/10</td><td><div class="d-flex align-items-center"><span class="mr-2">' + cuckoo_note_pourcent + '%</span><div><div class="progress"><div class="progress-bar bg-gradient-' + progress_bar_color1 + '" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: ' + cuckoo_note_pourcent + '%;"></div></div></div></div></td></tr>' print(response_code) print(scan_id) print(sha1) print(resource) print(scan_date) print(permalink) print(verbose_msg) print(sha256) print(positives) print(total) print(md5) print("Scan time taken: " + str(time_check) + " seconds.") context = { "name": obj.name, "id": obj.id, "SHA256": obj.SHA256, "filepath": obj.filepath, "size": obj.size, "date": obj.date, "MD5": obj2.MD5, "SHA1": obj2.SHA1, "SHA512": obj2.SHA512, "SSDEEP": obj2.SSDEEP, "TLSH": obj2.TLSH, "total": total, "positives": positives, "html": mark_safe(html), "html_hash": mark_safe(html_hash), "html_yara": mark_safe(html_yara), "cuckoo_score": cuckoo_score, "cuckoo_info": mark_safe(html_cuckoo), "html_notation": mark_safe(html_notation) } URLS = [] URLS = urls() print("Found " + str(len(URLS)) + " URLs in this file.") signatures = [] signatures = Signatures() cuckoo_info = str() cuckoo_info += "<tr><td><b>Found " + str(len(URLS)) + " URLs in this file.</b></td></tr>" for x in URLS: cuckoo_info += '<tr><td>' + x + '</td></tr>' for y in signatures: cuckoo_info += '<tr><td>' + y + '</td></tr>' context2 = { "cuckoo_information": mark_safe(cuckoo_info) } context.update(context2) if positives == 0: safety = "OmegaVirus flagged this file as safe" context2 = { "safety": safety } context.update(context2) else: safety = str(positives) + " OmegaVirus flagged this file as malicious" context2 = { "safetyPos": safety } context.update(context2) return render(request, "index.html", context) except ObjectDoesNotExist: return render(request, "index.html")
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')
pass shutil.copy( 'install\\CrossMgrVideo_Setup.exe', 'install\\' + newExeName ) six.print_( 'executable copied to: ' + newExeName ) # Create comprssed executable. os.chdir( 'install' ) newExeName = os.path.basename( newExeName ) newZipName = newExeName.replace( '.exe', '.zip' ) try: os.remove( newZipName ) except: pass z = zipfile.ZipFile(newZipName, "w") z.write( newExeName ) z.close() six.print_( 'executable compressed.' ) shutil.copy( newZipName, googleDrive ) from virus_total_apis import PublicApi as VirusTotalPublicApi API_KEY = '64b7960464d4dbeed26ffa51cb2d3d2588cb95b1ab52fafd82fb8a5820b44779' vt = VirusTotalPublicApi(API_KEY) print ( 'VirusTotal Scan' ) vt.scan_file( os.path.abspath(newExeName) )
pass shutil.copy(os.path.join('install', 'CrossMgrAlien_Setup.exe'), os.path.join('install', newExeName)) print('executable copied to: ' + newExeName) # Create compressed executable. os.chdir('install') newExeName = os.path.basename(newExeName) newZipName = newExeName.replace('.exe', '.zip') try: os.remove(newZipName) except: pass z = zipfile.ZipFile(newZipName, "w") z.write(newExeName) z.close() print('executable compressed.') shutil.copy(newZipName, googleDrive) #shutil.copy( '../CrossMgrAlienReadme.pdf', googleDrive ) from virus_total_apis import PublicApi as VirusTotalPublicApi API_KEY = '64b7960464d4dbeed26ffa51cb2d3d2588cb95b1ab52fafd82fb8a5820b44779' vt = VirusTotalPublicApi(API_KEY) print('VirusTotal Scan') vt.scan_file(os.path.abspath(newExeName))
class App(Daemon): def __init__(self, config, log): if not isfile(realpath(expanduser(config))): print('Run \'sh configure.sh\' first!') exit() else: with open(realpath(expanduser(config)), 'r') as handler: self.host = handler.readline().strip('\n') self.port = int(handler.readline().strip('\n')) self.username = handler.readline().strip('\n') self.password = handler.readline().strip('\n') self.from_ = handler.readline().strip('\n') self.to = handler.readline().strip('\n') self.vt = PublicApi(handler.readline().strip('\n')) self.dlfolder = realpath(expanduser(handler.readline().strip('\n'))) self.stfolder = realpath(expanduser(handler.readline().strip('\n'))) handler.close() Daemon.__init__(self, join(self.stfolder, "pidfile")) logging.basicConfig(filename=realpath(expanduser(log)), format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO) def run(self): # Touch known_hashes if not isdir(self.stfolder): makedirs(self.stfolder) open(join(self.stfolder, "known_hashes"), "a").close() # Read out known_hashes hash_handler = open(join(self.stfolder, "known_hashes"), "r+") hashlist = hash_handler.read().split("\n") hashlist = {i[:64]:i[67:] for i in hashlist} while True: dlcontent = listdir(self.dlfolder) # Rescan all 60 seconds for new files if not dlcontent: sleep(60) continue today = date.today() year = today.year month = today.month day = today.day datestring = str(year)+"-"+str(month)+"-"+str(day) for i in dlcontent: # Check if download of file hash finished size = stat(join(self.dlfolder, i)).st_size sleep(1) if stat(join(self.dlfolder, i)).st_size != size: continue with open(join(self.dlfolder, i), "rb") as h: # Hash file in dl folder and look if it's known hashit = sha256() hashit.update(h.read()) if hashit.hexdigest() in hashlist.keys(): # Just remove already known files logging.info("Found already known file "+hashlist[hashit.hexdigest()]) remove(join(self.dlfolder, i)) else: # Save and scan unknown files and remember the hash hashdigest = hashit.hexdigest() hashlist[hashdigest] = join(datestring, i) hash_handler.write(hashdigest+" > "+join(datestring, i)+"\n") hash_handler.flush() if not isdir(join(self.stfolder, datestring)): makedirs(join(self.stfolder, datestring)) move(join(self.dlfolder, i), join(self.stfolder, datestring, i)) response = self.scan(hashdigest, join(self.stfolder, datestring, i), today) if not isdir(join(self.stfolder, "reports", datestring)): makedirs(join(self.stfolder, "reports", datestring)) open(join(self.stfolder, "reports", datestring, i), "a").close() with open(join(self.stfolder, "reports", datestring, i), "r+") as report: report.write(dumps(response, sort_keys=False, indent=4)) report.flush() def scan(self, hashdigest, filepath, today): scan_flag = True while True: # First look if file is known to VirusTotal response = self.vt.get_file_report(hashdigest) if response["response_code"] == 204: logging.info("Submission limit reached. I'll sleep for 60 seconds") sleep(60) elif response["results"]["response_code"] == 1: # Rescan needed? #scan_date = datetime.strptime(response["results"]["scan_date"][:10], #"%Y-%m-%d") #if abs((today-scan_date).days) >= 30: #self.vt.rescan_file(hashdigest) #continue # Send report for unknown file msg = """From: %s To: %s Subject: Virustotal report %s""" % (self.from_, self.to, dumps(response, sort_keys=False, indent=4)) self.send(msg) logging.info("Sent report for "+filepath) return response else: # Submit the unknown file if scan_flag: # Workaround for download bug # Another test for unfinished downloads # Sadly as the file is already moved # the file is lost for analysis :( with open(filepath, "rb") as h: hashit = sha256() hashit.update(h.read()) if hashit.hexdigest() != hashdigest: logging.info("File for submission has another hash as in download folder!") logging.info("Filepath is %s" % (filepath)) break response = self.vt.scan_file(filepath) msg = """From: %s To: %s Subject: Virustotal submit Submitted unknown file %s with hash %s for scan. %s""" % (self.from_, self.to, filepath, hashdigest, dumps(response, sort_keys=False, indent=4)) self.send(msg) logging.info("Submitted unknown file "+filepath+" with hash "+hashdigest+" for scan") logging.info("I will sleep know for 60 seconds and try to receive the result after that") sleep(60) scan_flag = False else: logging.info("Scan seems not finished. Will sleep for another 30 seconds") sleep(30) def send(self, msg): smtp = smtplib.SMTP(self.host, self.port) smtp.starttls() smtp.login(self.username, self.password) smtp.sendmail(self.from_, self.to, msg)
f = open(sample_file, "rb") sample_file_content = f.read() f.close() sample_file_md5 = hashlib.md5(sample_file_content).hexdigest() if collection.find({'results.md5':sample_file_md5}).count() == 0: vt_response = vt.get_file_report(sample_file_md5) if vt_response['response_code'] == 200 and vt_response['results']['response_code'] == 1: collection.insert(vt_response) print "Sample " + sample_file_md5 + " added to database" print elif vt_response['response_code'] == 204: print "Hit API Limit; cooling off for 15 seconds" print "The standard VirusTotal API Key allows 4 requests per minute" file_list.append(sample_file) sleep(15) print else: print 'Sample not found; submitting to VirusTotal' vt_response = vt.scan_file(sample_file) if vt_response['response_code'] == 200 and vt_response['results']['response_code'] == 1: print "Sample submiited successfully; checking back later" file_list.insert(0,sample_file) print else: print "Sample submit failed; try again later" print else: print "Sample " + sample_file_md5 + " already exists in database" print
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()
def module_run(self, params): key = self.get_key("virus_total_api") if key == "": self.error("No key defined for virus_total_api") return self.output("Got key: %s" % key) api = Api(key) for i in params: location, product_name, version = i self.output("Scanning: %s" % location) if not os.path.exists(location): self.error("%s does not exist") continue size = os.path.getsize(location) if (size / (1024 * 1024.0)) > 32: self.error( "%s is larger than 32Mb..cannot submit to virus total" % location) continue is_local = not "://" in location response = api.scan_file(location, from_disk=is_local) result_code = response["response_code"] scan_id = response["results"]["scan_id"] self.output("Got response code: %s, scan_id: %s" % (result_code, scan_id)) if result_code == 200: tries = self.options['retries'] while tries > 1: self.output("Sleeping %ss to wait for response" % self.options['sleep_time']) time.sleep(self.options['sleep_time']) response = api.get_file_report(scan_id) if response["response_code"] == 204: self.output( "Exeeded api request limit sleeping an extra %ss" % self.options['extra_sleep_time']) time.sleep(self.options['extra_sleep_time']) continue if not "scans" in response["results"]: tries -= 1 continue detected = [ s for s in response["results"]["scans"] if response["results"]["scans"][s]["detected"] == True ] total_scans = response["results"]["total"] found = response["results"]["positives"] scans = response["results"]["scans"] for d in detected: self.add_virus(product_name, version, d, scans[d]["version"], scans[d]["update"], scans[d]["result"]) self.output("%s/%s scanners detected viruses" % (found, total_scans)) break
'38afdb6f1267ae26374823c5e80d84fc977ed7b326b152d21fedd15ca29f36dc') """Check if file is in VT's cache""" response = vt.get_file_report(file_md5) json_dump = json.dumps(response, sort_keys=False, indent=4) json_list = json.loads(json_dump) verbose_msg = "" for item_key, item_values in json_list.items(): if 'results' in item_key: print("Scanning... ") verbose_msg = json_list['results']['verbose_msg'] print(verbose_msg) if verbose_msg != "Scan finished, information embedded": print("Uploading file..") vt.scan_file(filename) """while verbose_msg == "The requested resource is not among the finished, queued or pending scans": vt.scan_file(filename) response = vt.get_file_report(file_md5) json_dump = json.dumps(response, sort_keys=False, indent=4) json_list = json.loads(json_dump) verbose_msg = "" for item_key, item_values in json_list.items(): if 'results' in item_key: verbose_msg = json_list['results']['verbose_msg'] print(verbose_msg)""" if verbose_msg != "Scan finished, information embedded": verbose_msg = "" """Scanning file""" time_check = 0
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")
from virus_total_apis import PublicApi as VirusTotalPublicApi except: print( '**** virus_total_apis module not found. Do "pip install virustotal-api"' ) raise API_KEY = '64b7960464d4dbeed26ffa51cb2d3d2588cb95b1ab52fafd82fb8a5820b44779' vt = VirusTotalPublicApi(API_KEY) parser = argparse.ArgumentParser( description='Submit executabes to virustotal.') parser.add_argument('executables', type=str, nargs='+', help='executable files') parser.add_argument("-v", "--verbose", action="store_true", help="verbose output") args = parser.parse_args() for exe in args.executables: if args.verbose: print('submitting "{}" to virustotal...'.format(exe)) if not os.path.exists(exe): raise ValueError('File not found: "{}"'.format(exe)) vt.scan_file(exe) sys.exit(0)
def run(self): db = Database() if 'file_id' in self.request.POST: # Get file object from DB file_id = self.request.POST['file_id'] file_object = db.get_filebyid(file_id) sha256 = file_object.sha256 print self.config['virustotal']['api_key'], type(self.config['virustotal']['api_key']) if self.config['virustotal']['api_key'] == 'None': state = 'error' vt_results = 'No API Key set in volutility.conf' else: # Init the API with key from config vt = PublicApi(self.config['virustotal']['api_key']) # If we upload if 'upload' in self.request.POST: response = vt.scan_file(file_object.read(), filename=file_object.filename, from_disk=False) if response['results']['response_code'] == 1 and 'Scan request successfully queued' in response['results']['verbose_msg']: print "File Uploaded and pending" state = 'pending' else: print response state = 'error' vt_results = None # Else just get the results else: # get results from VT response = vt.get_file_report(sha256) vt_results = {} # Valid response if response['response_code'] == 200: print "Valid Response from server" # Not present in data set prompt to uploads if response['results']['response_code'] == 0: state = 'missing' # Still Pending elif response['results']['response_code'] == -2: # Still Pending state = 'pending' # Results availiable elif response['results']['response_code'] == 1: vt_results['permalink'] = response['results']['permalink'] vt_results['total'] = response['results']['total'] vt_results['positives'] = response['results']['positives'] vt_results['scandate'] = response['results']['scan_date'] vt_results['scans'] = response['results']['scans'] # Store the results in datastore state = 'complete' store_data = {'file_id': file_id, 'vt': vt_results} db.create_datastore(store_data) self.render_type = 'file' self.render_data = {'VirusTotalSearch': {'state': state, 'vt_results': vt_results, 'file_id': file_id}}
original = open(sys.argv[2], 'w') API_KEY = '' with open('API_KEY2', 'r') as f: API_KEY = f.read().strip() executables = [ exe for exe in os.listdir(sys.argv[1]) if os.path.isfile(os.path.join(sys.argv[1], exe)) ] vt = PublicApi(API_KEY) for exe in executables: print('Uploading {}'.format(exe)) vtreport = vt.scan_file(os.path.join(sys.argv[1], exe)) while vtreport['response_code'] != 200: print('Reached maximum requests/minute, waiting 30 seconds') time.sleep(30) vtreport = vt.scan_file(os.path.join(sys.argv[1], exe)) r = vtreport['results'] if r['response_code'] != 1: print('Error rescaning file {}'.format(exe)) original.write('{:<50s}{}\n'.format(exe, 'An error occurred')) else: original.write('{:<50s}{}\n'.format(exe, r['permalink'])) original.flush() os.fsync(original.fileno())
f.close() sample_file_md5 = hashlib.md5(sample_file_content).hexdigest() if collection.find({'results.md5': sample_file_md5}).count() == 0: vt_response = vt.get_file_report(sample_file_md5) if vt_response['response_code'] == 200 and vt_response['results'][ 'response_code'] == 1: collection.insert(vt_response) print "Sample " + sample_file_md5 + " added to database" print elif vt_response['response_code'] == 204: print "Hit API Limit; cooling off for 15 seconds" print "The standard VirusTotal API Key allows 4 requests per minute" file_list.append(sample_file) sleep(15) print else: print 'Sample not found; submitting to VirusTotal' vt_response = vt.scan_file(sample_file) if vt_response['response_code'] == 200 and vt_response['results'][ 'response_code'] == 1: print "Sample submiited successfully; checking back later" file_list.insert(0, sample_file) print else: print "Sample submit failed; try again later" print else: print "Sample " + sample_file_md5 + " already exists in database" print
def scan_virus_total(target_file_list): ''' if there is no hash result, then do file upload :param filename: absolute file path, no exceptions :return: there is no return ''' conn = MongoClient(MONGODB_URI_SCHEME) db = conn[MONGODB_DATABASE] collections = db[MONGODB_COLLECTIONS] history = db[MONGODB_SCAN_HISTORY] time_elapsed = [10, 15, 20, 30] time_elapsed_pool = cycle(time_elapsed) init_time_pool = cycle(time_elapsed) valid_account_list = list( filter(lambda x: x['valid'] == True, VIRUSTOTAL_ACCOUNT)) account_number = len(valid_account_list) valid_account_pool = cycle(valid_account_list) counter = 0 init = valid_account_list[-1]['apikey'] for dir_path in target_file_list: for filename in target_file_list[dir_path]: sha1 = binary_sha1(filename) while True: apikey = next(valid_account_pool)['apikey'] if init == apikey: elapsed = next(init_time_pool) messageBold(" wait for time elapsed (%d)" % elapsed) time.sleep(elapsed) vt = PublicApi(apikey) resp = vt.get_file_report(sha1) resp_code = resp.get('response_code', -1) normalBold("# %s -> scan (%d)" % (filename, resp_code)) if resp_code == 204: # exceeded request rate limit (4 request / min) epoch = next(time_elapsed_pool) if epoch == 30: criticalBold("there is no virustotal response") break messageBold(" Wait for time elapsed (%d)" % epoch) time.sleep(epoch) break elif resp_code == 200: scan_report = resp.get('results') scan_resp_code = scan_report.get('response_code') if scan_resp_code == 1: # pymongo code is here resp['filename'] = filename collections.insert(resp) break elif scan_resp_code == 0: # pending, or has no data in virustotal, so that upload file tmp = vt.scan_file(filename) tmp['filename'] = filename history.insert(tmp) continue elif scan_resp_code == -2: warningBold(" Resource is pending for check") pprint(resp) break else: warningBold( " No Normal Response Code From VirusTotal ") warningBold(json.dump(resp, sort_keys=True, indent=4)) break elif resp_code == -1: # connection error criticalBold('VirusTotal Response >>>>>>') pprint(resp) criticalBold('<<<<<<') continue # add for trace resp['filepath'] = filename
from pymongo import MongoClient from virus_total_apis import ApiError, PublicApi import json import pprint # MongoDB URI Format #client = MongoClient('mongodb://*****:*****@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".encode('utf-8') vt = PublicApi(API_KEY) data = vt.get_file_report('44cda81782dc2a346abd7b2285530c5f') data2 = vt.scan_file('C:\\Users\\YES24\\Desktop\\자료정리\\분류전\\cmd.exe') #pprint.pprint(data) print(type(data)) data['chuka'] = "c:\\users\\fuckyou.exe" print(db.scan_result.insert(data)) print(db.scan_result.insert(data2))
def run(self): db = Database() #self.render_javascript = "function test(){ alert(1); }; test();" self.render_javascript = "" if not self.config['virustotal']['api_key'] or not VT_LIB: self.render_type = 'error' self.render_data = "Unable to use Virus Total. No Key or Library Missing. Check the Console for details" if 'file_id' in self.request.POST: # Get file object from DB file_id = self.request.POST['file_id'] file_object = db.get_filebyid(file_id) sha256 = file_object.sha256 # Init the API with key from config vt = PublicApi(self.config.api_key) # If we upload if 'upload' in self.request.POST: response = vt.scan_file(file_object.read(), filename=file_object.filename, from_disk=False) if response['results'][ 'response_code'] == 1 and 'Scan request successfully queued' in response[ 'results']['verbose_msg']: print "File Uploaded and pending" state = 'pending' else: print response state = 'error' vt_results = None # Else just get the results else: # get results from VT response = vt.get_file_report(sha256) vt_results = {} # Valid response if response['response_code'] == 200: print "Valid Response from server" # Not present in data set prompt to uploads if response['results']['response_code'] == 0: state = 'missing' # Still Pending elif response['results']['response_code'] == -2: # Still Pending state = 'pending' # Results availiable elif response['results']['response_code'] == 1: vt_results['permalink'] = response['results']['permalink'] vt_results['total'] = response['results']['total'] vt_results['positives'] = response['results']['positives'] vt_results['scandate'] = response['results']['scan_date'] vt_results['scans'] = response['results']['scans'] # Store the results in datastore state = 'complete' store_data = {'file_id': file_id, 'vt': vt_results, 'state': state} db.create_datastore(store_data) self.render_type = 'file' self.render_data = { 'VirusTotalSearch': { 'state': state, 'vt_results': vt_results, 'file_id': file_id } }
def ajax_handler(request, command): """ return data requested by the ajax handler in volutility.js :param request: :param command: :return: """ if command == 'pollplugins': if 'session_id' in request.POST: # Get Current Session session_id = request.POST['session_id'] session = db.get_session(ObjectId(session_id)) plugin_rows = db.get_pluginbysession(ObjectId(session_id)) # Check for new registered plugins # Get compatible plugins profile = session['session_profile'] session_path = session['session_path'] vol_int = RunVol(profile, session_path) plugin_list = vol_int.list_plugins() # Plugin Options plugin_filters = vol_interface.plugin_filters refresh_rows = False existing_plugins = [] for row in plugin_rows: existing_plugins.append(row['plugin_name']) # For each plugin create the entry for plugin in plugin_list: # Ignore plugins we cant handle if plugin[0] in plugin_filters['drop']: continue if plugin[0] in existing_plugins: continue else: db_results = {} db_results['session_id'] = ObjectId(session_id) db_results['plugin_name'] = plugin[0] db_results['help_string'] = plugin[1] db_results['created'] = None db_results['plugin_output'] = None db_results['status'] = None # Write to DB db.create_plugin(db_results) refresh_rows = True if refresh_rows: plugin_rows = db.get_pluginbysession(ObjectId(session_id)) return render(request, 'plugin_poll.html', {'plugin_output': plugin_rows}) else: return HttpResponseServerError if command == 'dropplugin': if 'plugin_id' in request.POST: plugin_id = request.POST['plugin_id'] # update the plugin new_values = {'created': None,'plugin_output': None, 'status': None} db.update_plugin(ObjectId(plugin_id), new_values) return HttpResponse('OK') if command == 'runplugin': if 'plugin_id' in request.POST and 'session_id' in request.POST: plugin_name = run_plugin(request.POST['session_id'], request.POST['plugin_id']) return HttpResponse(plugin_name) if command == 'plugin_dir': # Platform PATH seperator seperator = ':' if sys.platform.startswith('win'): seperator = ';' # Set Plugins if 'plugin_dir' in request.POST: plugin_dir = request.POST['plugin_dir'] if os.path.exists(volrc_file): with open(volrc_file, 'a') as out: output = '{0}{1}'.format(seperator, plugin_dir) out.write(output) return HttpResponse(' No Plugin Path Provided') else: # Create new file. with open(volrc_file, 'w') as out: output = '[DEFAULT]\nPLUGINS = {0}'.format(plugin_dir) out.write(output) return HttpResponse(' No Plugin Path Provided') else: return HttpResponse(' No Plugin Path Provided') if command == 'filedetails': if 'file_id' in request.POST: file_id = request.POST['file_id'] file_object = db.get_filebyid(ObjectId(file_id)) file_datastore = db.search_datastore({'file_id': ObjectId(file_id)}) vt_results = None yara_match = None string_list = None state = 'notchecked' for row in file_datastore: if 'vt' in row: vt_results = row['vt'] state = 'complete' if 'yara' in row: yara_match = row['yara'] # New String Store new_strings = db.get_strings(file_id) if new_strings: string_list = new_strings._id yara_list = sorted(os.listdir('yararules')) return render(request, 'file_details.html', {'file_details': file_object, 'file_id': file_id, 'yara_list': yara_list, 'yara': yara_match, 'vt_results': vt_results, 'string_list': string_list, 'state': state, 'error': None }) if command == 'hivedetails': if 'plugin_id' and 'rowid' in request.POST: pluginid = request.POST['plugin_id'] rowid = request.POST['rowid'] plugin_details = db.get_pluginbyid(ObjectId(pluginid)) key_name = 'hive_keys_{0}'.format(rowid) if key_name in plugin_details: hive_details = plugin_details[key_name] else: session_id = plugin_details['session_id'] session = db.get_session(session_id) plugin_data = plugin_details['plugin_output'] for row in plugin_data['rows']: if str(row[0]) == rowid: hive_offset = str(row[1]) # Run the plugin vol_int = RunVol(session['session_profile'], session['session_path']) hive_details = vol_int.run_plugin('hivedump', hive_offset=hive_offset) # update the plugin / session new_values = {key_name: hive_details} db.update_plugin(ObjectId(ObjectId(pluginid)), new_values) # Update the session new_sess = {} new_sess['modified'] = datetime.now() db.update_session(session_id, new_sess) return render(request, 'hive_details.html', {'hive_details': hive_details}) if command == 'dottree': session_id = request.POST['session_id'] session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) results = vol_int.run_plugin('pstree', output_style='dot') return HttpResponse(results) if command == 'timeline': logger.debug('Running Timeline') session_id = request.POST['session_id'] session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) results = vol_int.run_plugin('timeliner', output_style='dot') return HttpResponse(results) if command == 'virustotal': if not config.api_key or not VT_LIB: logger.error('No Virustotal key provided in volutitliy.conf') return HttpResponse("Unable to use Virus Total. No Key or Library Missing. Check the Console for details") if 'file_id' in request.POST: file_id = request.POST['file_id'] file_object = db.get_filebyid(ObjectId(file_id)) sha256 = file_object.sha256 vt = PublicApi(config.api_key) if 'upload' in request.POST: response = vt.scan_file(file_object.read(), filename=file_object.filename, from_disk=False) if response['results']['response_code'] == 1: return render(request, 'file_details_vt.html', {'state': 'pending', 'vt_results': '', 'file_id': file_id}) else: return render(request, 'file_details_vt.html', {'state': 'error', 'vt_results': '', 'file_id': file_id}) else: response = vt.get_file_report(sha256) vt_fields = {} if response['results']['response_code'] == 1: vt_fields['permalink'] = response['results']['permalink'] vt_fields['total'] = response['results']['total'] vt_fields['positives'] = response['results']['positives'] vt_fields['scandate'] = response['results']['scan_date'] vt_fields['scans'] = response['results']['scans'] # Store the results in datastore store_data = {} store_data['file_id'] = ObjectId(file_id) store_data['vt'] = vt_fields update = db.create_datastore(store_data) return render(request, 'file_details_vt.html', {'state': 'complete', 'vt_results': vt_fields, 'file_id': file_id}) elif response['results']['response_code'] == -2: # Still Pending Analysis return render(request, 'file_details_vt.html', {'state': 'pending', 'vt_results': vt_fields, 'file_id': file_id}) elif response['results']['response_code'] == 0: # Not present in data set prompt to uploads return render(request, 'file_details_vt.html', {'state': 'missing', 'vt_results': vt_fields, 'file_id': file_id}) if command == 'yara-string': session_id = request.POST['session_id'] if request.POST['yara-string'] != '': yara_string = request.POST['yara-string'] else: yara_string = False if request.POST['yara-pid'] != '': yara_pid = request.POST['yara-pid'] else: yara_pid = None if request.POST['yara-file'] != '': yara_file = os.path.join('yararules', request.POST['yara-file']) yara_hex = request.POST['yara-hex'] if yara_hex != '': yara_hex = int(yara_hex) else: yara_hex = 256 yara_reverse = request.POST['yara-reverse'] if yara_reverse != '': yara_reverse = int(yara_reverse) else: yara_reverse = 0 yara_case = request.POST['yara-case'] if yara_case == 'true': yara_case = True else: yara_case = None yara_kernel = request.POST['yara-kernel'] if yara_kernel == 'true': yara_kernel = True else: yara_kernel = None yara_wide = request.POST['yara-wide'] if yara_wide == 'true': yara_wide = True else: yara_wide = None logger.debug('Yara String Scanner') try: session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) if yara_string: results = vol_int.run_plugin('yarascan', output_style='json', pid=yara_pid, plugin_options={'YARA_RULES': yara_string, 'CASE': yara_case, 'ALL': yara_kernel, 'WIDE': yara_wide, 'SIZE': yara_hex, 'REVERSE': yara_reverse}) elif yara_file: results = vol_int.run_plugin('yarascan', output_style='json', pid=yara_pid, plugin_options={'YARA_FILE': yara_file, 'CASE': yara_case, 'ALL': yara_kernel, 'WIDE': yara_wide, 'SIZE': yara_hex, 'REVERSE': yara_reverse}) else: return if 'Data' in results['columns']: row_loc = results['columns'].index('Data') for row in results['rows']: try: row[row_loc] = string_clean_hex(row[row_loc].decode('hex')) except Exception as e: logger.warning('Error converting hex to str: {0}'.format(e)) return render(request, 'file_details_yara.html', {'yara': results, 'error': None}) #return render(request, 'plugin_output_nohtml.html', {'plugin_results': results, #'plugin_id': None, #'bookmarks': []}) #return HttpResponse(results) except Exception as error: logger.error(error) if command == 'yara': file_id = rule_file = False if 'file_id' in request.POST: file_id = request.POST['file_id'] if 'rule_file' in request.POST: rule_file = request.POST['rule_file'] if rule_file and file_id and YARA: file_object = db.get_filebyid(ObjectId(file_id)) file_data = file_object.read() rule_file = os.path.join('yararules', rule_file) if os.path.exists(rule_file): rules = yara.compile(rule_file) matches = rules.match(data=file_data) results = {'rows': [], 'columns': ['Rule', 'process', 'Offset', 'Data']} for match in matches: for item in match.strings: results['rows'].append([match.rule, file_object.filename, item[0], string_clean_hex(item[2])]) else: return render(request, 'file_details_yara.html', {'yara': None, 'error': 'Could not find Rule File'}) if len(results) > 0: # Store the results in datastore store_data = {} store_data['file_id'] = ObjectId(file_id) store_data['yara'] = results update = db.create_datastore(store_data) return render(request, 'file_details_yara.html', {'yara': results, 'error': None}) else: return HttpResponse('Either No file ID or No Yara Rule was provided') if command == 'strings': if 'file_id' in request.POST: file_id = request.POST['file_id'] file_object = db.get_filebyid(ObjectId(file_id)) file_data = file_object.read() chars = r"A-Za-z0-9/\-:.,_$%'()[\]<>@=+ " shortest_run = 4 regexp = '[%s]{%d,}' % (chars, shortest_run) pattern = re.compile(regexp) string_list = pattern.findall(file_data) logger.debug('Joining Strings') string_list = '\n'.join(string_list) ''' String lists can get larger than the 16Mb bson limit Need to store in GridFS ''' # Store the list in datastore store_data = {} store_data['file_id'] = ObjectId(file_id) store_data['string_list'] = string_list logger.debug('Store Strings in DB') string_id = db.create_file(string_list, 'session_id', 'sha256', '{0}_strings.txt'.format(file_id)) # Write to DB #db.create_datastore(store_data) return HttpResponse('<td><a class="btn btn-success" role="button" href="/download/file/{0}">Download</a></td>'.format(string_id)) if command == 'dropsession': if 'session_id' in request.POST: session_id = ObjectId(request.POST['session_id']) db.drop_session(session_id) return HttpResponse('OK') if command == 'memhex': if 'session_id' in request.POST: session_id = ObjectId(request.POST['session_id']) session = db.get_session(session_id) mem_path = session['session_path'] if 'start_offset' and 'end_offset' in request.POST: try: start_offset = int(request.POST['start_offset'], 0) end_offset = int(request.POST['end_offset'], 0) hex_cmd = 'hexdump -C -s {0} -n {1} {2}'.format(start_offset, end_offset - start_offset, mem_path) hex_output = hex_dump(hex_cmd) return HttpResponse(hex_output) except Exception as e: return HttpResponse(e) if command == 'memhexdump': if 'session_id' in request.POST: session_id = ObjectId(request.POST['session_id']) session = db.get_session(session_id) mem_path = session['session_path'] if 'start_offset' and 'end_offset' in request.POST: try: start_offset = int(request.POST['start_offset'], 0) end_offset = int(request.POST['end_offset'], 0) mem_file = open(mem_path, 'rb') # Get to start mem_file.seek(start_offset) file_data = mem_file.read(end_offset - start_offset) response = HttpResponse(file_data, content_type='application/octet-stream') response['Content-Disposition'] = 'attachment; filename="{0}-{1}.bin"'.format(start_offset, end_offset) return response except Exception as e: logger.error('Error Getting hex dump: {0}'.format(e)) if command == 'addcomment': html_resp = '' if 'session_id' and 'comment_text' in request.POST: session_id = request.POST['session_id'] comment_text = request.POST['comment_text'] comment_data = {'session_id': ObjectId(session_id), 'comment_text': comment_text, 'date_added': datetime.now()} db.create_comment(comment_data) # now return all the comments for the ajax update for comment in db.get_commentbysession(ObjectId(session_id)): html_resp += '<pre>{0}</pre>'.format(comment['comment_text']) return HttpResponse(html_resp) if command == 'searchbar': if 'search_type' and 'search_text' and 'session_id' in request.POST: search_type = request.POST['search_type'] search_text = request.POST['search_text'] session_id = request.POST['session_id'] logger.debug('{0} search for {1}'.format(search_type, search_text)) if search_type == 'plugin': results = {'rows':[]} results['columns'] = ['Plugin Name', 'View Results'] rows = db.search_plugins(search_text, session_id=ObjectId(session_id)) for row in rows: results['rows'].append([row['plugin_name'], '<a href="#" onclick="ajaxHandler(\'pluginresults\', {{\'plugin_id\':\'{0}\'}}, false ); return false">View Output</a>'.format(row['_id'])]) return render(request, 'plugin_output.html', {'plugin_results': results}) if search_type == 'hash': pass if search_type == 'string': logger.debug('yarascan for string') # If search string ends with .yar assume a yara rule if any(ext in search_text for ext in ['.yar', '.yara']): if os.path.exists(search_text): try: session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) results = vol_int.run_plugin('yarascan', output_style='json', plugin_options={'YARA_FILE': search_text}) return render(request, 'plugin_output_nohtml.html', {'plugin_results': results}) except Exception as error: logger.error(error) else: logger.error('No Yara Rule Found') else: try: session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) results = vol_int.run_plugin('yarascan', output_style='json', plugin_options={'YARA_RULES': search_text}) return render(request, 'plugin_output_nohtml.html', {'plugin_results': results}) except Exception as error: logger.error(error) if search_type == 'registry': logger.debug('Registry Search') try: session = db.get_session(ObjectId(session_id)) vol_int = RunVol(session['session_profile'], session['session_path']) results = vol_int.run_plugin('printkey', output_style='json', plugin_options={'KEY': search_text}) return render(request, 'plugin_output.html', {'plugin_results': results}) except Exception as error: logger.error(error) if search_type == 'vol': # Run a vol command and get the output session = db.get_session(ObjectId(session_id)) search_text = search_text.replace('%profile%', '--profile={0}'.format(session['session_profile'])) search_text = search_text.replace('%path%', '-f {0}'.format(session['session_path'])) vol_output = getoutput('vol.py {0}'.format(search_text)) results = {'rows': [['<pre>{0}</pre>'.format(vol_output)]], 'columns': ['Volatility Raw Output']} # Consider storing the output here as well. return render(request, 'plugin_output.html', {'plugin_results': results, 'bookmarks': []}) return HttpResponse('No valid search query found.') if command == 'pluginresults': if 'plugin_id' in request.POST: plugin_id = ObjectId(request.POST['plugin_id']) plugin_id = ObjectId(plugin_id) plugin_results = db.get_pluginbyid(plugin_id) try: bookmarks = db.get_pluginbyid(plugin_id)['bookmarks'] except: bookmarks = [] return render(request, 'plugin_output.html', {'plugin_results': plugin_results['plugin_output'], 'plugin_id': plugin_id, 'bookmarks': bookmarks, 'plugin_name': plugin_results['plugin_name']}) if command == 'bookmark': if 'row_id' in request.POST: plugin_id, row_id = request.POST['row_id'].split('_') plugin_id = ObjectId(plugin_id) row_id = int(row_id) # Get Bookmarks for plugin try: bookmarks = db.get_pluginbyid(plugin_id)['bookmarks'] except: bookmarks = [] # Update bookmarks if row_id in bookmarks: bookmarks.remove(row_id) bookmarked = 'remove' else: bookmarks.append(row_id) bookmarked = 'add' # Update Plugins new_values = {'bookmarks': bookmarks} db.update_plugin(ObjectId(plugin_id), new_values) return HttpResponse(bookmarked) if command == 'procmem': if 'row_id' in request.POST and 'session_id' in request.POST: plugin_id, row_id = request.POST['row_id'].split('_') session_id = request.POST['session_id'] plugin_id = ObjectId(plugin_id) row_id = int(row_id) plugin_data = db.get_pluginbyid(ObjectId(plugin_id))['plugin_output'] row = plugin_data['rows'][row_id - 1] pid = row[2] plugin_row = db.get_plugin_byname('memdump', ObjectId(session_id)) logger.debug('Running Plugin: memdump with pid {0}'.format(pid)) res = run_plugin(session_id, plugin_row['_id'], pid=pid) return HttpResponse(res) if command == 'filedump': if 'row_id' in request.POST and 'session_id' in request.POST: plugin_id, row_id = request.POST['row_id'].split('_') session_id = request.POST['session_id'] plugin_id = ObjectId(plugin_id) row_id = int(row_id) plugin_data = db.get_pluginbyid(ObjectId(plugin_id))['plugin_output'] row = plugin_data['rows'][row_id - 1] offset = row[0] plugin_row = db.get_plugin_byname('dumpfiles', ObjectId(session_id)) logger.debug('Running Plugin: dumpfiles with offset {0}'.format(offset)) res = run_plugin(session_id, plugin_row['_id'], plugin_options={'PHYSOFFSET':str(offset), 'NAME':True, 'REGEX':None}) return HttpResponse(res) return HttpResponse('No valid search query found.')