def get_report(self, sample): """ Return oletools report or create if not already cached. """ if sample.oletools_report != None: return sample.oletools_report report = {} try: vbaparser = VBA_Parser(sample.file_path) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros( ) or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # no macros pass vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) sample.register_oletools_report(OletoolsReport(report)) return report
def get_report(self): """ Return oletools report or create if not already cached. """ if self.sample.oletools_report is not None: return self.sample.oletools_report report = { 'autoexec': [], 'suspicious': [], } file_path = self.sample.file_path try: vbaparser = VBA_Parser(file_path) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros( ) or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # office document with no macros pass all_macros = vbaparser.extract_all_macros() if (report['has_macros'] and len(all_macros) == 1 and isinstance(all_macros[0], tuple) and len(all_macros[0]) >= 3 and all_macros[0][2] == file_path): logger.warning( "Buggy oletools version detected, result overridden. May " "lead to false negatives, please update to fixed version") report['has_macros'] = False if vbaparser.detect_vba_macros(): vb_code = vbaparser.extract_all_macros() for (_, _, _, c) in vb_code: autoexec = detect_autoexec(c) if len(autoexec) >= 1: report['autoexec'].append(autoexec[0]) suspicious = detect_suspicious(c) if len(suspicious) >= 1: report['suspicious'].append(suspicious[0]) vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) report = OletoolsReport(report) self.sample.register_oletools_report(report) return report
def get_report(self, sample): """ Return oletools report or create if not already cached. """ if sample.oletools_report != None: return sample.oletools_report report = {} if sample.file_extension not in self.MS_OFFICE_EXTENSIONS: raise OleNotAnOfficeDocumentException(sample.file_extension) try: vbaparser = VBA_Parser(sample.file_path) # List from oletools/olevba.py#L553 oletype = ('OLE', 'OpenXML', 'FlatOPC_XML', 'Word2003_XML', 'MHTML', 'PPT') # check if ole detects it as an office file if vbaparser.type not in oletype: raise OleNotAnOfficeDocumentException(sample.file_extension) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros( ) or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # no macros pass vbaparser.close() except IOError: raise except TypeError: # The given file is not an office document. pass except Exception as error: logger.exception(error) sample.register_oletools_report(OletoolsReport(report)) return report
def detect(self, filename): return_list = [] vbaparser = VBA_Parser(filename) if vbaparser.detect_vba_macros(): for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): return_list.append({ 'filename': filename, 'ole_stream': stream_path, 'vba_filename': vba_filename, 'vba_code': vba_code }) results = vbaparser.analyze_macros() for kw_type, keyword, description in results: return_list.append({ 'type': kw_type, 'keyword': keyword, 'description': description }) return_list.append({'revealed_macro': vbaparser.reveal()}) return return_list else: return None
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 = {} # olevba olevba_results = {} try: vbaparser = VBA_Parser(filepath) olevba_results[ 'macro_found'] = True if vbaparser.detect_vba_macros( ) else False if olevba_results['macro_found']: macro_data = [] for (v_filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): extracted_macro = { "filename": v_filename, "ole_stream": stream_path, "vba_filename": vba_filename, "vba_code": vba_code } macro_data.append(extracted_macro) olevba_results['macro_data'] = macro_data # example output ''' {'description': 'Runs when the Word document is opened', 'keyword': 'AutoOpen', 'type': 'AutoExec'}, {'description': 'May run an executable file or a system command', 'keyword': 'Shell', 'type': 'Suspicious'}, {'description': 'May run an executable file or a system command', 'keyword': 'WScript.Shell', 'type': 'Suspicious'}, {'description': 'May run an executable file or a system command', 'keyword': 'Run', 'type': 'Suspicious'}, {'description': 'May run PowerShell commands', 'keyword': 'powershell', 'type': 'Suspicious'}, {'description': '9BA55BE5', 'keyword': 'xxx', 'type': 'Hex String'}, ''' analyzer_results = vbaparser.analyze_macros( show_decoded_strings=True) # it gives None if it does not find anything if analyzer_results: analyze_macro_results = [] for kw_type, keyword, description in analyzer_results: if kw_type != 'Hex String': analyze_macro_result = { "type": kw_type, "keyword": keyword, "description": description } analyze_macro_results.append(analyze_macro_result) olevba_results['analyze_macro'] = analyze_macro_results olevba_results['reveal'] = vbaparser.reveal() vbaparser.close() except Exception as e: traceback.print_exc() error_message = "job_id {} vba parser failed. Error: {}".format( job_id, e) logger.exception(error_message) report['errors'].append(error_message) results['olevba'] = olevba_results # mraptor macro_raptor = mraptor.MacroRaptor(olevba_results.get('reveal', '')) if macro_raptor: macro_raptor.scan() results[ 'mraptor'] = "suspicious" if macro_raptor.suspicious else 'ok' # pprint.pprint(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) logger.info("ended analyzer {} job_id {}" "".format(analyzer_name, job_id)) return report
def run(self): results = {} # olevba olevba_results = {} try: vbaparser = VBA_Parser(self.filepath) olevba_results["macro_found"] = ( True if vbaparser.detect_vba_macros() else False ) if olevba_results["macro_found"]: macro_data = [] for ( v_filename, stream_path, vba_filename, vba_code, ) in vbaparser.extract_macros(): extracted_macro = { "filename": v_filename, "ole_stream": stream_path, "vba_filename": vba_filename, "vba_code": vba_code, } macro_data.append(extracted_macro) olevba_results["macro_data"] = macro_data # example output """ {'description': 'Runs when the Word document is opened', 'keyword': 'AutoOpen', 'type': 'AutoExec'}, {'description': 'May run an executable file or a system command', 'keyword': 'Shell', 'type': 'Suspicious'}, {'description': 'May run an executable file or a system command', 'keyword': 'WScript.Shell', 'type': 'Suspicious'}, {'description': 'May run an executable file or a system command', 'keyword': 'Run', 'type': 'Suspicious'}, {'description': 'May run PowerShell commands', 'keyword': 'powershell', 'type': 'Suspicious'}, {'description': '9BA55BE5', 'keyword': 'xxx', 'type': 'Hex String'}, """ analyzer_results = vbaparser.analyze_macros(show_decoded_strings=True) # it gives None if it does not find anything if analyzer_results: analyze_macro_results = [] for kw_type, keyword, description in analyzer_results: if kw_type != "Hex String": analyze_macro_result = { "type": kw_type, "keyword": keyword, "description": description, } analyze_macro_results.append(analyze_macro_result) olevba_results["analyze_macro"] = analyze_macro_results olevba_results["reveal"] = vbaparser.reveal() vbaparser.close() except Exception as e: traceback.print_exc() error_message = f"job_id {self.job_id} vba parser failed. Error: {e}" logger.exception(error_message) self.report["errors"].append(error_message) results["olevba"] = olevba_results # mraptor macro_raptor = mraptor.MacroRaptor(olevba_results.get("reveal", None)) if macro_raptor: macro_raptor.scan() results["mraptor"] = "suspicious" if macro_raptor.suspicious else "ok" return results
def get_report(self): """ Return oletools report or create if not already cached. """ if self.sample.oletools_report is not None: return self.sample.oletools_report report = { 'autoexec': [], 'suspicious' : [], } filename = self.sample.filename try: vbaparser = VBA_Parser(filename, data=self.sample.content) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros() or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # office document with no macros pass # When called on an empty or text document oletools will falsely # report that it contains macros and returns a one item list of # macros which contains only the filename again. # # Oletool assume the submitted file is the plain text macro if # it can not determine another file type. # # Add a workaround to detect this behaviour and override the # result. all_macros = vbaparser.extract_all_macros() if (report['has_macros'] and len(all_macros) == 1 and isinstance(all_macros[0], tuple) and len(all_macros[0]) >= 3 and all_macros[0][2] == filename): report['has_macros'] = False if vbaparser.detect_vba_macros(): vb_code = vbaparser.extract_all_macros() for (_, _, _, c) in vb_code: autoexec = detect_autoexec(c) if len(autoexec) >= 1: report['autoexec'].extend(autoexec) suspicious = detect_suspicious(c) if len(suspicious) >= 1: report['suspicious'].extend(suspicious) vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) report = OletoolsReport(report) self.sample.register_oletools_report(report) return report
def ProcessFile(path): if not(os.path.isfile(path)): print '{0} not a file!'.format(path) return 2 try: data = {} data['valid'] = True oledata = {} vbaparser = VBA_Parser(path) oledata['has_macros'] = vbaparser.detect_vba_macros() # dump macros content macros = [] for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): macro = {} macro['filename'] = filename macro['stream'] = stream_path macro['vba'] = vba_filename macro['content'] = convert_to_printable_null_terminated(vba_code) macros.append(macro) oledata['macros'] = macros # macro analysis macros_warnings = [] results = vbaparser.analyze_macros() for kw_type, keyword, description in results: warning = {} warning['type'] = kw_type warning['keyword'] = keyword warning['description'] = description macros_warnings.append(warning) oledata['macros_warnings'] = macros_warnings # counters counters = {} counters['autoexec'] = vbaparser.nb_autoexec counters['suspicious'] = vbaparser.nb_suspicious counters['iocs'] = vbaparser.nb_iocs counters['hexstrings'] = vbaparser.nb_hexstrings counters['base64strings'] = vbaparser.nb_base64strings counters['dridexstrings'] = vbaparser.nb_dridexstrings counters['vbastrings'] = vbaparser.nb_vbastrings oledata['counters'] = counters # deobfuscation oledata['deobfuscated'] = convert_to_printable_null_terminated(vbaparser.reveal()) # close vbaparser.close() data['data'] = oledata encoded = json.dumps(data) print encoded except Exception as ex: data = {} data['valid'] = False data['error'] = str(ex) print json.dumps(data) return 1 return 0