Esempio n. 1
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        rtfp = rtfobj.RtfObjParser(scanObject.buffer)  #import reference
        rtfp.parse()
        for rtfobject in rtfp.objects:
            i = rtfp.objects.index(rtfobject)  #index
            if rtfobject.is_package:
                objtypeis = "OLEPackage"
                typeolepackagedict = {}
                typeolepackagedict.update({
                    'Type': objtypeis,
                    'Index': i,
                    'Filename': rtfobject.filename,
                    'Source Patch': rtfobject.src_path,
                    'Temp Path': rtfobject.temp_path
                })
                scanObject.addMetadata(self.module_name,
                                       "Parsed_Objects_Metadata",
                                       typeolepackagedict)
                moduleResult.append(
                    ModuleObject(buffer=rtfobject.olepkgdata,
                                 externalVars=ExternalVars(
                                     filename='e_rtf_object_%08X.olepackage' %
                                     rtfobject.start)))

            elif rtfobject.is_ole:
                objtypeis = "OLE"
                typeoledict = {}
                typeoledict.update({
                    'Type': objtypeis,
                    'Index': i,
                    'Format_id': rtfobject.format_id,
                    'Class_name': rtfobject.class_name,
                    'Size': rtfobject.oledata_size
                })
                scanObject.addMetadata(self.module_name,
                                       "Parsed_Objects_Metadata", typeoledict)
                moduleResult.append(
                    ModuleObject(buffer=rtfobject.oledata,
                                 externalVars=ExternalVars(
                                     filename='e_rtf_object_%08X.ole' %
                                     rtfobject.start)))

            else:
                objtypeis = "RAW"  #Not a well-formed OLE object.
                typerawdict = {}
                typerawdict.update({'Type': objtypeis, 'Index': i})
                scanObject.addMetadata(self.module_name,
                                       "Parsed_Objects_Metadata", typerawdict)
                moduleResult.append(
                    ModuleObject(buffer=rtfobject.rawdata,
                                 externalVars=ExternalVars(
                                     filename='e_rtf_object_%08X.raw' %
                                     rtfobject.start)))

        return moduleResult
Esempio n. 2
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
Esempio n. 3
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []
        e = email.message_from_string(scanObject.buffer)

        attachments = []

        i = 1
        for p in e.walk():
            childBuffer = p.get_payload(decode=True)
            if childBuffer is not None:
                filename = p.get_filename()
                if filename is None:
                    filename = 'e_email_%s_%s' % (p.get_content_type(), i)
                else:
                    attachments.append(filename)
                logging.debug("explode email: found filename: %s" % (filename))
                moduleResult.append(
                    ModuleObject(buffer=childBuffer,
                                 externalVars=ExternalVars(
                                     filename=filename,
                                     contentType=p.get_content_maintype())))
                i += 1

        # If enabled, this will combine the email headers and all decoded
        # text portions contained in the email into a single object
        if strtobool(
                get_option(args, 'createhybrid', 'explodeemlcreatehybrid',
                           'False')):
            # First, grab the headers
            header_end = scanObject.buffer.find('\x0a\x0a')
            hybrid = scanObject.buffer[:header_end] + '\n\n'
            for mo in moduleResult:
                if 'text' in mo.externalVars.contentType:
                    hybrid += mo.buffer + '\n\n'

            # Add the hybrid as another object with a special content type
            # for easy identification.
            moduleResult.append(
                ModuleObject(
                    buffer=hybrid,
                    externalVars=ExternalVars(
                        filename='e_email_hybrid',
                        contentType='application/x-laika-eml-hybrid')))

        # Since we already gathered up the attachment names, we'll add them
        # on behalf of META_EMAIL
        scanObject.addMetadata('META_EMAIL', 'Attachments', attachments)

        return moduleResult
Esempio n. 4
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []
        minFileSize = 0  #Explode everything!
        useUnvalidatedFilenames = 0
        if 'minFileSize' in args:
            try:
                minFileSize = int(args['minFileSize'])
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                pass
        if 'useUnvalidatedFilenames' in args:
            try:
                minFileSize = int(args['useUnvalidatedFilenames'])
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                pass
        file = StringIO.StringIO()
        file.write(scanObject.buffer)
        file.flush()
        file.seek(0)
        ole = olefile.OleFileIO(file)

        lstStreams = ole.listdir()
        numStreams = 0
        for stream in lstStreams:
            try:
                if ole.get_size(stream) >= minFileSize:
                    numStreams += 1
                    streamF = ole.openstream(stream)
                    childBuffer = streamF.read()
                    if childBuffer:
                        filename = "e_ole_stream_" + str(numStreams)
                        try:
                            u = unicode(str(stream), "utf-8")
                            filename = u.encode("utf-8")

                        except (QuitScanException, GlobalScanTimeoutError,
                                GlobalModuleTimeoutError):
                            raise
                        except:
                            pass  #keep ole_stream_number as filename
                        moduleResult.append(
                            ModuleObject(
                                buffer=childBuffer,
                                externalVars=ExternalVars(filename=filename)))
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                log_module("MSG", self.module_name, 0, scanObject, result,
                           "ERROR EXTRACTING STREAM: " + str(stream))
        ole.close()
        file.close()
        return moduleResult
