Exemple #1
0
    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
Exemple #2
0
def get_macros():
    extracted_macros = []
    macro_analysis = []
    tags = []

    try:
        vbaparser = VBA_Parser('/sample')
        vbaparser.detect_vba_macros()

        for (filename, stream_path, vba_filename,
             vba_code) in vbaparser.extract_macros():
            extracted_macros.append({
                "stream_path": stream_path,
                "vba_filename": vba_filename,
                "vba_code": vba_code
            })

        try:
            for kw_type, keyword, description in vbaparser.analyze_macros():
                macro_analysis.append({
                    "kw_type": kw_type,
                    "keyword": keyword,
                    "description": description
                })

                if keyword == 'Shell':
                    tags.append('run-file')
        except TypeError:
            pass

        macro_suspicious_categories = {
            "nb_macros": vbaparser.nb_macros,
            "nb_autoexec": vbaparser.nb_autoexec,
            "nb_suspicious": vbaparser.nb_suspicious,
            "nb_iocs": vbaparser.nb_iocs,
            "nb_hexstrings": vbaparser.nb_hexstrings,
            "nb_base64strings": vbaparser.nb_base64strings,
            "nb_dridexstrings": vbaparser.nb_dridexstrings,
            "nb_vbastrings": vbaparser.nb_vbastrings,
        }

        if vbaparser.nb_macros:
            tags.append('macros')

        if vbaparser.nb_hexstrings or vbaparser.nb_base64strings:
            tags.append('obfuscated')

    except FileOpenError:
        return None, tags

    return {
        "extracted_macros": extracted_macros,
        "macro_analysis": macro_analysis,
        "macro_suspicious_categories": macro_suspicious_categories
    }, tags
	def doc_parsing(self, filename, filecontent):
		'''
			Function to parse the given data in mail content
		'''
		mil_attach = '' # reset var
		# send data to vba parser
		vbaparser = VBA_Parser(filename, data=filecontent)
		# if a macro is detected
		if vbaparser.detect_vba_macros():
			results = vbaparser.analyze_macros()
			nr = 1
			self.log("VBA Macros found")
			# generate report for log file
			for kw_type, keyword, description in results:
				if kw_type == 'Suspicious':
					mil_attach += 'Macro Number %i:\n Type: %s\n Keyword: %s\n Description: %s\n' % (nr, kw_type, keyword, description)
				nr += 1
			mil_attach += '\nSummery:\nAutoExec keywords: %d\n' % vbaparser.nb_autoexec
			mil_attach += 'Suspicious keywords: %d\n' % vbaparser.nb_suspicious
			mil_attach += 'IOCs: %d\n' % vbaparser.nb_iocs
			mil_attach += 'Hex obfuscated strings: %d\n' % vbaparser.nb_hexstrings
			mil_attach += 'Base64 obfuscated strings: %d\n' % vbaparser.nb_base64strings
			mil_attach += 'Dridex obfuscated strings: %d\n' % vbaparser.nb_dridexstrings
			mil_attach += 'VBA obfuscated strings: %d' % vbaparser.nb_vbastrings
			
			r_level = vbaparser.nb_autoexec + vbaparser.nb_suspicious + vbaparser.nb_iocs + vbaparser.nb_hexstrings + vbaparser.nb_base64strings + vbaparser.nb_dridexstrings + vbaparser.nb_vbastrings
			
			# set reject level to global
			self.level = r_level
			vbaparser.close()
			return mil_attach # return the log to caller
		else:
			self.log("VBA no Macros found in file")
			vbaparser.close()
			return None # nothing found
Exemple #4
0
 def parse_vba(self, save_path):
     save = False
     vbaparser = VBA_Parser(__sessions__.current.file.path)
     # Check for Macros
     if not vbaparser.detect_vba_macros():
         self.log('error', "No Macro's Detected")
         return
     self.log('info', "Macro's Detected")
     #try:
     if True:
         an_results = {'AutoExec':[], 'Suspicious':[], 'IOC':[], 'Hex String':[], 'Base64 String':[], 'Dridex String':[], 'VBA string':[]}
         for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
             self.log('info', "Stream Details")
             self.log('item', "OLE Stream: {0}".format(string_clean(stream_path)))
             self.log('item', "VBA Filename: {0}".format(string_clean(vba_filename)))
             # Analyse the VBA Code
             vba_scanner = VBA_Scanner(vba_code)
             analysis = vba_scanner.scan(include_decoded_strings=True)
             for kw_type, keyword, description in analysis:
                 an_results[kw_type].append([string_clean_hex(keyword), description])
                 
             # Save the code to external File
             if save_path:
                 try:
                     with open(save_path, 'a') as out:
                         out.write(vba_code)
                     save = True
                 except:
                     self.log('error', "Unable to write to {0}".format(save_path))
                     return
         # Print all Tables together
         self.log('info', "AutoRun Macros Found")
         self.log('table', dict(header=['Method', 'Description'], rows=an_results['AutoExec']))
         
         self.log('info', "Suspicious Keywords Found")
         self.log('table', dict(header=['KeyWord', 'Description'], rows=an_results['Suspicious']))
         
         self.log('info', "Possible IOC's")
         self.log('table', dict(header=['IOC', 'Type'], rows=an_results['IOC']))
         
         self.log('info', "Hex Strings")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Hex String']))
         
         self.log('info', "Base64 Strings")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Base64 String']))
         
         self.log('info', "Dridex String")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Dridex String']))
         
         self.log('info', "VBA string")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['VBA string']))
         
         
         
         if save:
             self.log('success', "Writing VBA Code to {0}".format(save_path))
     #except:
         #self.log('error', "Unable to Process File")
     # Close the file
     vbaparser.close()
Exemple #5
0
def EXTRACT_VBA_MACRO(s, buff):

    EXTRACT_MACRO = {}
    counter = 0

    ### TODO: REMOVE THIS WORKAROUND ONCE MODULE AUTHOR FIXES CODE ###
    ### Reference: http://stackoverflow.com/questions/32261679/strange-issue-using-logging-module-in-python/32264445#32264445
    ### Reference: https://bitbucket.org/decalage/oletools/issues/26/use-of-logger
    ### /dev/null used instead of NullHandler for 2.6 compatibility
    logging.getLogger('workaround').root.addHandler(
        logging.FileHandler('/dev/null'))
    ###

    vba = VBA_Parser('None', data=buff)

    if not vba.detect_vba_macros():
        return EXTRACT_MACRO

    for (filename, stream_path, vba_filename,
         vba_code) in vba.extract_macros():

        CHILD_MACRO = OrderedDict([('OLE Stream', stream_path),
                                   ('VBA Filename',
                                    vba_filename.decode('ascii', 'ignore')),
                                   ('Scan', scan_macro(vba_code)),
                                   ('Buffer', vba_code)])

        EXTRACT_MACRO['Object_%s' % counter] = CHILD_MACRO
        counter += 1

    return EXTRACT_MACRO
