示例#1
0
文件: ole.py 项目: khw5123/Project
 def arclist(self, filename, fileformat):
     import oletools.thirdparty.olefile.olefile as olefile
     import oletools.olevba as vba
     file_scan_list = []  # 검사 대상의 압축 엔진 ID 및 임의의 문자열이 저장될 리스트
     if 'ff_ole' in fileformat:  # format 함수에 의해 분석된 OLE 파일 포맷이 있을 경우
         # OLE Stream 목록 추출
         o = olefile.OleFileIO(filename)
         for path in o.listdir():
             name = '/'.join(path)
             if o.get_type(name) == olefile.STGTY_STREAM:  # 파일인 경우
                 file_scan_list.append(['arc_ole', name])
         o.close()
         # 매크로 목록 추출
         v = vba.VBA_Parser(filename)
         if v.detect_vba_macros():  # 매크로가 존재할 경우
             macros = v.extract_all_macros()  # 매크로 추출
             for macro in macros():
                 name = macro[1]
                 print name + '\n' + macro[3] + '\n'
                 file_scan_list.append(
                     ['arc_vba', name.encode('ascii', 'ignore')])
         v.close()
     elif 'ff_zip' in fileformat:  # OOXML(Open Office XML) 파일 포맷일 경우
         # 매크로 목록 추출
         v = vba.VBA_Parser(filename)
         if v.detect_vba_macros():  # 매크로가 존재할 경우
             macros = v.extract_all_macros()  # 매크로 추출
             for macro in macros():
                 name = macro[0] + '/' + macro[1]
                 print name + '\n' + macro[3] + '\n'
                 file_scan_list.append(
                     ['arc_vba', name.encode('ascii', 'ignore')])
         v.close()
     return file_scan_list
示例#2
0
    def getZipFiles(self, attachment, filename):
        '''
			Checks a zip for parsable files and extracts all macros
		'''
        log.debug(
            "[%d] Found attachment with archive extension - file name: %s" %
            (self.id, filename))
        vba_code_all_modules = ''
        file_object = StringIO.StringIO(attachment)
        files_in_zip = self.zipwalk(file_object, 0, [])

        for zip_name, zip_data in files_in_zip:
            # checks if it is a file

            zip_mem_data = StringIO.StringIO(zip_data)
            name, ext = os.path.splitext(zip_name.filename)
            # send to the VBA_Parser
            # fallback with extensions - maybe removed in future releases
            if olefile.isOleFile(zip_mem_data) or ext in EXTENSIONS:
                log.info(
                    "[%d] File in zip detected! Name: %s - check for VBA" %
                    (self.id, zip_name.filename))
                vba_parser = olevba.VBA_Parser(filename=zip_name.filename,
                                               data=zip_data)
                for (subfilename, stream_path, vba_filename,
                     vba_code) in vba_parser.extract_all_macros():
                    vba_code_all_modules += vba_code + '\n'
        return vba_code_all_modules
示例#3
0
文件: oleid.py 项目: singlag/oletools
    def check_macros(self):
        """
        Check whether this file contains macros (VBA and XLM/Excel 4).

        :returns: :py:class:`Indicator`
        """
        vba_indicator = Indicator(_id='vba', value='No', _type=str, name='VBA Macros',
                                  description='This file does not contain VBA macros.',
                                  risk=RISK.NONE)
        try:
            vba_parser = olevba.VBA_Parser(filename=self.filename, data=self.data)
            if vba_parser.detect_vba_macros():
                vba_indicator.value = 'Yes'
                vba_indicator.risk = RISK.MEDIUM
                vba_indicator.description = 'This file contains VBA macros. No suspicious keyword was found. Use olevba and mraptor for more info.'
                # check code with mraptor
                vba_code = vba_parser.get_vba_code_all_modules()
                m = mraptor.MacroRaptor(vba_code)
                m.scan()
                if m.suspicious:
                    vba_indicator.value = 'Yes, suspicious'
                    vba_indicator.risk = RISK.HIGH
                    vba_indicator.description = 'This file contains VBA macros. Suspicious keywords were found. Use olevba and mraptor for more info.'
        except Exception as e:
            vba_indicator.risk = RISK.ERROR
            vba_indicator.value = 'Error'
            vba_indicator.description = 'Error while checking VBA macros: %s' % str(e)
        self.indicators.append(vba_indicator)
        return vba_indicator