Esempio n. 5
0
    def _unzip_file(self, moduleResult, file, scanObject, result, password, file_limit, byte_limit):
        """
        Attempts to unzip the file, looping through the namelist and adding each
        object to the ModuleResult. We add the filename from the archive to the
        external variables so it is available during recursive scanning.

        If the file is encrypted (determined by an exception), add the flag and return

        Arguments:
        moduleResult -- an instance of the ModuleResult class created above
        file -- a file object created using the buffer passed into this _module
        scanObject -- an instance of the ScanObject class, created by the dispatcher
        result -- an instance of the ScanResult class, created by the caller
        password -- the password for the zipfile, if any
        file_limit -- the maximum number of files to explode, adds flag if exceeded
        byte_limit -- the maximum size in bytes for an exploded buffer, adds flag if exceeded

        Returns:
        Nothing, modification made directly moduleResult.
        """
        try:
            zf = zipfile.ZipFile(file)
            if password:
                zf.setpassword(password)
            file_count = 0
            #dir_depth_max = 0
            #dir_count = 0
            namelist = zf.namelist()
            scanObject.addMetadata(self.module_name, "Total_Files", len(namelist))
            exceeded_byte_limit = False
            for name in namelist:
                if byte_limit:
                    info = zf.getinfo(name)
                    if info.file_size > byte_limit:
                        logging.debug("EXPLODE_ZIP: skipping file due to byte limit")
                        exceeded_byte_limit = True
                        continue
                childBuffer = zf.read(name)
                if byte_limit and len(childBuffer) > byte_limit:
                    logging.debug("EXPLODE_ZIP: skipping file due to byte limit")
                    exceeded_byte_limit = True
                    continue
                moduleResult.append(ModuleObject(buffer=childBuffer,
                    externalVars=ExternalVars(filename='e_zip_%s' % name)))
                file_count += 1
                if file_limit and file_count >= file_limit:
                    scanObject.addFlag("zip:err:LIMIT_EXCEEDED")
                    logging.debug("EXPLODE_ZIP: breaking due to file limit")
                    break
            if exceeded_byte_limit:
                scanObject.addFlag("zip:err:BYTE_LIMIT_EXCEEDED")

        except RuntimeError as rte:
            if "encrypted" in rte.args[0]:
                scanObject.addFlag("ENCRYPTED_ZIP")
            else:
                raise
Esempio n. 6
0
    def _helloworld(buffer, moduleResult, helloworld_param):
        ''' 
        An example of a worker function you may include in your module.
        Note the @staticmethod "decorator" on the top of the function.
        These private methods are set to static to ensure immutability since
        they may be called more than once in the lifetime of the class
        '''
        flags = []

        # Using the logging module is a great way to create debugging output during testing without generating anything during production.
        # The Laika framework does not use the logging module for its logging (it uses syslog underneath several helpers found it laikaboss.util),
        # so none of thses messages will clutter up Laika logs.
        logging.debug('Hello world!')
        logging.debug('HELLOWORLD invoked with helloworld_param value %i',
                      helloworld_param)

        if helloworld_param < 10:
            flags.append('e_helloworld:nfo:helloworldsmall')
        else:
            logging.debug('HELLOWORLD(%i >= 10) setting flag',
                          helloworld_param)
            flags.append('e_helloworld:nfo:helloworld')

        if helloworld_param > 20:
            logging.debug('HELLOWORLD(%i > 20) adding new object',
                          helloworld_param)
            flags.append('e_helloworld:nfo:helloworldx2')

            if len(buffer) > helloworld_param:

                # Take the module buffer and trim the first helloworld_param size bytes.
                buff = buffer[helloworld_param:]

                object_name = 'e_helloworld_%s_%s' % (
                    len(buff), hashlib.md5(buff).hexdigest())

                logging.debug('HELLOWORLD - New object: %s', object_name)

                # And we can create new objects that go back to the dispatcher and subsequent laika modules
                # Any modifications we make to the "moduleResult" variable here will go back to the main function

                # laikaboss/objectmodel.py defines the variables you can set for externalVars. Two most common to set are
                #   contentType
                #   filename
                moduleResult.append(
                    ModuleObject(
                        buffer=buff,
                        externalVars=ExternalVars(filename=object_name)))

            else:
                logging.debug(
                    'HELLOWORLD - object is too small to carve (%i < %i)',
                    len(buffer), helloworld_param)

        return set(flags)
Esempio n. 7
0
 def _run(self, scanObject, result, depth, args):
     moduleResult = []
     try:
         decoded = base64.b64decode(scanObject.buffer)
         moduleResult.append(
             ModuleObject(buffer=decoded,
                          externalVars=ExternalVars(filename="d_base64_%s" %
                                                    len(decoded))))
         return moduleResult
     except:
         raise
Esempio n. 8
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        for index, obj_len, obj_data in rtfobj.rtf_iter_objects(
                scanObject.filename):
            # index location of the RTF object becomes the file name
            name = 'index_' + str(index)
            moduleResult.append(
                ModuleObject(buffer=obj_data,
                             externalVars=ExternalVars(filename='e_rtf_%s' %
                                                       name)))

        return moduleResult
Esempio n. 9
0
 def _run(self, scanObject, result, depth, args):
     ''' The core of your laika module. This is how your code will be invoked
         
         Requires:
             Package Dependencies Only
         Assumes:
             scanObject.buffer is a upx compressed executable
         Ensures:
             1. No propagating errors
             2. Decompressed buffer is returned as a new buffer to scanned
         Error Handling:
             1. If upx decompress fails, output file will not be created
                attempt to open the decompressed file will throw file not exists exception
                silently passed
         Module Execution:
             1. Dump the scanObject.buffer into a named temp file
             2. Call upx decompresser outputting to the <input_filename>_output
             3. Open the decompressed buffer file and read it into a buffer
             4. Close and delete the decompressed buffer file
             5. If length of the decompressed buffer is > the compressed buffer (decompression worked):
                True:  Add the buffer to the result object
                False: Do nothing (future perhaps add failed to decompress metadata?)
             6. Return
     '''
     moduleResult = []
     try:
         with tempfile.NamedTemporaryFile(
                 dir=self.TEMP_DIR) as temp_file_input:
             temp_file_input_name = temp_file_input.name
             temp_file_input.write(scanObject.buffer)
             temp_file_input.flush()
             temp_file_output_name = temp_file_input_name + "_output"
             strCMD = "upx -d " + temp_file_input_name + " -o " + temp_file_output_name
             outputString = pexpect.run(strCMD)
             f = open(
                 temp_file_output_name
             )  #if strCMD failed, this will throw a file not exists exception
             newbuf = f.read()
             f.close()
             os.remove(temp_file_output_name)
             if len(newbuf) > len(scanObject.buffer):
                 moduleResult.append(
                     ModuleObject(
                         buffer=newbuf,
                         externalVars=ExternalVars(filename="e_upx")))
     except (QuitScanException, GlobalScanTimeoutError,
             GlobalModuleTimeoutError):
         raise
     except:
         pass
     return moduleResult