Exemple #6
0
def olevba_trig(file):
    try:
        vbaparser = VBA_Parser(file)
        if vbaparser.detect_vba_macros():
            for (filename, stream_path, vba_filename,
                 vba_code) in vbaparser.extract_macros():
                print('Filename    :', filename)
                print('OLE stream  :', stream_path)
                print('VBA filename:', vba_filename)
                print('- ' * 39)
                print(vba_code)
                print('- ' * 39)

                results = vbaparser.analyze_macros()
                for kw_type, keyword, description in results:
                    print('type=%s - keyword=%s - description=%s' %
                          (kw_type, keyword, description))

                print('AutoExec keywords: %d' % vbaparser.nb_autoexec)
                print('Suspicious keywords: %d' % vbaparser.nb_suspicious)
                print('IOCs: %d' % vbaparser.nb_iocs)
                print('Hex obfuscated strings: %d' % vbaparser.nb_hexstrings)
                print('Base64 obfuscated strings: %d' %
                      vbaparser.nb_base64strings)
                print('Dridex obfuscated strings: %d' %
                      vbaparser.nb_dridexstrings)
                print('VBA obfuscated strings: %d' % vbaparser.nb_vbastrings)
                print("\n")

    except:
        e = sys.exc_info()[0]
        print(f'{e} from {file}')
def EXTRACT_VBA_MACRO(s, buff):

   EXTRACT_MACRO = {}
   counter = 0

   ### TODO: REMOVE THIS WORKAROUND ONCE MODULE AUTHOR FIXES CODE ###
   ### Reference: http://stackoverflow.com/questions/32261679/strange-issue-using-logging-module-in-python/32264445#32264445
   ### Reference: https://bitbucket.org/decalage/oletools/issues/26/use-of-logger
   ### /dev/null used instead of NullHandler for 2.6 compatibility 
   logging.getLogger('workaround').root.addHandler(logging.FileHandler('/dev/null'))
   ###

   vba = VBA_Parser('None', data=buff)

   if not vba.detect_vba_macros():
      return EXTRACT_MACRO

   for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros():

      CHILD_MACRO = OrderedDict([('OLE Stream', stream_path),
                                 ('VBA Filename', vba_filename.decode('ascii', 'ignore')),
                                 ('Scan', scan_macro(vba_code)),
                                 ('Buffer', vba_code)])

      EXTRACT_MACRO['Object_%s' % counter] = CHILD_MACRO
      counter += 1

   return EXTRACT_MACRO
Exemple #8
0
def parseOLEDocument(f):
	"""Parse an OLE document for VBA macros"""
	if not f or not useOLETools:
		return

	writeLog('DEBUG: Analyzing with oletools')
	try:
		v = VBA_Parser(f)
	except:
		writeLog("Not a supported file format: %s" % f)
		return
	writeLog('DEBUG: Detected file type: %s' % v.type)
	if v.detect_vba_macros():
		writeLog('DEBUG: VBA Macros found')
		try:
			t = open("%s.analysis" % f, 'w')
		except IOError as e:
			writeLog("Cannot create analysis file %s.analysis: %s" % (f,e.strerror))
			return
		for kw_type, keyword, description in v.analyze_macros():
			t.write("%-12s | %-25s | %s\n" % (kw_type, keyword, description))
		t.close()
		writeLog("DEBUG: Analysis dumped to %s.analysis" % f)
	else:
		writeLog('DEBUG: No VBA Macros found')
	return
Exemple #9
0
def extract_macros_from_office2003(fullpath, fileobj=None):
    '''

    :return: [(host_fullpath, filename_from_host, data), ... ]
    '''
    from oletools.olevba import VBA_Parser

    vp = VBA_Parser(fullpath, data=fileobj.read() if fileobj else None)

    r = []

    try:
        if vp.detect_vba_macros():
            macros = vp.extract_all_macros()
            assert (macros
                    )  # macros detect, if cannot extact, must be error occured
            if macros:
                for (subfullpath, stream_path, vba_filename,
                     vba_code) in macros:
                    a = os.path.basename(fullpath)
                    b = os.path.basename(subfullpath)
                    vba_filename += u'.vba'
                    sub = (io_text_arg(fullpath),
                           io_text_arg(vba_filename if a == b else u'{0}_{1}'.
                                       format(b, vba_filename)), vba_code)
                    r.append(sub)
    except:
        pass
    finally:
        vp.close()

    return r
Exemple #10
0
 def parse_vba(self, save_path):
     save = False
     vbaparser = VBA_Parser(__sessions__.current.file.path)
     # Check for Macros
     if not vbaparser.detect_vba_macros():
         self.log('error', "No Macro's Detected")
         return
     self.log('info', "Macro's Detected")
     #try:
     if True:
         an_results = {'AutoExec':[], 'Suspicious':[], 'IOC':[], 'Hex String':[], 'Base64 String':[], 'Dridex String':[], 'VBA string':[]}
         for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
             self.log('info', "Stream Details")
             self.log('item', "OLE Stream: {0}".format(string_clean(stream_path)))
             self.log('item', "VBA Filename: {0}".format(string_clean(vba_filename)))
             # Analyse the VBA Code
             vba_scanner = VBA_Scanner(vba_code)
             analysis = vba_scanner.scan(include_decoded_strings=True)
             for kw_type, keyword, description in analysis:
                 an_results[kw_type].append([string_clean_hex(keyword), description])
                 
             # Save the code to external File
             if save_path:
                 try:
                     with open(save_path, 'a') as out:
                         out.write(vba_code)
                     save = True
                 except:
                     self.log('error', "Unable to write to {0}".format(save_path))
                     return
         # Print all Tables together
         self.log('info', "AutoRun Macros Found")
         self.log('table', dict(header=['Method', 'Description'], rows=an_results['AutoExec']))
         
         self.log('info', "Suspicious Keywords Found")
         self.log('table', dict(header=['KeyWord', 'Description'], rows=an_results['Suspicious']))
         
         self.log('info', "Possible IOC's")
         self.log('table', dict(header=['IOC', 'Type'], rows=an_results['IOC']))
         
         self.log('info', "Hex Strings")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Hex String']))
         
         self.log('info', "Base64 Strings")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Base64 String']))
         
         self.log('info', "Dridex String")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Dridex String']))
         
         self.log('info', "VBA string")
         self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['VBA string']))
         
         
         
         if save:
             self.log('success', "Writing VBA Code to {0}".format(save_path))
     #except:
         #self.log('error', "Unable to Process File")
     # Close the file
     vbaparser.close()
Exemple #11
0
    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
Exemple #12
0
def parseOLEDocument(f):

	"""Parse an OLE document for VBA macros"""

	if not f or not useOLETools:
		return

	writeLog('DEBUG: Analyzing with oletools')
	try:
		v = VBA_Parser(f)
	except:
		writeLog("Not a supported file format: %s" % f)
		return
	writeLog('DEBUG: Detected file type: %s' % v.type)

	# Hack: Search for a .js extension
	fname, fextension = os.path.splitext(f)

	if v.detect_vba_macros() or fextension == ".js":
		writeLog('DEBUG: VBA Macros/JScript found')
		try:
			t = open("%s.analysis" % f, 'w')
		except IOError as e:
			writeLog("Cannot create analysis file %s.analysis: %s" % (f,e.strerror))
			return
		for kw_type, keyword, description in v.analyze_macros():
			t.write("%-12s | %-25s | %s\n" % (kw_type, keyword, description))
		t.close()
		writeLog("DEBUG: Analysis dumped to %s.analysis" % f)
	else:
		writeLog('DEBUG: No VBA Macros found')
	return