示例#4
0
文件: ole.py 项目: khw5123/Project
 def unarc(self, arc_engine_id, arc_name, fname_in_arc):
     import oletools.thirdparty.olefile.olefile as olefile
     import oletools.olevba as vba
     data = None
     if arc_engine_id == 'arc_ole':  # 압축 해제 엔진 ID가 arc_ole 일 경우
         o = olefile.OleFileIO(arc_name)
         fp = o.openstream(fname_in_arc)  # OLE 파일 내부 파일 열기
         data = fp.read()  # 데이터 추출
         o.close()
         return data
     elif arc_engine_id == 'arc_vba':  # 압축 해제 엔진 ID가 arc_vba 일 경우
         v = vba.VBA_Parser(arc_name)
         if v.detect_vba_macros():  # 매크로가 존재할 경우
             macros = v.extract_all_macros()  # 매크로 추출
             for macro in macros():
                 if v.type == 'OLE':
                     name = macro[1]
                 elif v.type == 'OpenXML':
                     name = macro[0] + '/' + macro[1]
                 else:
                     name = 'UNKNOWN'
                 if name == fname_in_arc:
                     data = macro[3]  # VBA Code
                     break
         v.close()
         return data
     return None
def get_macros(data_stream):
    """

    :param data_stream:  binary data stream
    :return: macro
    [{'vba_filename': 'ThisDocument.cls', 'subfilename': 'vba', 'ole_stream': 'VBA/ThisDocument', 'code': 'this_is_code_space'}, ...]
    """
    vba2 = olevba.VBA_Parser(filename="vba", data=data_stream)
    macros = []
    try:
        if vba2.detect_vba_macros():
            for (subfilename, stream_path, vba_filename,
                 vba_code) in vba2.extract_all_macros():
                curr_macro = {}
                if vba_code is None:
                    continue
                vba_code_filtered = filter_vba(vba_code)

                curr_macro['vba_filename'] = vba_filename
                curr_macro['subfilename'] = subfilename
                curr_macro['ole_stream'] = stream_path
                curr_macro['code'] = vba_code_filtered.strip()
                if curr_macro['code'] != '':
                    macros.append(curr_macro)
    except TypeError as te:
        logging.exception("get_macros: {te}".format(te=te))
    return macros
示例#6
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []
        try:
            vbaparser = olevba.VBA_Parser(
                scanObject.objectHash,
                data=scanObject.buffer)  #load ole into olevba
            if vbaparser.detect_vba_macros():  #VBA Macro Found
                # Loop to parse VBA Macro
                for (filename, stream_path, vba_filename, vba_code
                     ) in vbaparser.extract_macros():  # macro extraction
                    macrofilesdict = {}
                    macrofilesdict.update({
                        'Type': vbaparser.type,
                        'VBA_project': vbaparser.vba_projects,
                        'OLE_stream': stream_path,
                        'VBA_filename': vba_filename
                    })
                    scanObject.addMetadata(self.module_name,
                                           "Parsed_Macros_Metadata",
                                           macrofilesdict)
                    explodevbafilename = 'e_vba_%s_%s' % (
                        scanObject.objectHash, vba_filename
                    )  # Exploded file name contains source hash
                    moduleResult.append(
                        ModuleObject(buffer=vba_code,
                                     externalVars=ExternalVars(
                                         filename=explodevbafilename)))
                # Loop to parse VBA Forms
                combinedstring = ""
                formfilesdlist = set()
                for (filename, stream_path,
                     form_string) in vbaparser.extract_form_strings():
                    formfilesdlist.add(
                        stream_path
                    )  #set because stream_path could be the same over and over again
                    combinedstring += " %s" % form_string  #combining all found forms text into a single variable
                if combinedstring:  #form text found
                    scanObject.addMetadata(self.module_name,
                                           "VBA_Forms_Found_Streams",
                                           formfilesdlist)
                    explodeformsfilename = 'e_vba_%s_combined_forms.txt' % (
                        scanObject.objectHash)
                    moduleResult.append(
                        ModuleObject(buffer=combinedstring,
                                     externalVars=ExternalVars(
                                         filename=explodeformsfilename)))
            vbaparser.close()

        except olevba.OlevbaBaseException as e:  # exceptions from olevba import will raise
            olevbaerror = 'e_vba:err:%s' % e
            #scanObject.addFlag(olevbaerror)
            log_module("MSG", self.module_name, 0, scanObject, result,
                       olevbaerror)
        except (QuitScanException, GlobalScanTimeoutError,
                GlobalModuleTimeoutError):
            raise
        return moduleResult
