def vt_scan_file(api_key, md5, job_id, additional_config_params): try: binary = general.get_binary(job_id) except Exception: raise AnalyzerRunException( "couldn't retrieve the binary to perform a scan") headers = {'x-apikey': api_key} files = {'file': binary} uri = 'files' try: response = requests.post(vt_base + uri, files=files, headers=headers) response.raise_for_status() except requests.RequestException as e: raise AnalyzerRunException(e) result = response.json() # pprint.pprint(result) result_data = result.get('data', {}) scan_id = result_data.get('id', '') if not scan_id: raise AnalyzerRunException( "no scan_id given by VirusTotal to retrieve the results") # max 5 minutes waiting max_tries = additional_config_params.get('max_tries', 100) poll_distance = 5 got_result = False uri = "analyses/{}".format(scan_id) for chance in range(max_tries): time.sleep(poll_distance) logger.info( "vt polling, try n.{}. job_id {}. starting the query".format( chance + 1, job_id)) try: response = requests.get(vt_base + uri, headers=headers) response.raise_for_status() except requests.RequestException as e: raise AnalyzerRunException(e) json_response = response.json() # pprint.pprint(json_response) analysis_status = json_response.get('data', {}).get('attributes', {}).get('status', '') if analysis_status == "completed": got_result = True break else: logger.info("vt polling, try n.{}. job_id {}. status:{}".format( chance + 1, job_id, analysis_status)) if not got_result: raise AnalyzerRunException( "max VT polls tried without getting any result. job_id {}".format( job_id)) # retrieve the FULL report, not only scans results. If it's a new sample, it's free of charge result = vt3_get.vt_get_report(api_key, md5, "hash", {}, job_id) # pprint.pprint(result) return result
def run(analyzer_name, job_id, filepath, filename, md5, additional_config_params): logger.info("started analyzer {} job_id {}" "".format(analyzer_name, job_id)) report = general.get_basic_report_template(analyzer_name) try: # cuckoo installation can be with or without the api_token # it depends on version and configuration api_key_name = additional_config_params.get("api_key_name", "") if api_key_name: api_key = secrets.get_secret(api_key_name) else: api_key = None logger.info("job_id {} md5 {} analyzer {} no API key set" "".format(job_id, md5, analyzer_name)) cuckoo_url = secrets.get_secret("CUCKOO_URL") if not cuckoo_url: raise AnalyzerRunException("cuckoo URL missing") cuckoo_analysis = CuckooAnalysis(api_key, cuckoo_url) binary = general.get_binary(job_id) if not binary: raise AnalyzerRunException("is the binary empty?!") _cuckoo_scan_file(cuckoo_analysis, additional_config_params, filename, md5, binary) result = cuckoo_analysis.report # pprint.pprint(result) report["report"] = result except AnalyzerRunException as e: error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Analyzer Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.error(error_message) report["errors"].append(error_message) report["success"] = False except Exception as e: traceback.print_exc() error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Unexpected Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.exception(error_message) report["errors"].append(str(e)) report["success"] = False else: report["success"] = True general.set_report_and_cleanup(job_id, report) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report
def run(analyzer_name, job_id, filepath, filename, md5, additional_config_params): logger.info("started analyzer {} job_id {}" "".format(analyzer_name, job_id)) report = general.get_basic_report_template(analyzer_name) try: api_key_name = additional_config_params.get("api_key_name", "") if not api_key_name: api_key_name = "INTEZER_KEY" api_key = secrets.get_secret(api_key_name) if not api_key: raise AnalyzerRunException("no api key retrieved") intezer_token = os.environ.get("INTEZER_TOKEN", "") intezer_token_date = os.environ.get("INTEZER_TOKEN_DATE", "") today = get_now_date_only() if not intezer_token or intezer_token_date != today: intezer_token = _get_access_token(api_key) if not intezer_token: raise AnalyzerRunException("token extraction failed") binary = general.get_binary(job_id) result = _intezer_scan_file(intezer_token, md5, filename, binary, additional_config_params) # pprint.pprint(result) report["report"] = result except AnalyzerRunException as e: error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Analyzer Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.error(error_message) report["errors"].append(error_message) report["success"] = False except Exception as e: traceback.print_exc() error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Unexpected Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.exception(error_message) report["errors"].append(str(e)) report["success"] = False else: report["success"] = True general.set_report_and_cleanup(job_id, report) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report
def run(analyzer_name, job_id, filepath, filename, md5, additional_config_params): logger.info("started analyzer {} job_id {}" "".format(analyzer_name, job_id)) report = general.get_basic_report_template(analyzer_name) try: results = {} results["magic"] = magic.from_file(filepath) results["mimetype"] = magic.from_file(filepath, mime=True) results["filetype"] = pyexifinfo.fileType(filepath) exif_report = pyexifinfo.get_json(filepath) if exif_report: exif_report_cleaned = { key: value for key, value in exif_report[0].items() if not (key.startswith("File") or key.startswith("SourceFile")) } results["exiftool"] = exif_report_cleaned binary = general.get_binary(job_id) results["md5"] = hashlib.md5(binary).hexdigest() results["sha1"] = hashlib.sha1(binary).hexdigest() results["sha256"] = hashlib.sha256(binary).hexdigest() results["ssdeep"] = pydeep.hash_file(filepath).decode() report["report"] = results except AnalyzerRunException as e: error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Analyzer Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.error(error_message) report["errors"].append(error_message) report["success"] = False except Exception as e: traceback.print_exc() error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Unexpected Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.exception(error_message) report["errors"].append(str(e)) report["success"] = False else: report["success"] = True general.set_report_and_cleanup(job_id, report) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report
def run(analyzer_name, job_id, filepath, filename, md5, additional_config_params): logger.info("started analyzer {} job_id {}" "".format(analyzer_name, job_id)) report = general.get_basic_report_template(analyzer_name) try: api_key_name = additional_config_params.get('api_key_name', '') if not api_key_name: api_key_name = "VT_KEY" api_key = secrets.get_secret(api_key_name) if not api_key: raise AnalyzerRunException("no api key retrieved") # this is a config value that can be used to force the waiting of the scan result anyway wait_for_scan_anyway = additional_config_params.get( 'wait_for_scan_anyway', False) notify_url = secrets.get_secret("VT_NOTIFY_URL") binary = general.get_binary(job_id, logger) result = _vt_scan_file(api_key, notify_url, binary) # in case we didn't use the webhook to get the result of the scan, start a poll for the result # or in case we'd like to force the scan anyway from the configuration if not notify_url or wait_for_scan_anyway: scan_id = result.get('scan_id', '') if not scan_id: raise (AnalyzerRunException( "no scan_id given by VirusTotal to retrieve the results")) # max 5 minutes waiting max_tries = 10 poll_distance = 30 got_result = False for chance in range(max_tries): time.sleep(poll_distance) logger.info("vt polling, try n.{}. job_id {}".format( chance + 1, job_id)) result = vt2_get.vt_get_report(api_key, scan_id, "hash") response_code = result.get('response_code', 1) # response code -2 means the we still have to wait if response_code == -2: continue elif response_code == 1: got_result = True logger.info( "vt polling retrieved the result correctly for job_id {}" .format(job_id)) break if not got_result: logger.info( "max VT polls tried without getting any result. job_id {}". format(job_id)) # pprint.pprint(result) report['report'] = result except AnalyzerRunException as e: error_message = "job_id:{} analyzer:{} md5:{} filename: {} Analyzer Error {}" \ "".format(job_id, analyzer_name, md5, filename, e) logger.error(error_message) report['errors'].append(error_message) report['success'] = False except Exception as e: traceback.print_exc() error_message = "job_id:{} analyzer:{} md5:{} filename: {} Unexpected Error {}" \ "".format(job_id, analyzer_name, md5, filename, e) logger.exception(error_message) report['errors'].append(str(e)) report['success'] = False else: report['success'] = True general.set_report_and_cleanup(job_id, report, logger) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report
def run(analyzer_name, job_id, filepath, filename, md5, additional_config_params): logger.info("started analyzer {} job_id {}" "".format(analyzer_name, job_id)) report = general.get_basic_report_template(analyzer_name) try: results = {} rtfobj_results = {} binary = general.get_binary(job_id) rtfp = RtfObjParser(binary) rtfp.parse() rtfobj_results["ole_objects"] = [] for rtfobj in rtfp.objects: if rtfobj.is_ole: class_name = rtfobj.class_name.decode() ole_dict = { "format_id": rtfobj.format_id, "class_name": class_name, "ole_datasize": rtfobj.oledata_size, } if rtfobj.is_package: ole_dict["is_package"] = True ole_dict["filename"] = rtfobj.filename ole_dict["src_path"] = rtfobj.src_path ole_dict["temp_path"] = rtfobj.temp_path ole_dict["olepkgdata_md5"] = rtfobj.olepkgdata_md5 else: ole_dict["ole_md5"] = rtfobj.oledata_md5 if rtfobj.clsid: ole_dict["clsid_desc"] = rtfobj.clsid_desc ole_dict["clsid_id"] = rtfobj.clsid rtfobj_results["ole_objects"].append(ole_dict) # http://www.kb.cert.org/vuls/id/921560 if class_name == "OLE2Link": rtfobj_results["exploit_ole2link_vuln"] = True # https://www.kb.cert.org/vuls/id/421280/ elif class_name.lower() == "equation.3": rtfobj_results["exploit_equation_editor"] = True results["rtfobj"] = rtfobj_results report["report"] = results except AnalyzerRunException as e: error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Analyzer Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.error(error_message) report["errors"].append(error_message) report["success"] = False except Exception as e: traceback.print_exc() error_message = ( "job_id:{} analyzer:{} md5:{} filename: {} Unexpected Error {}" "".format(job_id, analyzer_name, md5, filename, e)) logger.exception(error_message) report["errors"].append(str(e)) report["success"] = False else: report["success"] = True general.set_report_and_cleanup(job_id, report) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report