Exemple #13
0
def process_file_scanexpr (container, filename, data):
    """
    Process a single file

    :param container: str, path and filename of container if the file is within
    a zip archive, None otherwise.
    :param filename: str, path and filename of file on disk, or within the container.
    :param data: bytes, content of the file if it is in a container, None if it is a file on disk.
    """
    #TODO: replace print by writing to a provided output file (sys.stdout by default)
    if container:
        display_filename = '%s in %s' % (filename, container)
    else:
        display_filename = filename
    print '='*79
    print 'FILE:', display_filename
    all_code = ''
    try:
        #TODO: handle olefile errors, when an OLE file is malformed
        vba = VBA_Parser(filename, data)
        print 'Type:', vba.type
        if vba.detect_vba_macros():
            #print 'Contains VBA Macros:'
            for (subfilename, stream_path, vba_filename, vba_code) in vba.extract_macros():
                # hide attribute lines:
                #TODO: option to disable attribute filtering
                vba_code_filtered = filter_vba(vba_code)
                print '-'*79
                print 'VBA MACRO %s ' % vba_filename
                print 'in file: %s - OLE stream: %s' % (subfilename, repr(stream_path))
                print '- '*39
                # detect empty macros:
                if vba_code_filtered.strip() == '':
                    print '(empty macro)'
                else:
                    # TODO: option to display code
                    print vba_code_filtered
                    vba_code = vba_collapse_long_lines(vba_code)
                    all_code += '\n' + vba_code
            print '-'*79
            print 'EVALUATED VBA EXPRESSIONS:'
            t = prettytable.PrettyTable(('Obfuscated expression', 'Evaluated value'))
            t.align = 'l'
            t.max_width['Obfuscated expression'] = 36
            t.max_width['Evaluated value'] = 36
            for expression, expr_eval in scan_expressions(all_code):
                t.add_row((repr(expression), repr(expr_eval)))
            print t


        else:
            print 'No VBA macros found.'
    except: #TypeError:
        #raise
        #TODO: print more info if debug mode
        #print sys.exc_value
        # display the exception with full stack trace for debugging, but do not stop:
        traceback.print_exc()
    print ''
Exemple #14
0
 def is_file_has_VBA_macros(self):
     """Check if file has VBA macros."""
     file_path = self.file_path
     vbaparser = VBA_Parser(file_path)
     print('The file type is "%s"' % (vbaparser.type))
     report = vbaparser.detect_vba_macros()
     vbaparser.close()
     return report
Exemple #15
0
    def parse_vba(self, save_path):
        vba = VBA_Parser(__sessions__.current.file.path)
        # Check for Macros
        if not vba.detect_vba_macros():
            self.log('error', "No Macro's Detected")
            return
        self.log('info', "Macro's Detected")
        try:
            for (filename, stream_path, vba_filename,
                 vba_code) in vba.extract_macros():
                self.log('info', "Stream Details")
                self.log('item', "OLE Stream: {0}".format(stream_path))
                self.log('item', "VBA Filename: {0}".format(vba_filename))
                autoexec_keywords = detect_autoexec(vba_code)
                if autoexec_keywords:
                    self.log('info', "AutoRun Macros Found")
                    rows = []
                    for keyword, description in autoexec_keywords:
                        rows.append([keyword, description])
                    self.log(
                        'table',
                        dict(header=['KeyWord', 'Description'], rows=rows))
                # Match Keyword Types
                suspicious_keywords = detect_suspicious(vba_code)
                if suspicious_keywords:
                    self.log('info', "Suspicious Keywords Found")
                    rows = []
                    for keyword, description in suspicious_keywords:
                        rows.append([keyword, description])
                    self.log(
                        'table',
                        dict(header=['KeyWord', 'Description'], rows=rows))
                # Match IOCs
                patterns = detect_patterns(vba_code)
                if patterns:
                    self.log('info', "Suspicious Keywords Found")
                    rows = []
                    for pattern_type, value in patterns:
                        rows.append([pattern_type, value])
                    self.log('table',
                             dict(header=['Pattern', 'Value'], rows=rows))

                # Save the code to external File
                if save_path:
                    try:
                        with open(save_path, 'w') as out:
                            out.write(vba_code)
                        self.log('info',
                                 "Writing VBA Code to {0}".format(save_path))
                    except:
                        self.log('Error',
                                 "Unable to write to {0}".format(save_path))
                    return
        except:
            self.log('Error', "Unable to Process File")
        # Close the file
        vba.close()
Exemple #16
0
    def getVBA(self, myfile, source='filepath'):
        '''
        Given a file, parses out the stream paths, vba code, and vba filenames for each.
        :param myfile: filename
        :param source: type of data being passed in.  Either "filepath" to indicate we need to read from disk or
        "filecontents" meaning that the file contents are being passed as a parameter.
        :return: pandas Series that can be used in concert with the pandas DataFrame apply method
        '''
        if source == 'filepath':
            filedata = open(myfile, 'rb').read()
        else:
            filedata = myfile

        entry = {}
        try:
            vbaparser = VBA_Parser('mmbot', data=filedata)
            allcode = ''
            pathnames = ''
            filenames = ''
            if vbaparser.detect_vba_macros():
                filenameslist = []
                pathnameslist = []
                vbacodelist = []
                for (filename, stream_path, filename_vba,
                     extracted_vba) in vbaparser.extract_macros():
                    vbacodelist.append(extracted_vba.decode("ascii", "ignore"))
                    #vbacodelist.append(extracted_vba.decode('utf8', 'ignore'))

                    if pathnames is None:
                        pathnameslist.append(
                            stream_path.decode("ascii", "ignore"))
                        filenameslist.append(
                            filename_vba.decode("ascii", "ignore"))
                    else:
                        pathnameslist.append(
                            stream_path.decode("ascii", "ignore"))
                        filenameslist.append(
                            filename_vba.decode("ascii", "ignore"))
                allcode = "\n\n\n\n".join(vbacodelist)
                filenames = ", ".join(filenameslist)
                pathnames = ", ".join(pathnameslist)

            else:
                pathnames = 'No VBA Macros found'
                filenames = 'No VBA Macros found'
                allcode = 'No VBA Macros found'

        except Exception as e:
            pathnames = 'Error:' + str(e)
            filenames = 'Error:' + str(e)
            allcode = 'Error:' + str(e)

        return pd.Series({
            'extracted_vba': allcode,
            'stream_path': pathnames,
            'filename_vba': filenames
        })