示例#7
0
 def check_mraptor(self):
     '''
     Check the attachments of a message using mraptor.
     If an attachment is identified as suspicious, it is replaced by a simple text file.
     :return: Milter.ACCEPT or Milter.DISCARD if processing error
     '''
     msg = email.message_from_string(self.message.getvalue())
     result = Milter.ACCEPT
     try:
         for part in msg.walk():
             # for name, value in part.items():
             #     logging.debug(' - %s: %r' % (name, value))
             content_type = part.get_content_type()
             logging.debug('[%d] Content-type: %r' % (self.id, content_type))
             # TODO: handle any content-type, but check the file magic?
             if not content_type.startswith('multipart'):
                 filename = part.get_filename(None)
                 logging.debug('[%d] Analyzing attachment %r' % (self.id, filename))
                 attachment = part.get_payload(decode=True)
                 attachment_lowercase = attachment.lower()
                 # check if this is a supported file type (if not, just skip it)
                 # TODO: use is_zipfile instead of 'PK'
                 # TODO: this function should be provided by olevba
                 if attachment.startswith(olevba.olefile.MAGIC) \
                     or attachment.startswith('PK') \
                     or 'http://schemas.microsoft.com/office/word/2003/wordml' in attachment \
                     or ('mime' in attachment_lowercase and 'version' in attachment_lowercase
                         and 'multipart' in attachment_lowercase):
                     vba_parser = olevba.VBA_Parser(filename='message', data=attachment)
                     vba_code_all_modules = ''
                     for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
                         vba_code_all_modules += vba_code + '\n'
                     m = mraptor.MacroRaptor(vba_code_all_modules)
                     m.scan()
                     if m.suspicious:
                         logging.warning('[%d] The attachment %r contains a suspicious macro: replace it with a text file'
                                         % (self.id, filename))
                         part.set_payload('This attachment has been removed because it contains a suspicious macro.')
                         part.set_type('text/plain')
                         # TODO: handle case when CTE is absent
                         part.replace_header('Content-Transfer-Encoding', '7bit')
                         # for name, value in part.items():
                         #     logging.debug(' - %s: %r' % (name, value))
                         # TODO: archive filtered e-mail to a file
                     else:
                         logging.debug('The attachment %r is clean.'
                                         % filename)
     except Exception:
         logging.exception('[%d] Error while processing the message' % self.id)
         # TODO: depending on error, decide to forward the e-mail as-is or not
         result = Milter.DISCARD
     # TODO: only do this if the body has actually changed
     body = str(msg)
     self.message = io.BytesIO(body)
     self.replacebody(body)
     logging.info('[%d] Message relayed' % self.id)
     return result
示例#8
0
    def each(self, target):
        self.results = {
            'macros': u'',
            'analysis': {
                'AutoExec': [],
                'Suspicious': [],
                'IOC': [],
                'Hex String': [],
                'Base64 String': [],
                'Dridex string': [],
                'VBA string': [],
                'Form String': []
            }
        }

        vba = olevba.VBA_Parser(target)

        # code is inspired by 'reveal' method in olevba
        analysis = vba.analyze_macros(show_decoded_strings=True)

        # extract all macros code
        for (_, _, _, vba_code) in vba.extract_all_macros():
            self.results['macros'] += vba_code.decode('utf-8',
                                                      errors='replace') + '\n'

        # extract all form strings
        for (_, _, form_string) in vba.extract_form_strings():
            self.results['analysis']['Form String'].append(
                form_string.decode('utf-8', errors='replace'))

        # extract all analysis
        if analysis:
            analysis = sorted(
                analysis,
                key=lambda type_decoded_encoded: len(type_decoded_encoded[2]),
                reverse=True)
            for kw_type, keyword, description in analysis:
                # and replace obfuscated strings
                if kw_type in [
                        'VBA string', 'Dridex string', 'Base64 String',
                        'Hex String'
                ]:
                    if olevba.is_printable(keyword):
                        keyword = keyword.replace('"', '""')
                        self.results['macros'] = self.results[
                            'macros'].replace(description, '"%s"' % keyword)
                        self.results['analysis'][kw_type].append(
                            (keyword.decode('utf-8', errors='replace'),
                             description.decode('utf-8', errors='replace')))
                else:
                    self.results['analysis'][kw_type].append(
                        (keyword, description))

        return len(self.results['macros']) > 0