Esempio n. 10
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        file = StringIO.StringIO(scanObject.buffer)
        gzip_file = gzip.GzipFile(fileobj=file)

        new_buffer = gzip_file.read()

        moduleResult.append(
            ModuleObject(buffer=new_buffer,
                         externalVars=ExternalVars(filename="gzip_%s" %
                                                   len(new_buffer))))

        return moduleResult
Esempio n. 11
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        flags = []

        buffer = scanObject.buffer
        cert = None

        try:
            #scanObject.addMetadata(self.module_name, key, value)

            input_bio = BIO.MemoryBuffer(buffer)

            #Check for PEM or DER
            if buffer[:1] == "0":
                #DER
                p7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(input_bio._ptr()), 1)
            else:
                #PEM
                p7 = SMIME.load_pkcs7_bio(input_bio)

            certs = p7.get0_signers(X509.X509_Stack())

            #some pkcs7's should have more than one certificate in them. openssl can extract them handily.
            #openssl pkcs7 -inform der -print_certs -in MYKEY.DSA
            i = 0
            for cert in certs:
                cert_filename = "%x.der" % (cert.get_serial_number())
                moduleResult.append(
                    ModuleObject(
                        buffer=cert.as_der(),
                        externalVars=ExternalVars(filename=cert_filename)))
                i = i + 1

        except (QuitScanException, GlobalScanTimeoutError,
                GlobalModuleTimeoutError):
            raise
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            logging.exception("Error parsing cert in " +
                              str(get_scanObjectUID(getRootObject(result))))

            ugly_error_string = str(exc_value)
            #nicer_error_string = string.split(string.split(ugly_error_string,":")[4])[0]
            nicer_error_string = ugly_error_string.split(":")[4].split()[0]

            scanObject.addFlag("pkcs7:err:" + nicer_error_string)

        return moduleResult
Esempio n. 12
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []

        pdfBuffer = cStringIO.StringIO(scanObject.buffer)

        try:

            pdfFile = PdfFileReader(pdfBuffer)

            docInfo = pdfFile.getDocumentInfo()
            for metaItem in docInfo:
                scanObject.addMetadata(self.module_name, metaItem[1:],
                                       str(docInfo[metaItem]))

            pdf = PDFParser(pdfBuffer)
            pdfDoc = PDFDocument(pdf)

            for xref in pdfDoc.xrefs:
                for objid in xref.get_objids():
                    try:
                        obj = pdfDoc.getobj(objid)
                        if isinstance(obj, dict):
                            for (key, val) in obj.iteritems():
                                if key in ['AA', 'OpenAction']:
                                    scanObject.addFlag('pdf:nfo:auto_action')
                                elif key in ['JS', 'Javascript']:
                                    scanObject.addFlag('pdf:nfo:js_embedded')
                        if isinstance(obj, PDFStream):
                            if 'Type' in obj.attrs and obj.attrs[
                                    'Type'] == LIT('EmbeddedFile'):
                                moduleResult.append(
                                    ModuleObject(
                                        buffer=obj.get_data(),
                                        externalVars=ExternalVars(
                                            filename='e_pdf_stream_%s' %
                                            objid)))

                    except PDFObjectNotFound:
                        scanObject.addFlag('pdf:err:missing_object_%s' % objid)
                    except ScanError:
                        raise

        except PSEOF:
            scanObject.addFlag('pdf:err:unexpected_eof')
        except ScanError:
            raise

        return moduleResult
Esempio n. 13
0
 def _run(self, scanObject, result, depth, args):
     moduleResult = [] 
     try:
         fstr = StringIO(scanObject.buffer) 
         fstr.seek(4)
         swf_size = struct.unpack("<i", fstr.read(4))[0]
         logging.debug("swf size is %s" % swf_size) 
         fstr.seek(0)
         fws = self._decompressSWF(fstr, swf_size)
         if fws != None and fws != "ERROR":
             moduleResult.append(ModuleObject(buffer=fws, externalVars=ExternalVars(filename='e_swf_%s' % swf_size)))
         return moduleResult
     except:
         raise
     finally:
         logging.debug("extract_swf - closing stringio handle in run")
         fstr.close()
Esempio n. 14
0
    def _run(self, scanObject, result, depth, args):

        moduleResult = []
        success = "Decompiled dotnet results available in dir: \n"
        try:
            outfile = "<insert_output_dir>/%s/decompiled_%s/" % (
                scanObject.rootUID, scanObject.objectHash)
            filename = "e_decompiled_dotnet_%s" % md5.new(
                scanObject.filename).hexdigest()
            outname = "decompiled_%s/\n" % scanObject.objectHash
            subprocess.check_output([
                'mono', '<path_to_exe>/dnSpy.Console.exe', '--no-resx',
                '--no-sln', scanObject.filename, '-o', outfile
            ])
            moduleResult.append(
                ModuleObject(buffer=success + outname,
                             externalVars=ExternalVars(filename=filename)))
        except ScanError:
            raise

        return moduleResult