Exemple #17
0
 def parse_vba(self, save_path):
     save = False
     vba = VBA_Parser(__sessions__.current.file.path)
     # Check for Macros
     if not vba.detect_vba_macros():
         self.log('error', "No Macro's Detected")
         return
     self.log('info', "Macro's Detected")
     try:
         run_rows = []
         word_rows = []
         pattern_rows = []
         for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros():
             self.log('info', "Stream Details")
             self.log('item', "OLE Stream: {0}".format(string_clean(stream_path)))
             self.log('item', "VBA Filename: {0}".format(string_clean(vba_filename)))
             autoexec_keywords = detect_autoexec(vba_code)
             if autoexec_keywords:
                 for keyword, description in autoexec_keywords:
                     run_rows.append([keyword, description])
                 
             # Match Keyword Types
             suspicious_keywords = detect_suspicious(vba_code)
             if suspicious_keywords:
                 for keyword, description in suspicious_keywords:
                     word_rows.append([keyword, description])
                 
             # Match IOCs
             patterns = detect_patterns(vba_code)
             if patterns:
                 for pattern_type, value in patterns:
                     pattern_rows.append([pattern_type, value])
                 
             # Save the code to external File
             if save_path:
                 try:
                     with open(save_path, 'a') as out:
                         out.write(vba_code)
                     save = True
                 except:
                     self.log('Error', "Unable to write to {0}".format(save_path))
                     return
         # Print all Tables together
         self.log('info', "AutoRun Macros Found")
         self.log('table', dict(header=['KeyWord', 'Description'], rows=run_rows))
         self.log('info', "Suspicious Keywords Found")
         self.log('table', dict(header=['KeyWord', 'Description'], rows=word_rows))
         self.log('info', "Suspicious Patterns Found")
         self.log('table', dict(header=['Pattern', 'Value'], rows=pattern_rows))
         if save:
             self.log('success', "Writing VBA Code to {0}".format(save_path))
     except:
         self.log('Error', "Unable to Process File")
     # Close the file
     vba.close()
Exemple #18
0
def POE(logdir, targetfile, logging, debug):

    if (logging == True): 
        LOG = logger()             
    newlogentry = ''
    macro_dump_data = ''

    FI = fileio()

    try:        
        filedata = open(targetfile.filename, 'rb').read()
        vbaparser = VBA_Parser(targetfile.filename, data=filedata)
        if vbaparser.detect_vba_macros():
            print '[*] VBA macros found - Extracting...\n'
            if (logging == True):
                newlogentry = 'VBA macros found - Extracting...'
                LOG.WriteLog(logdir, targetfile.filename, newlogentry)
            for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
                macro_dump_data += '-' * 79 + '\n'
                try:
                    macro_dump_data += 'Filename    :' + filename.encode("ascii", "replace") + '\n'
                    macro_dump_data += 'OLE stream  :' + stream_path.encode("ascii", "replace") + '\n'                
                    macro_dump_data += 'VBA filename:' + vba_filename.encode("ascii", "replace") + '\n'
                except Exception, e:
                    print '[x] Current macro - unable to print Filename, OLE stream or VBA filename due to encoding issue (Unicode?): ', e
                macro_dump_data += '-' * 79 + '\n'
                macro_dump_data += vba_code
                FI.WriteLogFile(logdir + vba_filename, macro_dump_data)

                try:                     
                    print '[*] Macro ' + vba_filename.encode("ascii", "replace") + ' extracted to: ' + logdir + vba_filename.encode("ascii", "replace")
                    targetfile.macros.append(logdir + vba_filename.encode("ascii", "replace"))

                    if (logging == True):
                        newlogentry = 'Macro ' + vba_filename.encode("ascii", "replace") + ' extracted to: <a href=\"' + logdir + vba_filename.encode("ascii", "replace") + '\">' + vba_filename.encode("ascii", "replace") + '</a>'
                    LOG.WriteLog(logdir, targetfile.filename, newlogentry)
                    if (debug == True):
                        print '-'*79
                        print 'Filename    :', filename.encode("ascii", "replace")
                        print 'OLE stream  :', stream_path.encode("ascii", "replace")
                        print 'VBA filename:', vba_filename.encode("utf-8", "ignore")
                        print '-'*79
                except Exception, e:
                    print '[x] Current macro - unable print Filename, OLE stream or VBA filename due to encoding issue: (Unicode?)', e

                if (debug == True):
                    print vba_code

                macro_dump_data = ''
            print 'Macro List'
            for mlist in targetfile.macros:
                print mlist
Exemple #19
0
 def get_macro(self):
     """
     Get Macros from an Office file and write them to a text file
     """
     try:
         self.mk_tmp_dir()
         print "Getting Macros from {}".format(self.file)
         vb = VBA_Parser(self.file, relaxed=True)
         if vb.detect_vba_macros():
             with open("{}{}macros.txt".format(self.tmp_dir, os.sep), "w") as macro_file:
                 for (subfilename, stream_path, vba_filename, vba_code) in vb.extract_all_macros():
                     macro_file.write(vba_code)
     except Exception as e:
         print "get_macro Exception: {}".format(e)
Exemple #20
0
def check_macros(doc_path, filename) -> dict:
    try:

        vbaparser = VBA_Parser(doc_path)

        if not vbaparser.detect_vba_macros():
            return ""

        logging.warning("VBA macros in \"%s\"" % filename)

        details = "Macro Results\n"
        suspicious_count = 0
        suspicious_list = []
        ioc_list = []
        ioc_count = 0
        mal_score = 0

        logging.disable(level=logging.CRITICAL)
        results = vbaparser.analyze_macros()
        logging.disable(level=logging.NOTSET)

        for kw_type, keyword, description in results:

            details += "\t - " + kw_type + " - (" + keyword + ") - " + description + "\n"

            if kw_type.lower() == "suspicious":
                suspicious_count += 1
                suspicious_list.append(keyword)

            elif kw_type.lower() == "ioc":
                ioc_count += 1
                ioc_list.append(keyword)

        if suspicious_count != 0:
            logging.warning("Found %d suspicious items in \"%s\"" %
                            (suspicious_count, filename))
            mal_score += suspicious_count

        if ioc_count != 0:
            logging.warning("Found %d IOCs: %s, in \"%s\"" %
                            (ioc_count, ioc_list, filename))
            mal_score += ioc_count * 2

        return {'details': details, 'mal_score': mal_score}

    except Exception as e:
        logging.error("Failed to parse macros for: {} - {}".format(
            filename, e))
        return
Exemple #21
0
    def get_vba_code(self):
        """Code analysis for malicious parts. Returns malicious code, if any."""
        if not self.has_macros:
            return "Документ не содержит макросов!"

        vbaparser = VBA_Parser(self.file_path)
        vbaparser.detect_vba_macros()
        code_list = list()

        for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
            code_list.append(vba_code)
            code = vba_code

        report_vba = code_list[0]
        macros_infos = self.macros_infos
        for i in range(len(macros_infos)):
            if macros_infos[i]['number'] > 0:
                macro_code = macros_infos[i]['function'](code)
                for i in macro_code:
                    for j in i:
                        report_vba += j

        vbaparser.close()
        return report_vba
def get_vba_source_from_excel(filename):
    vbaparser = VBA_Parser(filename)

    if vbaparser.detect_vba_macros():
        print('VBA Macros found')
    else:
        print('No VBA Macros found')

    for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
        print('-' * 79)
        print('Filename    :', filename)
        print('OLE stream  :', stream_path)
        print('VBA filename:', vba_filename)
        print('- ' * 39)
        print(vba_code)