示例#9
0
    def scan(self, data, file, options, expire_at):
        analyze_macros = options.get('analyze_macros', True)

        self.event['total'] = {'files': 0, 'extracted': 0}

        try:
            vba = olevba.VBA_Parser(filename=file.name, data=data)
            if vba.detect_vba_macros():
                extract_macros = list(vba.extract_macros())
                self.event['total']['files'] = len(extract_macros)
                for (filename, stream_path, vba_filename, vba_code) in extract_macros:
                    extract_file = strelka.File(
                        name=f'{vba_filename}',
                        source=self.name,
                    )

                    for c in strelka.chunk_string(vba_code):
                        self.upload_to_coordinator(
                            extract_file.pointer,
                            c,
                            expire_at,
                        )

                    self.files.append(extract_file)
                    self.event['total']['extracted'] += 1

                if analyze_macros:
                    self.event.setdefault('auto_exec', [])
                    self.event.setdefault('base64', [])
                    self.event.setdefault('dridex', [])
                    self.event.setdefault('hex', [])
                    self.event.setdefault('ioc', [])
                    self.event.setdefault('suspicious', [])
                    macros = vba.analyze_macros()
                    for (macro_type, keyword, description) in macros:
                        if macro_type == 'AutoExec':
                            self.event['auto_exec'].append(keyword)
                        elif macro_type == 'Base64 String':
                            self.event['base64'].append(keyword)
                        elif macro_type == 'Dridex String':
                            self.event['dridex'].append(keyword)
                        elif macro_type == 'Hex String':
                            self.event['hex'].append(keyword)
                        elif macro_type == 'IOC':
                            self.event['ioc'].append(keyword)
                        elif macro_type == 'Suspicious':
                            self.event['suspicious'].append(keyword)

        except olevba.FileOpenError:
            self.flags.append('file_open_error')
        finally:
            # TODO referenced before potential assignment as vba is opened in a try / catch block
            vba.close()
示例#10
0
    def extract_macro(self):
        vba = olevba.VBA_Parser(self.sample)
        macro_code = ""

        if vba.detect_vba_macros():
            for (filename, stream_path, vba_filename,
                 vba_code) in vba.extract_macros():
                macro_code += olevba.filter_vba(vba_code)

            self.results["analysis"] = vba.analyze_macros()

            self.results["code"] = macro_code
            vba.close()
            return self.results

        vba.close()
        return False
示例#11
0
    def make_analysis(self):
        """
        Function that make the file analysis
        :return:
        """
        logging.debug('\n\n%s' % self.separator)
        ole_parser = olevba.VBA_Parser(self.file_path)
        if not ole_parser.detect_vba_macros():
            return logging.info('No VBA Macros were found in this file')
        logging.critical('VBA Macros found')

        # Extracts the macro into analysis path
        for filename, stream_path, vba_filename, vba_code in ole_parser.extract_macros():
            logging.debug(self.separator)
            logging.info('OLE stream    : %s' % stream_path)
            logging.info('VBA filename  : %s' % vba_filename)

            tp = os.path.join(self.analysis_path, vba_filename)
            with open(tp, 'w') as f:
                f.write(vba_code)

            logging.warning('\nSaved in: "%s"\n' % tp)

        # Analyze all macros
        logging.debug(self.separator)
        logging.critical('Keywords: \n')
        for kw_type, keyword, description in ole_parser.analyze_macros():
            logging.warning('Type: %s' % kw_type)
            logging.info('Keyword: %s\nDescription: %s\n' % (keyword, description))

        logging.debug(self.separator)
        logging.critical('Analysis: \n')
        logging.warning('VBA obfuscated strings: %d' % ole_parser.nb_vbastrings)
        logging.warning('IOCs: %d' % ole_parser.nb_iocs)
        logging.warning('AutoExec keywords: %d' % ole_parser.nb_autoexec)
        logging.warning('Suspicious keywords: %d' % ole_parser.nb_suspicious)
        logging.warning('Hex obfuscated strings: %d' % ole_parser.nb_hexstrings)
        logging.warning('Base64 obfuscated strings: %d' % ole_parser.nb_base64strings)
        logging.warning('Dridex obfuscated strings: %d' % ole_parser.nb_dridexstrings)