Esempio n. 15
0
    def _run(self, scanObject, result, depth, args):

        moduleResult = []
        try:

            # Create a temp file so isoparser has a file to analyze
            with tempfile.NamedTemporaryFile(dir=self.TEMP_DIR) as temp_file_input:
                temp_file_input_name = temp_file_input.name
                temp_file_input.write(scanObject.buffer)
                temp_file_input.flush()

                # Create an iso object
                iso = isoparser.parse(temp_file_input_name)

                # Loop through iso and identify child object. Write each child object to output directory
                for child in iso.root.children:
                    child_md5 = hashlib.md5(child.content).hexdigest()
                    moduleResult.append(ModuleObject(buffer=child.content, externalVars=ExternalVars(filename='e_iso_%s' % child_md5)))

        except ScanError:
            raise

        return moduleResult
Esempio n. 16
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []
        imports = {}
        sections = {}
        dllChars = []
        imgChars = []
        exports = []
        cpu = []
        res_type = ""

        try:
            pe = pefile.PE(data=scanObject.buffer)

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680341%28v=vs.85%29.aspx
            for section in pe.sections:
                secAttrs = []
                secName = section.Name.strip('\0')
                secData = {
                    'Virtual Address': '0x%08X' % section.VirtualAddress,
                    'Virtual Size': section.Misc_VirtualSize,
                    'Raw Size': section.SizeOfRawData,
                    'MD5': section.get_hash_md5()
                }
                if secData['MD5'] != scanObject.objectHash:
                    moduleResult.append(
                        ModuleObject(
                            buffer=section.get_data(),
                            externalVars=ExternalVars(filename=secName)))

                secChar = section.Characteristics
                if secChar & 0x20: secAttrs.append('CNT_CODE')
                if secChar & 0x40: secAttrs.append('CNT_INITIALIZED_DATA')
                if secChar & 0x80: secAttrs.append('CNT_UNINITIALIZED_DATA')
                if secChar & 0x200: secAttrs.append('LNK_INFO')
                if secChar & 0x2000000: secAttrs.append('MEM_DISCARDABLE')
                if secChar & 0x4000000: secAttrs.append('MEM_NOT_CACHED')
                if secChar & 0x8000000: secAttrs.append('MEM_NOT_PAGED')
                if secChar & 0x10000000: secAttrs.append('MEM_SHARED')
                if secChar & 0x20000000: secAttrs.append('MEM_EXECUTE')
                if secChar & 0x40000000: secAttrs.append('MEM_READ')
                if secChar & 0x80000000: secAttrs.append('MEM_WRITE')
                secData['Section Characteristics'] = secAttrs

                sections[secName] = secData
            sections['Total'] = pe.FILE_HEADER.NumberOfSections
            scanObject.addMetadata(self.module_name, 'Sections', sections)

            try:
                for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
                    exports.append(exp.name)
                scanObject.addMetadata(self.module_name, 'Exports', exports)
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                logging.debug('No export entries')

            try:
                for entry in pe.DIRECTORY_ENTRY_IMPORT:
                    api = []
                    for imp in entry.imports:
                        api.append(imp.name)
                    imports[entry.dll] = filter(None, api)
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                logging.debug('No import entries')
            scanObject.addMetadata(self.module_name, 'Imports', imports)

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680313%28v=vs.85%29.aspx
            imgChar = pe.FILE_HEADER.Characteristics
            if imgChar & 0x1: imgChars.append('RELOCS_STRIPPED')
            if imgChar & 0x2: imgChars.append('EXECUTABLE_IMAGE')
            if imgChar & 0x4: imgChars.append('LINE_NUMS_STRIPPED')
            if imgChar & 0x8: imgChars.append('LOCAL_SYMS_STRIPPED')
            if imgChar & 0x10: imgChars.append('AGGRESIVE_WS_TRIM')
            if imgChar & 0x20: imgChars.append('LARGE_ADDRESS_AWARE')
            if imgChar & 0x80: imgChars.append('BYTES_REVERSED_LO')
            if imgChar & 0x100: imgChars.append('32BIT_MACHINE')
            if imgChar & 0x200: imgChars.append('DEBUG_STRIPPED')
            if imgChar & 0x400: imgChars.append('REMOVABLE_RUN_FROM_SWAP')
            if imgChar & 0x800: imgChars.append('NET_RUN_FROM_SWAP')
            if imgChar & 0x1000: imgChars.append('SYSTEM_FILE')
            if imgChar & 0x2000: imgChars.append('DLL_FILE')
            if imgChar & 0x4000: imgChars.append('UP_SYSTEM_ONLY')
            if imgChar & 0x8000: imgChars.append('BYTES_REVERSED_HI')

            scanObject.addMetadata(self.module_name, 'Image Characteristics',
                                   imgChars)

            scanObject.addMetadata(
                self.module_name, 'Date',
                datetime.fromtimestamp(
                    pe.FILE_HEADER.TimeDateStamp).isoformat())
            scanObject.addMetadata(self.module_name, 'Timestamp',
                                   pe.FILE_HEADER.TimeDateStamp)

            machine = pe.FILE_HEADER.Machine
            cpu.append(machine)

            # Reference: http://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#COFF_Header
            if machine == 0x14c: cpu.append('Intel 386')
            if machine == 0x14d: cpu.append('Intel i860')
            if machine == 0x162: cpu.append('MIPS R3000')
            if machine == 0x166: cpu.append('MIPS little endian (R4000)')
            if machine == 0x168: cpu.append('MIPS R10000')
            if machine == 0x169: cpu.append('MIPS little endian WCI v2')
            if machine == 0x183: cpu.append('old Alpha AXP')
            if machine == 0x184: cpu.append('Alpha AXP')
            if machine == 0x1a2: cpu.append('Hitachi SH3')
            if machine == 0x1a3: cpu.append('Hitachi SH3 DSP')
            if machine == 0x1a6: cpu.append('Hitachi SH4')
            if machine == 0x1a8: cpu.append('Hitachi SH5')
            if machine == 0x1c0: cpu.append('ARM little endian')
            if machine == 0x1c2: cpu.append('Thumb')
            if machine == 0x1d3: cpu.append('Matsushita AM33')
            if machine == 0x1f0: cpu.append('PowerPC little endian')
            if machine == 0x1f1:
                cpu.append('PowerPC with floating point support')
            if machine == 0x200: cpu.append('Intel IA64')
            if machine == 0x266: cpu.append('MIPS16')
            if machine == 0x268: cpu.append('Motorola 68000 series')
            if machine == 0x284: cpu.append('Alpha AXP 64-bit')
            if machine == 0x366: cpu.append('MIPS with FPU')
            if machine == 0x466: cpu.append('MIPS16 with FPU')
            if machine == 0xebc: cpu.append('EFI Byte Code')
            if machine == 0x8664: cpu.append('AMD AMD64')
            if machine == 0x9041: cpu.append('Mitsubishi M32R little endian')
            if machine == 0xc0ee: cpu.append('clr pure MSIL')

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339%28v=vs.85%29.aspx
            magic = pe.OPTIONAL_HEADER.Magic
            if magic == 0x10b: cpu.append('32_BIT')
            if magic == 0x20b: cpu.append('64_BIT')
            if magic == 0x107: cpu.append('ROM_IMAGE')

            cpu.append("0x%04X" % magic)

            scanObject.addMetadata(self.module_name, 'CPU', cpu)

            dllChar = pe.OPTIONAL_HEADER.DllCharacteristics
            if dllChar & 0x40: dllChars.append('DYNAMIC_BASE')
            if dllChar & 0x80: dllChars.append('FORCE_INTEGRITY')
            if dllChar & 0x100: dllChars.append('NX_COMPAT')
            if dllChar & 0x200: dllChars.append('NO_ISOLATION')
            if dllChar & 0x400: dllChars.append('NO_SEH')
            if dllChar & 0x800: dllChars.append('NO_BIND')
            if dllChar & 0x2000: dllChars.append('WDM_DRIVER')
            if dllChar & 0x8000: dllChars.append('TERMINAL_SERVER_AWARE')

            scanObject.addMetadata(self.module_name, 'DLL Characteristics',
                                   dllChars)

            subsystem = pe.OPTIONAL_HEADER.Subsystem
            if subsystem == 0:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'UNKNOWN')
            if subsystem == 1:
                scanObject.addMetadata(self.module_name, 'Subsystem', 'NATIVE')
            if subsystem == 2:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'WINDOWS_GUI')
            if subsystem == 3:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'WINDOWS_CUI')
            if subsystem == 5:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'OS2_CUI')
            if subsystem == 7:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'POSIX_CUI')
            if subsystem == 9:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'WINDOWS_CE_GUI')
            if subsystem == 10:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'EFI_APPLICATION')
            if subsystem == 11:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'EFI_BOOT_SERVICE_DRIVER')
            if subsystem == 12:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'EFI_RUNTIME_DRIVER')
            if subsystem == 13:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'EFI_ROM')
            if subsystem == 14:
                scanObject.addMetadata(self.module_name, 'Subsystem', 'XBOX')
            if subsystem == 16:
                scanObject.addMetadata(self.module_name, 'Subsystem',
                                       'BOOT_APPLICATION')

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648009%28v=vs.85%29.aspx

            try:
                for resource in pe.DIRECTORY_ENTRY_RESOURCE.entries:
                    if resource.id == 9: res_type = "RT_ACCELERATOR"
                    if resource.id == 21: res_type = "RT_ANICURSOR"
                    if resource.id == 22: res_type = "RT_ANIICON"
                    if resource.id == 2: res_type = "RT_BITMAP"
                    if resource.id == 1: res_type = "RT_CURSOR"
                    if resource.id == 5: res_type = "RT_DIALOG"
                    if resource.id == 17: res_type = "RT_DLGINCLUDE"
                    if resource.id == 8: res_type = "RT_FONT"
                    if resource.id == 7: res_type = "RT_FONTDIR"
                    if resource.id == 12: res_type = "RT_GROUP_CURSOR"
                    if resource.id == 14: res_type = "RT_GROUP_ICON"
                    if resource.id == 23: res_type = "RT_HTML"
                    if resource.id == 3: res_type = "RT_ICON"
                    if resource.id == 24: res_type = "RT_MANIFEST"
                    if resource.id == 4: res_type = "RT_MENU"
                    if resource.id == 11: res_type = "RT_MESSAGETABLE"
                    if resource.id == 19: res_type = "RT_PLUGPLAY"
                    if resource.id == 10: res_type = "RT_RCDATA"
                    if resource.id == 6: res_type = "RT_STRING"
                    if resource.id == 16: res_type = "RT_VERSION"
                    if resource.id == 20: res_type = "RT_VXD"

                    for entry in resource.directory.entries:
                        scanObject.addMetadata(self.module_name, 'Resources',
                                               res_type + "_%s" % entry.id)
            except (QuitScanException, GlobalScanTimeoutError,
                    GlobalModuleTimeoutError):
                raise
            except:
                logging.debug('No resources')

            scanObject.addMetadata(self.module_name, 'Stack Reserve Size',
                                   pe.OPTIONAL_HEADER.SizeOfStackReserve)
            scanObject.addMetadata(self.module_name, 'Stack Commit Size',
                                   pe.OPTIONAL_HEADER.SizeOfStackCommit)

            scanObject.addMetadata(self.module_name, 'Heap Reserve Size',
                                   pe.OPTIONAL_HEADER.SizeOfHeapReserve)
            scanObject.addMetadata(self.module_name, 'Heap Commit Size',
                                   pe.OPTIONAL_HEADER.SizeOfHeapCommit)

            scanObject.addMetadata(self.module_name, 'EntryPoint',
                                   hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint))
            scanObject.addMetadata(self.module_name, 'ImageBase',
                                   hex(pe.OPTIONAL_HEADER.ImageBase))

            # Parse RSDS & Rich
            scanObject.addMetadata(self.module_name, 'RSDS',
                                   self.parseRSDS(scanObject))
            scanObject.addMetadata(self.module_name, 'Rich',
                                   self.parseRich(pe))

        except pefile.PEFormatError:
            logging.debug("Invalid PE format")

        return moduleResult