Exemple #23
0
def _ole_analysis(full_targ_path):
    # This function calls a number of tools / scripts to run against document samples containing OLE data and extracts data and/or performs analysis as needed.
    try:
        vba_parse_Obj = VBA_Parser(full_targ_path)
    except AttributeError:
        return ("ERROR_PARSING", "ERROR_PARSING", "ERROR_PARSING",
                "ERROR_PARSING")
    macro_analysis_over = []
    macro_analysis_info = []
    if vba_parse_Obj.detect_vba_macros():
        vba_macro = "Present"
        # Utilizing oletools to perform analysis.

        # Grabbing info from each macro.
        MA_CNT = 1
        for (file_name, ole_stream, vba_filename,
             vba_code) in vba_parse_Obj.extract_macros():
            macro_analysis_over.append(str(MA_CNT) + ':' + str(full_targ_path))
            macro_analysis_over.append(
                str(MA_CNT) + ":Filename      :" + file_name)
            macro_analysis_over.append(
                str(MA_CNT) + ":OLE Stream    :" + ole_stream)
            macro_analysis_over.append(
                str(MA_CNT) + ":VBA Filename  :" + vba_filename)
            macro_analysis_over.append(str(MA_CNT) + ':' + vba_code)
            MA_CNT += 1

        # Grabbing some overall VBA analysis info.
        macro_flag_types = []
        macro_analysis_res = vba_parse_Obj.analyze_macros()
        if isinstance(macro_analysis_res, list):
            for iocType in macro_analysis_res:
                if str(iocType) not in macro_flag_types:
                    macro_flag_types.append(str(iocType[0]))

        if len(macro_flag_types) > 0:
            iocs = ':'.join(list(set(macro_flag_types)))
        else:
            iocs = "None"

    else:
        vba_macro = "None"
        iocs = "None"
        macro_analysis_res = "None"

    vba_parse_Obj.close()

    return (vba_macro, macro_analysis_over, str(macro_analysis_res), iocs)
	def _run(self, scanObject, result, depth, args):
		moduleResult = []
		vbap_buffer = VBA_Parser(scanObject.buffer)

		try:
			if vbap_buffer.detect_vba_macros():
				vbap_result = vbap_buffer.analyze_macros()
				for kw_type, keyword, description in vbap_result:
					kw = '%s - %s' % ( keyword,description )
					scanObject.addMetadata(self.module_name,kw_type,kw)
		except (QuitScanException, GlobalScanTimeoutError, GlobalModuleTimeoutError):
			raise
		except:
			logging.debug("Failed to parse OLEVBA")

		vbap_buffer.close()

		return moduleResult
Exemple #25
0
def _ole_analysis(full_targ_path):
    # This function calls a number of tools / scripts to run against document samples containing OLE data and extracts data and/or performs analysis as needed.
    try:
        vba_parse_Obj = VBA_Parser(full_targ_path)
    except AttributeError:
        return("ERROR_PARSING", "ERROR_PARSING", "ERROR_PARSING", "ERROR_PARSING")
    macro_analysis_over = []
    macro_analysis_info = []
    if vba_parse_Obj.detect_vba_macros():
        vba_macro = "Present"
        # Utilizing oletools to perform analysis.

        # Grabbing info from each macro.
        MA_CNT = 1
        for (file_name, ole_stream, vba_filename, vba_code) in vba_parse_Obj.extract_macros():
            macro_analysis_over.append(str(MA_CNT)+':'+str(full_targ_path))
            macro_analysis_over.append(str(MA_CNT)+":Filename      :"+file_name)
            macro_analysis_over.append(str(MA_CNT)+":OLE Stream    :"+ole_stream)
            macro_analysis_over.append(str(MA_CNT)+":VBA Filename  :"+vba_filename)
            macro_analysis_over.append(str(MA_CNT)+':'+vba_code)
            MA_CNT+=1

        # Grabbing some overall VBA analysis info.
        macro_flag_types = []
        macro_analysis_res = vba_parse_Obj.analyze_macros()
        if isinstance(macro_analysis_res, list):
            for iocType in macro_analysis_res:
                if str(iocType) not in macro_flag_types:
                    macro_flag_types.append(str(iocType[0]))


        if len(macro_flag_types) > 0:
            iocs = ':'.join(list(set(macro_flag_types)))
        else:
            iocs = "None"

    else:
        vba_macro = "None"
        iocs = "None"
        macro_analysis_res = "None"

    vba_parse_Obj.close()

    return(vba_macro, macro_analysis_over, str(macro_analysis_res), iocs)
Exemple #26
0
def has_office_macros(office_file):
    """
    Detects macros in Microsoft Office documents.

    :param office_file: The MS Office document to check for macros.
    :return: True if macros where found, otherwise False.
             If VBA_Parser crashes it returns False too.
    """
    file_extension = office_file.split('.')[-1]
    if file_extension not in ms_office_extensions:
        return False
    try:
        # VBA_Parser reports macros for office documents
        vbaparser = VBA_Parser(office_file)
        return vbaparser.detect_vba_macros()
    except TypeError:
        # The given file is not an office document.
        return False
    except Exception as e:
        logger.exception(e)
        return False
def get_office_file_startup_command(extension, file_path):
    start_command = ["cmd.exe", "/C", "start"]
    if is_office_word_file(extension):
        start_command.append("winword.exe")
    elif is_office_excel_file(extension):
        start_command.append("excel.exe")
    elif is_office_powerpoint_file(extension):
        start_command.append("powerpnt.exe")
    else:
        log.warning(f"Unknown office file extension {extension}.")
        return None
    start_command.extend(["/t", "%f"])

    vbaparser = VBA_Parser(file_path)
    if vbaparser.detect_vba_macros():
        outer_macros = get_outer_nodes_from_vba_file(file_path)
        if not outer_macros:
            outer_macros = []
        for outer_macro in outer_macros:
            start_command.append(f"/m{outer_macro}")

    return subprocess.list2cmdline(start_command)
Exemple #28
0
    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
Exemple #29
0
 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