示例#12
0
    def analyze(self, afile):
        '''Analyze OLE files and extract metadata about the file into the 
		FileAnalysis object.

		Args:
			afile (FileAnalysis): The file to be analyzed.
		
		Returns:
			None
		'''
        if afile.mime_type in self.analyzed_mimes:

            # Parse the metadata for the ole file and add all ole metadata
            # attributes to the FileAnalysis object. This should add a ton
            # of contectual information to the file.
            try:
                ole = olefile.OleFileIO(afile.path)
                process_metadata = True
            except IOError:
                afile.errors = afile.errors + [
                    'doc plugin: unsupported filetype'
                ]
                output = 'None'
                afile.plugin_output[self.__NAME__] = output
                process_metadata = False
            # There are OLE files out there with LOTS of embedded objects.
            # This should prevent plugin crashes for those cases.
            except RuntimeError:
                afile.errors = afile.errors + [
                    'doc plugin: max recursion reached'
                ]
                output = 'None'
                process_metadata = False
                afile.suspicious = True
                process_metadata = False

            if process_metadata:
                meta = ole.get_metadata()
                # These loops iterate through the meta for attributes and then
                # set attributes with the same name in the FileAnalysis object
                for prop in meta.SUMMARY_ATTRIBS:
                    value = getattr(meta, prop)
                    setattr(afile, prop, value)

                for prop in meta.DOCSUM_ATTRIBS:
                    value = getattr(meta, prop)
                    setattr(afile, prop, value)

                # Thumbnails are binary streams and muck up the output so they
                # are removed. This is a temporary work-around... the doc
                # analyzer will be rewritten to accomidate things like this
                if hasattr(afile, 'thumbnail'):
                    afile.has_thumbnail = True
                    del afile.thumbnail

                # Explicitly call close to ensure that the ole object gets closed
                ole.close()

            # Parse the file again, this time looking for VBA scripts.
            try:
                parser = olevba.VBA_Parser(afile.path)
            except TypeError:
                afile.errors = afile.errors + [
                    'doc plugin: unsupported filetype'
                ]
                output = 'None'
                afile.plugin_output[self.__NAME__] = output
                return

            results = parser.analyze_macros()

            contains_macro = parser.detect_vba_macros()
            if contains_macro and self.alert_on_macro:
                afile.alert = True
            if contains_macro and self.suspicious_on_macro:
                afile.suspicious = True

            output = ''

            if results is not None:
                for result in results:
                    output = output + '[%s] keyword: %s description: %s' % result
            else:
                output = 'None'

            if contains_macro:
                afile.vba = parser.reveal()

            afile.plugin_output[self.__NAME__] = output

            # The parser requires an explicit close
            parser.close()
示例#13
0
    def checkforVBA(self, msg):
        '''
			Checks if it contains a vba macro and checks if user is whitelisted or file already parsed
		'''
        # Accept all messages with no attachment
        result = Milter.ACCEPT
        try:
            for part in msg.walk():
                # for name, value in part.items():
                #     log.debug(' - %s: %r' % (name, value))
                content_type = part.get_content_type()
                log.debug('[%d] Content-Type: %r' % (self.id, content_type))
                # TODO: handle any content-type, but check the file magic?
                if not content_type.startswith('multipart'):
                    filename = part.get_filename(None)
                    attachment = part.get_payload(decode=True)
                    if attachment is None:
                        return Milter.CONTINUE
                    log.debug('[%d] Analyzing attachment: %r' %
                              (self.id, filename))
                    attachment_lowercase = attachment.lower()
                    attachment_fileobj = StringIO.StringIO(attachment)
                    # check if file was already parsed
                    if self.fileHasAlreadyBeenParsed(attachment):
                        return Milter.REJECT
                    # check if this is a supported file type (if not, just skip it)
                    # TODO: this function should be provided by olevba
                    if olefile.isOleFile(attachment_fileobj) or is_zipfile(attachment_fileobj) or 'http://schemas.microsoft.com/office/word/2003/wordml' in attachment \
                     or ('mime' in attachment_lowercase and 'version' in attachment_lowercase \
                     and 'multipart' in attachment_lowercase):
                        vba_code_all_modules = ''
                        # check if the attachment is a zip
                        if not olefile.isOleFile(attachment_fileobj):
                            extn = (os.path.splitext(filename)[1]).lower()
                            # skip non archives
                            if is_zipfile(attachment_fileobj) and not (
                                    ".docx" in extn or ".xlsx" in extn
                                    or ".pptx" in extn):
                                # extract all file in zip and add
                                try:
                                    zipvba = self.getZipFiles(
                                        attachment, filename)
                                    vba_code_all_modules += zipvba + '\n'
                                except ToManyZipException:
                                    log.warning(
                                        "[%d] Attachment %s is reached the max. nested zip count! ZipBomb?: REJECT"
                                        % (self.id, filename))
                                    # rewrite the reject message
                                    self.setreply(
                                        '550', '5.7.2',
                                        "The message contains a suspicious archive and was rejected!"
                                    )
                                    return Milter.REJECT
                        # check the rest of the message
                        vba_parser = olevba.VBA_Parser(filename='message',
                                                       data=attachment)
                        for (subfilename, stream_path, vba_filename,
                             vba_code) in vba_parser.extract_all_macros():
                            vba_code_all_modules += vba_code + '\n'
                        # run the mraptor
                        m = mraptor.MacroRaptor(vba_code_all_modules)
                        m.scan()
                        if m.suspicious:
                            # Add MD5 to the database
                            self.addHashtoDB(attachment)
                            # Replace the attachment or reject it
                            if REJECT_MESSAGE:
                                log.warning(
                                    '[%d] The attachment %r contains a suspicious macro: REJECT'
                                    % (self.id, filename))
                                result = Milter.REJECT
                            else:
                                log.warning(
                                    '[%d] The attachment %r contains a suspicious macro: replace it with a text file'
                                    % (self.id, filename))
                                part.set_payload(
                                    'This attachment has been removed because it contains a suspicious macro.'
                                )
                                part.set_type('text/plain')
                                part.replace_header(
                                    'Content-Transfer-Encoding', '7bit')
                        else:
                            log.debug('[%d] The attachment %r is clean.' %
                                      (self.id, filename))

        except Exception:
            log.error('[%d] Error while processing the message' % self.id)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            exep = ''.join('!! ' + line for line in lines)
            log.debug("[%d] Exeption code: [%s]" % (self.id, exep))

        if REJECT_MESSAGE is False:
            body = str(msg)
            self.message = io.BytesIO(body)
            self.replacebody(body)
            log.info('[%d] Message relayed' % self.id)
        return result