Esempio n. 17
0
    def _run(self, scanObject, result, depth, args):
        '''Laika framework module logic execution'''
        moduleResult = []

        file_limit = int(get_option(args, 'filelimit', 'rarfilelimit', 0))
        byte_limit = int(get_option(args, 'bytelimit', 'rarbytelimit', 0))
        password = get_option(args, 'password', 'rarpassword')
        attempt_decrypt = strtobool(
            get_option(args, 'attemptdecrypt', 'rarattemptdecrypt', 'false'))
        temp_dir = get_option(args, 'tempdir', 'tempdir', '/tmp/laikaboss_tmp')
        if not os.path.isdir(temp_dir):
            os.mkdir(temp_dir)
            os.chmod(temp_dir, 0777)

        # A temp file must be created as UnRAR2 does not accept buffers
        with tempfile.NamedTemporaryFile(dir=temp_dir) as temp_file:
            temp_file.write(scanObject.buffer)
            temp_file.flush()

            # RAR can be password protected, which encrypts the headers
            headers_are_encrypted = False
            # RAR can encrypt the files while leaving the headers decrypted
            files_are_encrypted = False

            rar = None
            # list of the file info objects
            infos = []

            try:
                logging.debug('%s: Attempting to open rar file',
                              self.module_name)
                # If headers are encrypted, the following will raise IncorrectRARPassword
                rar = UnRAR2.RarFile(temp_file.name)
                infos = rar.infolist()
                logging.debug('%s: Succeeded opening rar file',
                              self.module_name)

                # If files are encrypted, the filename will be prefixed with a '*'
                for info in infos:
                    if info.filename.startswith('*'):
                        logging.debug('%s: Rar files are encrypted',
                                      self.module_name)
                        scanObject.addFlag('ENCRYPTED_RAR')
                        scanObject.addMetadata(self.module_name, "Encrypted",
                                               "Protected Files")
                        files_are_encrypted = True
                        break
            except IncorrectRARPassword:
                logging.debug('%s: Rar headers are encrypted',
                              self.module_name)
                scanObject.addFlag('ENCRYPTED_RAR')
                scanObject.addMetadata(self.module_name, "Encrypted",
                                       "Protected Header")
                headers_are_encrypted = True
            except InvalidRARArchive:
                logging.debug('%s: Invalid Rar file')

            if (headers_are_encrypted
                    or files_are_encrypted) and attempt_decrypt:
                logging.debug('%s: Attempting to decrypt', self.module_name)
                possible_passwords = []

                # Passwords are sometimes sent in the email content. Use the content of the parent
                # object as the list of possible passwords
                parent_object = getParentObject(result, scanObject)
                if parent_object:
                    possible_passwords = _create_word_list(
                        parent_object.buffer)

                if password:
                    possible_passwords.insert(0, password)

                explode_temp_dir = os.path.join(temp_dir, 'exploderar')
                for possible_password in possible_passwords:
                    try:
                        logging.debug("EXPLODE_RAR: Attempting password '%s'",
                                      possible_password)
                        rar = UnRAR2.RarFile(temp_file.name,
                                             password=possible_password)
                        # Extraction is needed to force the exception on encrypted files
                        if files_are_encrypted:
                            rar.extract(path=explode_temp_dir)
                        infos = rar.infolist()
                        logging.debug("EXPLODE_RAR: Found password '%s'",
                                      possible_password)
                        scanObject.addFlag('rar:decrypted')
                        scanObject.addMetadata(self.module_name, 'Password',
                                               possible_password)
                        break
                    except IncorrectRARPassword:
                        continue
                if os.path.exists(explode_temp_dir):
                    remove_dir(explode_temp_dir)

            scanObject.addMetadata(self.module_name, "Total_Files", len(infos))
            file_count = 0
            exceeded_byte_limit = False
            for info in infos:
                if byte_limit and info.size > byte_limit:
                    logging.debug(
                        "EXPLODE_RAR: skipping file due to byte limit")
                    exceeded_byte_limit = True
                    continue
                try:
                    content = rar.read_files(info.filename)[0][1]
                    if byte_limit and len(content) > byte_limit:
                        logging.debug(
                            "EXPLODE_RAR: skipping file due to byte limit")
                        exceeded_byte_limit = True
                        continue
                    moduleResult.append(
                        ModuleObject(
                            buffer=content,
                            externalVars=ExternalVars(filename=info.filename)))
                except IndexError:
                    pass
                file_count += 1
                if file_limit and file_count >= file_limit:
                    scanObject.addFlag("rar:err:LIMIT_EXCEEDED")
                    logging.debug("EXPLODE_RAR: breaking due to file limit")
                    break
            if exceeded_byte_limit:
                scanObject.addFlag("rar:err:BYTE_LIMIT_EXCEEDED")

        scanObject.addMetadata(self.module_name, "Unzipped", len(moduleResult))
        return moduleResult