Exemple #30
0
	def inspect_vba_data(self, filename, filecontent):
		'''
			Function to parse the given data in mail content
		'''
		vbaparser_report_log = ''  # reset var
		# send data to vba parser
		vbaparser = VBA_Parser(filename, data=filecontent)
		# if a macro is detected
		if not vbaparser.detect_vba_macros():
			self.log("VBA no Macros found in file")
			vbaparser.close()
			return None  # nothing found
		else:
			results = vbaparser.analyze_macros()
			nr = 1
			self.log("VBA Macros found")
			# generate report for log file
			for kw_type, keyword, description in results:
				if kw_type == 'Suspicious':
					vbaparser_report_log += 'Macro Number %i:\n Type: %s\n Keyword: %s\n Description: %s\n' % (
					nr, kw_type, keyword, description)
				nr += 1
			vbaparser_report_log += '\nSummery:\nAutoExec keywords: %d\n' % vbaparser.nb_autoexec
			vbaparser_report_log += 'Suspicious keywords: %d\n' % vbaparser.nb_suspicious
			vbaparser_report_log += 'IOCs: %d\n' % vbaparser.nb_iocs
			vbaparser_report_log += 'Hex obfuscated strings: %d\n' % vbaparser.nb_hexstrings
			vbaparser_report_log += 'Base64 obfuscated strings: %d\n' % vbaparser.nb_base64strings
			vbaparser_report_log += 'Dridex obfuscated strings: %d\n' % vbaparser.nb_dridexstrings
			vbaparser_report_log += 'VBA obfuscated strings: %d' % vbaparser.nb_vbastrings
			
			# TBD: calculate a better level - add additional values to Base64 and Hex. No human writes such strings into code.
			r_level = vbaparser.nb_autoexec + vbaparser.nb_suspicious + vbaparser.nb_iocs + vbaparser.nb_hexstrings + vbaparser.nb_base64strings + vbaparser.nb_dridexstrings + vbaparser.nb_vbastrings

			# set reject level to global
			#self.level = r_level
			vbaparser.close()
			return [r_level, vbaparser_report_log]  # return the log to caller
Exemple #31
0
    def check_for_macros(self, filename, file_contents, request_hash):
        # noinspection PyBroadException
        try:
            vba_parser = VBA_Parser(filename=filename, data=file_contents)

            try:
                if vba_parser.detect_vba_macros():
                    self.ole_result.add_tag(TAG_TYPE.TECHNIQUE_MACROS,
                                            "Contains VBA Macro(s)",
                                            weight=TAG_WEIGHT.LOW,
                                            usage=TAG_USAGE.IDENTIFICATION)

                    try:
                        for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_macros():
                            if vba_code.strip() == '':
                                continue
                            vba_code_sha256 = hashlib.sha256(vba_code).hexdigest()
                            if vba_code_sha256 == request_hash:
                                continue

                            self.all_vba.append(vba_code)
                            macro_section = self.macro_section_builder(vba_code)
                            toplevel_score = self.calculate_nested_scores(macro_section)

                            self.all_macros.append(Macro(vba_code, vba_code_sha256, macro_section, toplevel_score))
                    except Exception as e:
                        self.log.debug("OleVBA VBA_Parser.extract_macros failed: {}".format(str(e)))
                        section = ResultSection(SCORE.NULL, "OleVBA : Error extracting macros")
                        self.ole_result.add_section(section)

            except Exception as e:
                self.log.debug("OleVBA VBA_Parser.detect_vba_macros failed: {}".format(e))
                section = ResultSection(SCORE.NULL, "OleVBA : Error parsing macros: {}".format(e))
                self.ole_result.add_section(section)
        except:
            self.log.debug("OleVBA VBA_Parser constructor failed, may not be a supported OLE document")
def process_file_scanexpr (container, filename, data):
    """Process a single file.

    @param container (str) Path and filename of container if the file is within
    a zip archive, None otherwise.

    @param filename (str) path and filename of file on disk, or within
    the container.

    @param data (bytes) Content of the file if it is in a container,
    None if it is a file on disk.

    """
    #TODO: replace print by writing to a provided output file (sys.stdout by default)
    if container:
        display_filename = '%s in %s' % (filename, container)
    else:
        display_filename = filename
    safe_print('='*79)
    safe_print('FILE: ' + safe_str_convert(display_filename))
    all_code = ''
    try:
        #TODO: handle olefile errors, when an OLE file is malformed
        import oletools
        oletools.olevba.enable_logging()
        if (log.getEffectiveLevel() == logging.DEBUG):
            log.debug('opening %r' % filename)
        vba = VBA_Parser(filename, data, relaxed=True)
        if vba.detect_vba_macros():

            # Read in document metadata.
            vm = core.ViperMonkey(filename, data)
            ole = olefile.OleFileIO(filename)
            try:
                vm.set_metadata(ole.get_metadata())
            except Exception as e:
                log.warning("Reading in metadata failed. Trying fallback. " + safe_str_convert(e))
                vm.set_metadata(get_metadata_exif(filename))
            
            #print 'Contains VBA Macros:'
            for (subfilename, stream_path, vba_filename, vba_code) in vba.extract_macros():
                # hide attribute lines:
                #TODO: option to disable attribute filtering
                vba_code = filter_vba(vba_code)
                safe_print('-'*79)
                safe_print('VBA MACRO %s ' % vba_filename)
                safe_print('in file: %s - OLE stream: %s' % (subfilename, repr(stream_path)))
                safe_print('- '*39)
                # detect empty macros:
                if vba_code.strip() == '':
                    safe_print('(empty macro)')
                else:
                    # TODO: option to display code
                    safe_print(vba_code)
                    vba_code = core.vba_collapse_long_lines(vba_code)
                    all_code += '\n' + vba_code
            safe_print('-'*79)
            safe_print('EVALUATED VBA EXPRESSIONS:')
            t = prettytable.PrettyTable(('Obfuscated expression', 'Evaluated value'))
            t.align = 'l'
            t.max_width['Obfuscated expression'] = 36
            t.max_width['Evaluated value'] = 36
            for expression, expr_eval in core.scan_expressions(all_code):
                t.add_row((repr(expression), repr(expr_eval)))
                safe_print(t)

        else:
            safe_print('No VBA macros found.')
    except Exception as e:
        log.error("Caught exception. " + safe_str_convert(e))
        if (log.getEffectiveLevel() == logging.DEBUG):
            traceback.print_exc()

    safe_print('')