示例#14
0
for container, filename, data in xglob.iter_files(args,
                                                  recursive=True,
                                                  zip_password=None,
                                                  zip_fname=None):
    # ignore directory names stored in zip files:
    if container and filename.endswith('/'):
        continue
    full_name = '%s in %s' % (filename, container) if container else filename
    print(full_name)
    if isinstance(data, Exception):
        print("Error occured")
    else:
        filetype = '???'
        try:
            vba_parser = olevba.VBA_Parser(filename=filename,
                                           data=data,
                                           container=container)
            filetype = TYPE2TAG[vba_parser.type]
        except Exception as e:
            print(e)
            continue
        if vba_parser.detect_vba_macros():
            vba_code_all_modules = ''
            try:
                for (subfilename, stream_path, vba_filename,
                     vba_code) in vba_parser.extract_all_macros():
                    vba_code_all_modules += vba_code + '\n'
            except Exception as e:
                print(e)
                continue
        mraptor = MacroRaptor(vba_code_all_modules)
import re
import io
import sys
import pefile
import olefile
import hashlib
import zipfile
import tempfile
from subprocess import Popen, PIPE
from oletools import olevba
from base64 import b64decode

B64_RX ='(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?'

vba =  olevba.VBA_Parser(sys.argv[1])
path = ['Macros','UserForm1','o']
ole = vba.ole_file
if not ole:
   zipf = zipfile.ZipFile(sys.argv[1])
   data=zipf.read('word/vbaProject.bin')
   vba =  olevba.VBA_Parser(io.BytesIO(data))
   path = ['UserForm1','o']

ole = vba.ole_file
for _, _, _, t in  vba.extract_macros():
    x = t.find('Lib "')
    if x !=-1:
       print('LIB: '+t[x+5:x+200].split('"')[0])
    x = t.find('"S-')
    if x != -1:
       print('KEY: '+t[x+1:x+200].split('"')[0])