Esempio n. 18
0
    def _run(self, scanObject, result, depth, args):
        logging.debug("tactical: args: %s" % repr(args))
        moduleResult = []
        output = ''

        script_path = None
        timeout = "30"
        if 'timeout' in args:
            timeout = args['timeout']

        # Option to remove directory containing temp files
        unlinkDir = False
        if 'unlinkDir' in args:
            if args['unlinkDir'].upper() == 'TRUE':
                unlinkDir = True

        #only do something if script is defined in dispatcher--without external script this does nothing
        if 'script' in args:
            script_path = args['script']

            #temp_file_h, temp_file_name = tempfile.mkstemp()
            with tempfile.NamedTemporaryFile(dir=self.TEMP_DIR) as temp_file:
                temp_file_name = temp_file.name

                temp_file.write(scanObject.buffer)
                temp_file.flush()
                #use timeout command in the command, if available on the system?
                output = self._collect(
                    "timeout %s %s %s %s" %
                    (timeout, script_path, temp_file_name, self.TEMP_DIR),
                    shell=True)
                logging.debug(output)
                tmp_dirs = []
                for line in output.splitlines():
                    #need to process the lines
                    line_type = line[:5]
                    line_value = line[5:].strip()

                    if line_type == "FLAG:":
                        #not doing any validation on the flags, but truncating on length
                        scanObject.addFlag(line_value[:20])
                    elif line_type == "META:":
                        (meta_key, meta_sep,
                         meta_value) = line_value.partition('=')
                        scanObject.addMetadata(self.module_name, meta_key,
                                               meta_value)
                    elif line_type == "FILE:":
                        # Check to see if the file is actually a directory (silly 7zip)
                        if os.path.isdir(line_value):
                            # If the file is a directory and we don't already know about it, add it to the list
                            if line_value not in tmp_dirs:
                                tmp_dirs.append(line_value)
                            # Skip this since it's a directory
                            continue
                        # If we don't already know about this directory, add it to the list
                        if os.path.dirname(line_value) not in tmp_dirs:
                            file_path = os.path.dirname(line_value)
                            tmp_dirs.append(file_path)
                        try:
                            with open(line_value, 'r') as result_file:
                                moduleResult.append(
                                    ModuleObject(buffer=result_file.read(),
                                                 externalVars=ExternalVars(
                                                     filename=os.path.basename(
                                                         line_value))))
                        except:
                            raise
                        finally:
                            #make sure the incoming file is deleted, or at least we try....
                            logging.debug("Trying to unlink file: %s" %
                                          (line_value))
                            os.unlink(line_value)
                    else:
                        pass
                if unlinkDir:
                    logging.debug("Attempting to remove temp directories: %s" %
                                  (tmp_dirs))
                    # Loop through the directories and remove them, starting with the deepest level (by length)
                    for tmp_dir in sorted(tmp_dirs, key=len, reverse=True):
                        try:
                            rmtree(tmp_dir)
                        except (QuitScanException, GlobalScanTimeoutError,
                                GlobalModuleTimeoutError):
                            raise
                        except:
                            log_module(
                                "MSG", self.module_name, 0, scanObject, result,
                                "Could not remove tmp dir %s" % (tmp_dir))
                            logging.exception(
                                "Unable to remove temp directory: %s" %
                                (tmp_dir))

        return moduleResult