Exemple #33
0
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
Exemple #34
0
class DocInfo(FileAnalyzer):
    def set_config(self, additional_config_params):
        self.olevba_results = {}
        self.vbaparser = None
        self.experimental = additional_config_params.get("experimental", False)
        self.passwords_to_check = []
        # this is to extract the passwords for encryption requested by the client
        # you can use pyintelowl to send additional passwords to check for
        # example:
        #             "additional_configuration": {
        #                 "Doc_Info_Experimental": {
        #                     "additional_passwords_to_check": ["testpassword"]
        #                 }
        #             },
        additional_passwords_to_check = additional_config_params.get(
            "additional_passwords_to_check", []
        )
        if isinstance(additional_passwords_to_check, list):
            self.passwords_to_check.extend(additional_passwords_to_check)

    def run(self):
        results = {}

        # olevba
        try:
            self.vbaparser = VBA_Parser(self.filepath)

            self.manage_encrypted_doc()

            if self.experimental:
                self.experimental_analysis()

            # go on with the normal oletools execution
            self.olevba_results["macro_found"] = self.vbaparser.detect_vba_macros()

            if self.olevba_results["macro_found"]:
                vba_code_all_modules = ""
                macro_data = []
                for (
                    v_filename,
                    stream_path,
                    vba_filename,
                    vba_code,
                ) in self.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)
                    vba_code_all_modules += vba_code + "\n"
                self.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'},

                # mraptor
                macro_raptor = mraptor.MacroRaptor(vba_code_all_modules)
                if macro_raptor:
                    macro_raptor.scan()
                    results["mraptor"] = (
                        "suspicious" if macro_raptor.suspicious else "ok"
                    )

                # analyze macros
                analyzer_results = self.vbaparser.analyze_macros()
                # 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)
                    self.olevba_results["analyze_macro"] = analyze_macro_results

        except CannotDecryptException as e:
            logger.info(e)
        except Exception as e:
            error_message = f"job_id {self.job_id} vba parser failed. Error: {e}"
            logger.exception(error_message)
            self.report["errors"].append(error_message)
        finally:
            if self.vbaparser:
                self.vbaparser.close()

        results["olevba"] = self.olevba_results

        return results

    def manage_encrypted_doc(self):
        self.olevba_results["is_encrypted"] = False
        # checks if it is an OLE file. That could be encrypted
        if self.vbaparser.ole_file:
            # check if the ole file is encrypted
            is_encrypted = self.vbaparser.detect_is_encrypted()
            self.olevba_results["is_encrypted"] = is_encrypted
            # in the case the file is encrypted I try to decrypt it
            # with the default password and the most common ones
            if is_encrypted:
                # by default oletools contains some basic passwords
                # we just add some more guesses
                common_pwd_to_check = []
                for num in range(10):
                    common_pwd_to_check.append(f"{num}{num}{num}{num}")
                # https://twitter.com/JohnLaTwC/status/1265377724522131457
                filename_without_spaces_and_numbers = sub("[-_\d\s]", "", self.filename)
                filename_without_extension = sub(
                    "(\..+)", "", filename_without_spaces_and_numbers
                )
                common_pwd_to_check.append(filename_without_extension)
                self.passwords_to_check.extend(common_pwd_to_check)
                decrypted_file_name = self.vbaparser.decrypt_file(
                    self.passwords_to_check
                )
                self.olevba_results[
                    "additional_passwords_tried"
                ] = self.passwords_to_check
                if decrypted_file_name:
                    self.vbaparser = VBA_Parser(decrypted_file_name)
                else:
                    self.olevba_results["cannot_decrypt"] = True
                    raise CannotDecryptException(
                        "cannot decrypt the file with the default password"
                    )

    def experimental_analysis(self):
        self.manage_xlm_macros()

    def manage_xlm_macros(self):
        self.olevba_results["xlm_macro"] = False
        # check if the file contains an XLM macro
        # and try an experimental parsing
        # credits to https://twitter.com/gabriele_pippi for the idea
        if self.vbaparser.detect_xlm_macros():
            self.olevba_results["xlm_macro"] = True
            logger.debug("experimental XLM macro analysis start")
            parsed_file = b""
            try:
                excel_doc = XLSWrapper2(self.filepath)
                ae_list = [
                    "auto_open",
                    "auto_close",
                    "auto_activate",
                    "auto_deactivate",
                ]
                self.olevba_results["xlm_macro_autoexec"] = []
                for ae in ae_list:
                    auto_exec_labels = excel_doc.get_defined_name(ae, full_match=False)
                    for label in auto_exec_labels:
                        self.olevba_results["xlm_macro_autoexec"].append(label[0])

                for i in show_cells(excel_doc):
                    rec_str = ""
                    if len(i) == 5:
                        # rec_str = 'CELL:{:10}, {:20}, {}'
                        # .format(i[0].get_local_address(), i[2], i[4])
                        if i[2] != "None":
                            rec_str = "{:20}".format(i[2])
                    if rec_str:
                        parsed_file += rec_str.encode()
                        parsed_file += b"\n"
            except Exception as e:
                logger.info(f"experimental XLM macro analysis failed. Exception: {e}")
            else:
                logger.debug(
                    f"experimental XLM macro analysis succeded. "
                    f"Binary to analyze: {parsed_file}"
                )
                if parsed_file:
                    self.vbaparser = VBA_Parser(self.filename, data=parsed_file)
import sys
import os
from oletools.olevba import VBA_Parser, TYPE_OLE, TYPE_OpenXML, TYPE_Word2003_XML, TYPE_MHTML, detect_autoexec, VBA_Scanner

#PYTHON 2,3버전 모두 호환 
if sys.version_info[0]<= 2:
      #python 2
      from oletools.olevba import VBA_Parser
else:
     #python 3
	  from oletools.olevba3 import VBA_Parser

# VBA 퍼져 온 
vbaparser = VBA_Parser(sys.argv[1])
  # 매크로 검사
if not vbaparser.detect_vba_macros():
 print ('error', "macro not detected ")
 #경고모듈 넣는 위치 
 sys.exit(1)

print ('info', "macro detected ! ")

for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros():
  print ("- "*79)
  print ("filename    :", filename)
  print ("OLE stream  :", stream_path)
  print ("VBA filename:", vba_filename)
  print ("- "*39)
  print ("vba_code",vba_code)

     
Exemple #36
0
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
Exemple #37
0
    def parse_vba(self, save_path):
        """
        Parse VBA scripts.
        """
        save = False
        vbaparser = VBA_Parser(__sessions__.current.file.path)
        # Check for Macros
        if not vbaparser.detect_vba_macros():
            self.log("error", "No macros detected")
            return
        self.log("info", "Macros detected")
        # try:
        if True:
            an_results = {
                "AutoExec": [],
                "Suspicious": [],
                "IOC": [],
                "Hex String": [],
                "Base64 String": [],
                "Dridex string": [],
                "VBA string": []
            }
            for (filename, stream_path, vba_filename,
                 vba_code) in vbaparser.extract_macros():
                self.log("info", "Stream Details")
                self.log("item",
                         "OLE Stream: {0}".format(string_clean(stream_path)))
                self.log(
                    "item",
                    "VBA Filename: {0}".format(string_clean(vba_filename)))
                # Analyse the VBA Code
                vba_scanner = VBA_Scanner(vba_code)
                analysis = vba_scanner.scan(include_decoded_strings=True)
                for kw_type, keyword, description in analysis:
                    an_results[kw_type].append(
                        [string_clean_hex(keyword), description])

                # Save the code to external File
                if save_path:
                    try:
                        with open(save_path, "a") as out:
                            out.write(vba_code)
                        save = True
                    except Exception as e:
                        self.log(
                            "error",
                            "Unable to write to {0}: {1}".format(save_path, e))
                        return

            # Print all tables together
            if an_results["AutoExec"]:
                self.log("info", "Autorun macros found")
                self.log(
                    "table",
                    dict(header=["Method", "Description"],
                         rows=an_results["AutoExec"]))

            if an_results["Suspicious"]:
                self.log("info", "Suspicious keywords found")
                self.log(
                    "table",
                    dict(header=["Keyword", "Description"],
                         rows=an_results["Suspicious"]))

            if an_results["IOC"]:
                self.log("info", "Possible IOCs")
                self.log("table",
                         dict(header=["IOC", "Type"], rows=an_results["IOC"]))

            if an_results["Hex String"]:
                self.log("info", "Hex strings")
                self.log(
                    "table",
                    dict(header=["Decoded", "Raw"],
                         rows=an_results["Hex String"]))

            if an_results["Base64 String"]:
                self.log("info", "Base64 strings")
                self.log(
                    "table",
                    dict(header=["Decoded", "Raw"],
                         rows=an_results["Base64 String"]))

            if an_results["Dridex string"]:
                self.log("info", "Dridex strings")
                self.log(
                    "table",
                    dict(header=["Decoded", "Raw"],
                         rows=an_results["Dridex string"]))

            if an_results["VBA string"]:
                self.log("info", "VBA strings")
                self.log(
                    "table",
                    dict(header=["Decoded", "Raw"],
                         rows=an_results["VBA string"]))

            if save:
                self.log("success",
                         "Writing VBA Code to {0}".format(save_path))

        # Close the file
        vbaparser.close()