示例#16
0
    def check_macros(self):
        """
        Check whether this file contains macros (VBA and XLM/Excel 4).

        :returns: :py:class:`Indicator`
        """
        vba_indicator = Indicator(
            _id='vba',
            value='No',
            _type=str,
            name='VBA Macros',
            description='This file does not contain VBA macros.',
            risk=RISK.NONE,
            hide_if_false=False)
        self.indicators.append(vba_indicator)
        xlm_indicator = Indicator(
            _id='xlm',
            value='No',
            _type=str,
            name='XLM Macros',
            description='This file does not contain Excel 4/XLM macros.',
            risk=RISK.NONE,
            hide_if_false=False)
        self.indicators.append(xlm_indicator)
        if self.ftg.filetype == ftguess.FTYPE.RTF:
            # For RTF we don't call olevba otherwise it triggers an error
            vba_indicator.description = 'RTF files cannot contain VBA macros'
            xlm_indicator.description = 'RTF files cannot contain XLM macros'
            return vba_indicator, xlm_indicator
        vba_parser = None  # flag in case olevba fails
        try:
            vba_parser = olevba.VBA_Parser(filename=self.filename,
                                           data=self.data)
            if vba_parser.detect_vba_macros():
                vba_indicator.value = 'Yes'
                vba_indicator.risk = RISK.MEDIUM
                vba_indicator.description = 'This file contains VBA macros. No suspicious keyword was found. Use olevba and mraptor for more info.'
                # check code with mraptor
                vba_code = vba_parser.get_vba_code_all_modules()
                m = mraptor.MacroRaptor(vba_code)
                m.scan()
                if m.suspicious:
                    vba_indicator.value = 'Yes, suspicious'
                    vba_indicator.risk = RISK.HIGH
                    vba_indicator.description = 'This file contains VBA macros. Suspicious keywords were found. Use olevba and mraptor for more info.'
        except Exception as e:
            vba_indicator.risk = RISK.ERROR
            vba_indicator.value = 'Error'
            vba_indicator.description = 'Error while checking VBA macros: %s' % str(
                e)
        # Check XLM macros only for Excel file types:
        if self.ftg.is_excel():
            # TODO: for now XLM detection only works for files on disk... So we need to reload VBA_Parser from the filename
            #       To be improved once XLMMacroDeobfuscator can work on files in memory
            if self.file_on_disk:
                try:
                    vba_parser = olevba.VBA_Parser(filename=self.filename)
                    if vba_parser.detect_xlm_macros():
                        xlm_indicator.value = 'Yes'
                        xlm_indicator.risk = RISK.MEDIUM
                        xlm_indicator.description = 'This file contains XLM macros. Use olevba to analyse them.'
                except Exception as e:
                    xlm_indicator.risk = RISK.ERROR
                    xlm_indicator.value = 'Error'
                    xlm_indicator.description = 'Error while checking XLM macros: %s' % str(
                        e)
            else:
                xlm_indicator.risk = RISK.UNKNOWN
                xlm_indicator.value = 'Unknown'
                xlm_indicator.description = 'For now, XLM macros can only be detected for files on disk, not in memory'

        return vba_indicator, xlm_indicator