Esempio n. 19
0
    def _run(self, scanObject, result, depth, args):
        moduleResult = []
        imports = {}
        sections = {}
        exports = []

        try:
            pe = pefile.PE(data=scanObject.buffer)
            dump_dict = pe.dump_dict()

            # Parse sections
            for section in dump_dict.get('PE Sections', []):
                secName = section.get('Name', {}).get('Value', '').strip('\0')
                ptr = section.get('PointerToRawData', {}).get('Value')
                virtAddress = section.get('VirtualAddress', {}).get('Value')
                virtSize = section.get('Misc_VirtualSize', {}).get('Value')
                size = section.get('SizeOfRawData', {}).get('Value')
                secData = pe.get_data(ptr, size)
                secInfo = {
                    'Virtual Address': '0x%08X' % virtAddress,
                    'Virtual Size': virtSize,
                    'Raw Size': size,
                    'MD5': section.get('MD5', ''),
                    'SHA1': section.get('SHA1', ''),
                    'SHA256': section.get('SHA256', ''),
                    'Entropy': section.get('Entropy', ''),
                    'Section Characteristics': section.get('Flags', []),
                    'Structure': section.get('Structure', ''),
                }
                if secInfo['MD5'] != scanObject.objectHash:
                    moduleResult.append(ModuleObject(
                        buffer=secData,
                        externalVars=ExternalVars(filename=secName)))
                sections[secName] = secInfo
            sections['Total'] = pe.FILE_HEADER.NumberOfSections
            scanObject.addMetadata(self.module_name, 'Sections', sections)

            # Parse imports and exports
            try:
                for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
                    exports.append(exp.name)
                scanObject.addMetadata(self.module_name, 'Exports', exports)
            except ScanError:
                raise
            except:
                logging.debug('No export entries')

            for imp_symbol in dump_dict.get('Imported symbols',[]):
                for imp in imp_symbol:
                    if imp.get('DLL'):
                        dll = imp.get('DLL')
                        imports.setdefault(dll, [])
                        # Imports can be identified by ordinal or name
                        if imp.get('Ordinal'):
                            ordinal = imp.get('Ordinal')
                            imports[dll].append(ordinal)
                        if imp.get('Name'):
                            name = imp.get('Name')
                            imports[dll].append(name)
            scanObject.addMetadata(self.module_name, 'Imports', imports)

            # Parse resources
            try:
                for resource in pe.DIRECTORY_ENTRY_RESOURCE.entries:
                    res_type = pefile.RESOURCE_TYPE.get(resource.id, 'Unknown')
                    for entry in resource.directory.entries:
                        for e_entry in entry.directory.entries:
                            sublang = pefile.get_sublang_name_for_lang(
                                e_entry.data.lang,
                                e_entry.data.sublang,
                            )
                            offset = e_entry.data.struct.OffsetToData
                            size = e_entry.data.struct.Size
                            r_data = pe.get_data(offset, size)
                            language = pefile.LANG.get(
                                e_entry.data.lang, 'Unknown')
                            data = {
                                'Type': res_type,
                                'Id': e_entry.id,
                                'Name': e_entry.data.struct.name,
                                'Offset': offset,
                                'Size': size,
                                'SHA256': hashlib.sha256(r_data).hexdigest(),
                                'SHA1': hashlib.sha1(r_data).hexdigest(),
                                'MD5': hashlib.md5(r_data).hexdigest(),
                                'Language': language,
                                'Sub Language': sublang,
                            }
                            scanObject.addMetadata(
                                self.module_name, 'Resources', data)
            except ScanError:
                raise
            except:
                logging.debug('No resources')

            # Gather miscellaneous stuff
            try:
                scanObject.addMetadata(self.module_name,
                                       'Imphash', pe.get_imphash())
            except ScanError:
                raise
            except:
                logging.debug('Unable to identify imphash')

            imgChars = dump_dict.get('Flags', [])
            scanObject.addMetadata(
                self.module_name, 'Image Characteristics', imgChars)
            # Make a pretty date format
            date = datetime.fromtimestamp(pe.FILE_HEADER.TimeDateStamp)
            isoDate = date.isoformat()
            scanObject.addMetadata(self.module_name, 'Date', isoDate)
            scanObject.addMetadata(
                self.module_name, 'Timestamp', pe.FILE_HEADER.TimeDateStamp)

            machine = pe.FILE_HEADER.Machine
            machineData = {
                'Id': machine,
                'Type': pefile.MACHINE_TYPE.get(machine)
            }
            scanObject.addMetadata(
                self.module_name, 'Machine Type', machineData)

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339%28v=vs.85%29.aspx
            scanObject.addMetadata(
                self.module_name,
                'Image Magic',
                IMAGE_MAGIC_LOOKUP.get(pe.OPTIONAL_HEADER.Magic, 'Unknown'))

            dllChars = dump_dict.get('DllCharacteristics', [])
            scanObject.addMetadata(
                self.module_name, 'DLL Characteristics', dllChars)

            subsystem = pe.OPTIONAL_HEADER.Subsystem
            subName = pefile.SUBSYSTEM_TYPE.get(subsystem)
            scanObject.addMetadata(self.module_name, 'Subsystem', subName)

            # Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648009%28v=vs.85%29.aspx

            scanObject.addMetadata(
                self.module_name,
                'Stack Reserve Size',
                pe.OPTIONAL_HEADER.SizeOfStackReserve)
            scanObject.addMetadata(
                self.module_name,
                'Stack Commit Size',
                pe.OPTIONAL_HEADER.SizeOfStackCommit)
            scanObject.addMetadata(
                self.module_name,
                'Heap Reserve Size',
                pe.OPTIONAL_HEADER.SizeOfHeapReserve)
            scanObject.addMetadata(
                self.module_name,
                'Heap Commit Size',
                pe.OPTIONAL_HEADER.SizeOfHeapCommit)
            scanObject.addMetadata(
                self.module_name,
                'EntryPoint',
                hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint))
            scanObject.addMetadata(
                self.module_name,
                'ImageBase',
                hex(pe.OPTIONAL_HEADER.ImageBase))

            # Parse RSDS & Rich
            scanObject.addMetadata(
                self.module_name, 'Rich Header', self.parseRich(pe))

            if hasattr(pe, 'DIRECTORY_ENTRY_DEBUG'):
                debug = dict()
                for e in pe.DIRECTORY_ENTRY_DEBUG:
                    rawData = pe.get_data(e.struct.AddressOfRawData, e.struct.SizeOfData)
                    if rawData.find('RSDS') != -1 and len(rawData) > 24:
                        pdb = rawData[rawData.find('RSDS'):]
                        debug["guid"] = "%s-%s-%s-%s" % (
                            binascii.hexlify(pdb[4:8]),
                            binascii.hexlify(pdb[8:10]),
                            binascii.hexlify(pdb[10:12]),
                            binascii.hexlify(pdb[12:20]))
                        debug["age"] = struct.unpack('<L', pdb[20:24])[0]
                        debug["pdb"] = pdb[24:].rstrip('\x00')
                        scanObject.addMetadata(self.module_name, 'RSDS', debug)
                    elif rawData.find('NB10') != -1 and len(rawData) > 16:
                        pdb = rawData[rawData.find('NB10')+8:]
                        debug["created"] = datetime.fromtimestamp(struct.unpack('<L', pdb[0:4])[0]).isoformat()
                        debug["age"] = struct.unpack('<L', pdb[4:8])[0]
                        debug["pdb"] = pdb[8:].rstrip('\x00')
                        scanObject.addMetadata(self.module_name, 'NB10', debug)

        except pefile.PEFormatError:
            logging.debug("Invalid PE format")
        return moduleResult