Exemple #38
0
def process_file(container,
                 filename,
                 data,
                 altparser=False,
                 strip_useless=False,
                 entry_points=None):
    """
    Process a single file

    :param container: str, path and filename of container if the file is within
    a zip archive, None otherwise.
    :param filename: str, path and filename of file on disk, or within the container.
    :param data: bytes, content of the file if it is in a container, None if it is a file on disk.

    :return A list of actions if actions found, an empty list if no actions found, and None if there
    was an error.
    """
    #TODO: replace print by writing to a provided output file (sys.stdout by default)
    if container:
        display_filename = '%s in %s' % (filename, container)
    else:
        display_filename = filename
    print '=' * 79
    print 'FILE:', display_filename
    vm = ViperMonkey()
    if (entry_points is not None):
        for entry_point in entry_points:
            vm.entry_points.append(entry_point)
    try:
        #TODO: handle olefile errors, when an OLE file is malformed
        vba = VBA_Parser(filename, data, relaxed=True)
        print 'Type:', vba.type
        if vba.detect_vba_macros():

            # Read in document metadata.
            try:
                ole = olefile.OleFileIO(filename)
                vba_library.meta = ole.get_metadata()
                vba_object.meta = vba_library.meta
            except:
                log.error("Reading in metadata failed.")
                vba_library.meta = {}

            # Set the output directory in which to put dumped files generated by
            # the macros.
            out_dir = filename + "_artifacts"
            if ("/" in out_dir):
                start = out_dir.rindex("/") + 1
                out_dir = out_dir[start:]
            out_dir = out_dir.replace(".", "").strip()
            out_dir = "./" + out_dir + "/"
            vba_library.out_dir = out_dir

            # Parse the VBA streams.
            comp_modules = parse_streams(vba, strip_useless)
            if (comp_modules is None):
                return None
            for m in comp_modules:
                if (m != "empty"):
                    vm.add_compiled_module(m)

            # Pull out form variables.
            try:
                for (subfilename, stream_path,
                     form_variables) in vba.extract_form_strings_extended():
                    if form_variables is not None:
                        var_name = form_variables['name']
                        macro_name = stream_path
                        if ("/" in macro_name):
                            start = macro_name.rindex("/") + 1
                            macro_name = macro_name[start:]
                        global_var_name = (macro_name + "." + var_name).encode(
                            'ascii', 'ignore')
                        val = form_variables['value']
                        if (val is None):
                            val = ''
                        name = global_var_name.lower()
                        vm.globals[name] = val
                        log.debug(
                            "Added VBA form variable %r = %r to globals." %
                            (global_var_name, val))
                        vm.globals[name + ".tag"] = val
                        log.debug(
                            "Added VBA form variable %r = %r to globals." %
                            (global_var_name + ".Tag", val))
                        vm.globals[name + ".text"] = val
                        log.debug(
                            "Added VBA form variable %r = %r to globals." %
                            (global_var_name + ".Text", val))
            except Exception as e:
                log.error("Cannot read form strings. " + str(e))

            print '-' * 79
            print 'TRACING VBA CODE (entrypoint = Auto*):'
            if (entry_points is not None):
                log.info("Starting emulation from function(s) " +
                         str(entry_points))
            vm.trace()
            # print table of all recorded actions
            print('Recorded Actions:')
            print(vm.dump_actions())
            print ''
            return vm.actions

        else:
            print 'No VBA macros found.'
            print ''
            return []
    except Exception as e:
        if ("SystemExit" not in str(e)):
            traceback.print_exc()
        return None
Exemple #39
0
def process_file (container, filename, data,
                  altparser=False, strip_useless=False):
    """
    Process a single file

    :param container: str, path and filename of container if the file is within
    a zip archive, None otherwise.
    :param filename: str, path and filename of file on disk, or within the container.
    :param data: bytes, content of the file if it is in a container, None if it is a file on disk.
    """
    #TODO: replace print by writing to a provided output file (sys.stdout by default)
    if container:
        display_filename = '%s in %s' % (filename, container)
    else:
        display_filename = filename
    print '='*79
    print 'FILE:', display_filename
    vm = ViperMonkey()
    try:
        #TODO: handle olefile errors, when an OLE file is malformed
        vba = VBA_Parser(filename, data, relaxed=True)
        print 'Type:', vba.type
        if vba.detect_vba_macros():

            # Read in document metadata.
            try:
                ole = olefile.OleFileIO(filename)
                vba_library.meta = ole.get_metadata()
            except:
                vba_library.meta = {}

            # Parse the VBA streams.
            comp_modules = parse_streams(vba, strip_useless)
            for m in comp_modules:
                vm.add_compiled_module(m)

            # Pull out form variables.
            for (subfilename, stream_path, form_variables) in vba.extract_form_strings_extended():
                if form_variables is not None:
                    var_name = form_variables['name']
                    macro_name = stream_path
                    if ("/" in macro_name):
                        start = macro_name.rindex("/") + 1
                        macro_name = macro_name[start:]
                    global_var_name = (macro_name + "." + var_name).encode('ascii', 'ignore')
                    val = form_variables['value']
                    vm.globals[global_var_name.lower()] = val
                    log.debug("Added VBA form variable %r = %r to globals." % (global_var_name, val))
                
            print '-'*79
            print 'TRACING VBA CODE (entrypoint = Auto*):'
            vm.trace()
            # print table of all recorded actions
            print('Recorded Actions:')
            print(vm.dump_actions())

        else:
            print 'No VBA macros found.'
    except: #TypeError:
        #raise
        #TODO: print more info if debug mode
        #print sys.exc_value
        # display the exception with full stack trace for debugging, but do not stop:
        traceback.print_exc()
    print ''
Exemple #40
0
    return res


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Analyze docx document (pretty limited for now)')
    parser.add_argument('FILE', help='Docx document')
    args = parser.parse_args()

    if not os.path.isfile(args.FILE):
        print("Invalid file path")
        sys.exit(1)

    # Check if any macro and extract it
    vbaparser = VBA_Parser(args.FILE)
    if vbaparser.detect_vba_macros():
        print('VBA Macros found')
        mac_name = os.path.splitext(args.FILE)[0] + '.macro'
        with open(mac_name, 'w+') as f:
            for (filename, stream_path, vba_filename,
                 vba_code) in vbaparser.extract_macros():
                f.write(vba_code)
                f.write('\n')
        print("Macro dumped in {}".format(mac_name))
    else:
        print('No VBA Macros found')

    # Show metadata
    input_zip = ZipFile(args.FILE)
    print("")
    print("Metadata:")