示例#17
0
def main():
    """
    Main function, called when olevba is run from the command line
    """
    DEFAULT_LOG_LEVEL = "warning" # Default log level

    usage = 'usage: mraptor [options] <filename> [filename2 ...]'
    parser = optparse.OptionParser(usage=usage)
    parser.add_option("-r", action="store_true", dest="recursive",
                      help='find files recursively in subdirectories.')
    parser.add_option("-z", "--zip", dest='zip_password', type='str', default=None,
                      help='if the file is a zip archive, open all files from it, using the provided password (requires Python 2.6+)')
    parser.add_option("-f", "--zipfname", dest='zip_fname', type='str', default='*',
                      help='if the file is a zip archive, file(s) to be opened within the zip. Wildcards * and ? are supported. (default:*)')
    parser.add_option('-l', '--loglevel', dest="loglevel", action="store", default=DEFAULT_LOG_LEVEL,
                            help="logging level debug/info/warning/error/critical (default=%default)")
    parser.add_option("-m", '--matches', action="store_true", dest="show_matches",
                      help='Show matched strings.')

    # TODO: add logfile option

    (options, args) = parser.parse_args()

    # Print help if no arguments are passed
    if len(args) == 0:
        print('MacroRaptor %s - http://decalage.info/python/oletools' % __version__)
        print('This is work in progress, please report issues at %s' % URL_ISSUES)
        print(__doc__)
        parser.print_help()
        print('\nAn exit code is returned based on the analysis result:')
        for result in (Result_NoMacro, Result_NotMSOffice, Result_MacroOK, Result_Error, Result_Suspicious):
            print(' - %d: %s' % (result.exit_code, result.name))
        sys.exit()

    # print banner with version
    print('MacroRaptor %s - http://decalage.info/python/oletools' % __version__)
    print('This is work in progress, please report issues at %s' % URL_ISSUES)

    log_helper.enable_logging(level=options.loglevel)
    # enable logging in the modules:
    olevba.enable_logging()

    t = tablestream.TableStream(style=tablestream.TableStyleSlim,
            header_row=['Result', 'Flags', 'Type', 'File'],
            column_width=[10, 5, 4, 56])

    exitcode = -1
    global_result = None
    # TODO: handle errors in xglob, to continue processing the next files
    for container, filename, data in xglob.iter_files(args, recursive=options.recursive,
                                                      zip_password=options.zip_password, zip_fname=options.zip_fname):
        # ignore directory names stored in zip files:
        if container and filename.endswith('/'):
            continue
        full_name = '%s in %s' % (filename, container) if container else filename
        # try:
        #     # Open the file
        #     if data is None:
        #         data = open(filename, 'rb').read()
        # except:
        #     log.exception('Error when opening file %r' % full_name)
        #     continue
        if isinstance(data, Exception):
            result = Result_Error
            t.write_row([result.name, '', '', full_name],
                        colors=[result.color, None, None, None])
            t.write_row(['', '', '', str(data)],
                        colors=[None, None, None, result.color])
        else:
            filetype = '???'
            try:
                vba_parser = olevba.VBA_Parser(filename=filename, data=data, container=container)
                filetype = TYPE2TAG[vba_parser.type]
            except Exception as e:
                # log.error('Error when parsing VBA macros from file %r' % full_name)
                # TODO: distinguish actual errors from non-MSOffice files
                result = Result_Error
                t.write_row([result.name, '', filetype, full_name],
                            colors=[result.color, None, None, None])
                t.write_row(['', '', '', str(e)],
                            colors=[None, None, None, result.color])
                continue
            if vba_parser.detect_vba_macros():
                vba_code_all_modules = ''
                try:
                    vba_code_all_modules = vba_parser.get_vba_code_all_modules()
                except Exception as e:
                    # log.error('Error when parsing VBA macros from file %r' % full_name)
                    result = Result_Error
                    t.write_row([result.name, '', TYPE2TAG[vba_parser.type], full_name],
                                colors=[result.color, None, None, None])
                    t.write_row(['', '', '', str(e)],
                                colors=[None, None, None, result.color])
                    continue
                mraptor = MacroRaptor(vba_code_all_modules)
                mraptor.scan()
                if mraptor.suspicious:
                    result = Result_Suspicious
                else:
                    result = Result_MacroOK
                t.write_row([result.name, mraptor.get_flags(), filetype, full_name],
                            colors=[result.color, None, None, None])
                if mraptor.matches and options.show_matches:
                    t.write_row(['', '', '', 'Matches: %r' % mraptor.matches])
            else:
                result = Result_NoMacro
                t.write_row([result.name, '', filetype, full_name],
                            colors=[result.color, None, None, None])
        if result.exit_code > exitcode:
            global_result = result
            exitcode = result.exit_code

    log_helper.end_logging()
    print('')
    print('Flags: A=AutoExec, W=Write, X=Execute')
    print('Exit code: %d - %s' % (exitcode, global_result.name))
    sys.exit(exitcode)
示例#18
0
    def _handle_mraptor_scan(self, param):
        self.save_progress("In action handler for: {0}".format(
            self.get_action_identifier()))
        action_result = self.add_action_result(ActionResult(dict(param)))
        summary = action_result.update_summary({})

        vault_id = param['vault_id']

        try:
            success, message, info = vault.vault_info(
                vault_id=vault_id,
                container_id=self.get_container_id(),
                trace=True)
            if phantom.is_fail(success):
                return action_result.set_status(phantom.APP_ERROR, message)
            info = list(info)
        except Exception as e:
            error_msg = self._get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR, error_msg)

        # phantom vault file path
        vault_path = info[0].get("path")
        if not vault_path:
            return action_result.set_status(phantom.APP_ERROR,
                                            OLETOOLS_ERR_UNABLE_TO_FETCH_FILE)

        try:
            oid = oletools.oleid.OleID(vault_path)
            indicators = oid.check()

            result = {"oleid": {}, "mraptor": {}}

            for i in indicators:
                result["oleid"][i.id] = {
                    "id": i.id,
                    "name": i.name,
                    "value": str(i.value)
                }

            summary["ftype"] = result["oleid"].get("ftype", {}).get("value")

            vba_parser = olevba.VBA_Parser(filename=vault_path)
            if vba_parser.detect_vba_macros():
                vba_code_all_modules = ''
                vba_code_all_modules = vba_parser.get_vba_code_all_modules()

                mraptor = MacroRaptor(vba_code_all_modules)
                mraptor.scan()
                result["mraptor"] = mraptor.__dict__
                summary['suspicious'] = mraptor.suspicious
        except Exception as e:
            error_msg = self._get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR, error_msg)

        action_result.add_data(result)

        # Add a dictionary that is made up of the most important values from data into the summary
        if not summary.get('suspicious'):
            summary["suspicious"] = False

        # Return success, no need to set the message, only the status
        # BaseConnector will create a textual message based off of the summary dictionary
        return action_result.set_status(phantom.APP_SUCCESS)