Exemple #1
0
    def symtask(cls, jobitem, symserver, symdest, symlocal):
        '''
        perform symbol search for symbols of jobfile. If there are no symbols or symbols found
        are already in db, discard results. Else, return found symbols
        '''
        symlogger = logging.getLogger("BAM.Pools.SymWkr")
        jobfile = jobitem[0]
        hashes = (jobfile[1], jobfile[2])

        result = None
        logmsg = "[SYMMGR].. Getting SYM for (" + str(jobfile) + ")"
        symlogger.log(logging.DEBUG, logmsg)
        servers = ""

        if symlocal:
            servers = " \""+ symdest + "\""
        else:
            servers = "u \"srv*" + symdest + "*" + symserver +"\""

        args = (".\\tools\\x64\\symchk.exe /v \"" + str(jobfile) + "\" /s" + servers + " /od")

        try:
            with subprocess.Popen(args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) \
                    as psymchk:
                # communicate used as symchk's output is for one file and
                # is not "large or unlimited"
                pstdout, pstderr = psymchk.communicate()
                stdoutsplit = str(pstdout.decode("ascii")).split("\r\n")
                stderrsplit = str(pstderr.decode("ascii")).split("\r\n")

                logmsg = "[SYMMGR] Attempt to obtain symbols for " + str(jobfile) + " complete"
                symlogger.log(logging.DEBUG, logmsg)

                infolist = {}
                try:
                    unpefile = pefile.PE(jobfile)
                except pefile.PEFormatError as peerror:
                    logmsg = "[WSUS_DB] Caught: PE error " + str(peerror) + ". File: " + jobfile
                    symlogger.log(logging.ERROR, logmsg)
                    return result

                infolist['signature'] = getpesigwoage(unpefile)
                infolist['arch'] = getpearch(unpefile)

                unpefile.close()

                stderrsplit.append(symserver)
                result = ((str(jobfile), stderrsplit, stdoutsplit), hashes[0], hashes[1], infolist)
        except subprocess.CalledProcessError as error:
            logmsg = "[SYMMGR] {-} symchk failed with error: " + str(error) + ". File: " + jobfile
            symlogger.log(logging.ERROR, logmsg)
            result = None
        except FileNotFoundError as error:
            logmsg = ("[SYMMGR] {-} symchk.exe not found")
            symlogger.log(logging.ERROR, logmsg)
            result = None

        logmsg = "[SYMMGR] completed symtask for " + str(jobfile)
        symlogger.log(logging.DEBUG, logmsg)
        return result
def ispe(file):
    '''
    checks for valid PE file
    '''
    try:
        petemp = pefile.PE(file, fast_load=False)
        petemp.close()
    except (pefile.PEFormatError, IOError):
        return False
    return True
def ispebuiltwithdebug(pebinary):
    '''
    check to see if PE was built with debug symbols in a pdb file
    '''
    peitem = pefile.PE(pebinary)

    debugsize = peitem.dump_dict()['Directories'][6]['Size']['Value']
    peitem.close()
    if debugsize == 0:
        return False
    return True
def ispedbgstripped(file):
    '''
    checks to see if PE debug information was stripped and placed into dbg file.
    '''
    unknownpefile = pefile.PE(file)

    filehdr = getattr(unknownpefile, "FILE_HEADER", None)
    if filehdr is not None:
        characteristics = getattr(unknownpefile, "Characteristics", None)
        unknownpefile.close()
        if characteristics is not None:
            # https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_image_file_header
            # IMAGE_FILE_DEBUG_STRIPPED
            if (characteristics & 0x0200) == 0x0200:
                return True
    return False
Exemple #5
0
def findbannedapis(file):
    global _pbanlogger

    _pbanlogger.log(
        logging.DEBUG,
        "[PBAN] Working on " + file + " for Banned APIs verification")

    bannedapis = getbannedapis()

    if bannedapis is None:
        logmsg = ("[PBAN] {-} Skipping Banned Analysis.")
        _pbanlogger.log(logging.DEBUG, logmsg)
        return

    basename = os.path.basename(file)

    pe_file = None

    try:
        pe_file = pefile.PE(file)
    except pe_file.PEFormatError as peerror:
        logmsg = (
            "[PBAN] {-} Skipping DB insertion. Issue with handling PE file" +
            str(peerror.value))
        _pbanlogger.log(logging.DEBUG, logmsg)
        return

    hashes = getfilehashes(file)

    if hashes is None:
        _pbanlogger.log(logging.DEBUG,
                        "[PBSK] Error getting hashes for " + file)
        return

    dbcursor = DBCONN2.cursor()

    dbcursor.execute("BEGIN TRANSACTION")

    if hasattr(pe_file, 'DIRECTORY_ENTRY_IMPORT'):
        for module in pe_file.DIRECTORY_ENTRY_IMPORT:
            for importm in module.imports:
                if importm.name is not None and importm.name.decode(
                        'ascii') in bannedapis:
                    mname = module.dll.decode('ascii')
                    fn = importm.name.decode('ascii')

                    try:
                        dbcursor.execute(
                            "INSERT INTO " + "BannedApiFiles" + " VALUES (" +
                            "?," * 5 + "?)",
                            # FileName, SHA256, SHA1, ModuleName, BannedApiUsed
                            (
                                basename,
                                hashes[0],
                                hashes[1],
                                mname,
                                fn,
                                # timestamp
                                str(time())))

                    except sqlite3.Error as error:
                        _pbanlogger.log(logging.DEBUG, (
                            "[PBSK] INSERT ConfigurationNotifications error (incomplete): "
                            + error.args[0]))

    dbcursor.execute("END TRANSACTION")
    _pbanlogger.log(logging.DEBUG, ("[PBAN] Completed " + file))

    dbcursor.close()
Exemple #6
0
    def cleantask(cls, jobfile, updateid):
        '''
        task to clean up folder before submitting jobs for symbol search
        if item is removed in cleaning, None is returned, else return item
        '''
        clnlogger = logging.getLogger("BAM.Pools.ClnWkr")
        
        results = None

        logmsg = "[CLNMGR] Starting on " + str(jobfile)
        clnlogger.log(logging.DEBUG, logmsg)

        if ispe(jobfile):
            # check db to see if job already exists:
            hashes = getfilehashes(jobfile)

            if hashes is None:
                return hashes

            if wsuse_db.dbentryexistwithsymbols(globs.DBCONN.cursor(),     \
                                globs.PATCHEDFILESDBNAME, hashes[0], hashes[1]):
                # if PE is already in db with symbols obtained,
                # do not retask job to symbol manager, return None instead
                return results
            else:
                pass
                logmsg = "[CLNMGR] continuing forward with " + str(jobfile)
                clnlogger.log(logging.DEBUG, logmsg)

            # getting to this point means item is not in db, may need to come up
            # with case where db needs to update item though
            infolist = {
                    'OriginalFilename': '', 'FileDescription': '', 'ProductName': '',
                    'Comments': '', 'CompanyName': '', 'FileVersion': '',
                    'ProductVersion': '', 'IsDebug': '', 'IsPatched': '',
                    'IsPreReleased': '', 'IsPrivateBuild': '', 'IsSpecialBuild': '',
                    'Language': '', 'PrivateBuild': '', 'SpecialBuild': ''
                    }

            try:
                unpefile = pefile.PE(jobfile, fast_load=True)
            except pefile.PEFormatError as peerror:
                logmsg = "[WSUS_DB] skipping " + str(jobfile) + " due to exception: " + peerror.value
                clnlogger.log(logging.ERROR, logmsg)
                return results

            infolist['fileext'], infolist['stype'] = pebinarytype(unpefile)
            infolist['arch'] = getpearch(unpefile)
            infolist['age'] = getpeage(unpefile)
            infolist['strippedpe'] = ispedbgstripped(unpefile)
            infolist['builtwithdbginfo'] = ispebuiltwithdebug(unpefile)            

            direntires=[ pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_DEBUG'],    \
                pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE'] ]
            unpefile.parse_data_directories(directories=direntires)
            infolist['pdbfilename'] = getpepdbfilename(unpefile)
            infolist['signature'] = getpesigwoage(unpefile)

            # a PE only have 1 VERSIONINFO, but multiple language strings
            # More information on different properites can be found at
            # https://msdn.microsoft.com/en-us/library/windows/desktop/aa381058
            # https://msdn.microsoft.com/en-us/library/windows/desktop/aa381049
            if getattr(unpefile, "VS_VERSIONINFO", None) is not None and \
                getattr(unpefile, "FileInfo", None) is not None:
                    for fileinfoentries in unpefile.FileInfo:
                        for fileinfoentry in fileinfoentries:
                            if getattr(fileinfoentry, "StringTable", None) is not None:
                                for strtable in fileinfoentry.StringTable:
                                    # Currently only handling unicode en-us
                                    if strtable.LangID[:4] == b'0409' or \
                                            (strtable.LangID[:4] == b'0000' and
                                            (strtable.LangID[4:] == b'04b0' or
                                            strtable.LangID[4:] == b'04B0')):
                                        infolist["Language"] \
                                            = strtable.LangID.decode("utf-8")
                                        for field, value in strtable.entries.items():
                                            dfield = field.decode('utf-8')
                                            dvalue = value.decode('utf-8')
                                            if dfield == "OriginalFilename":
                                                infolist["OriginalFilename"] \
                                                    = dvalue
                                            if dfield == "FileDescription":
                                                infolist["FileDescription"] \
                                                    = dvalue
                                            if dfield == "ProductName":
                                                infolist["ProductName"] \
                                                    = dvalue
                                            if dfield == "Comments":
                                                infolist["Comments"] \
                                                    = dvalue
                                            if dfield == "CompanyName":
                                                infolist["CompanyName"] \
                                                    = dvalue
                                            if dfield == "FileVersion":
                                                infolist["FileVersion"] \
                                                    = dvalue
                                            if dfield == "ProductVersion":
                                                infolist["ProductVersion"] \
                                                    = dvalue
                                            if dfield == "IsDebug":
                                                infolist["IsDebug"] \
                                                    = dvalue
                                            if dfield == "IsPatched":
                                                infolist["IsPatched"] \
                                                    = dvalue
                                            if dfield == "IsPreReleased":
                                                infolist["IsPreReleased"] \
                                                    = dvalue
                                            if dfield == "IsPrivateBuild":
                                                infolist["IsPrivateBuild"] \
                                                    = dvalue
                                            if dfield == "IsSpecialBuild":
                                                infolist["IsSpecialBuild"] \
                                                    = dvalue
                                            if dfield == "PrivateBuild":
                                                infolist["PrivateBuild"] \
                                                    = dvalue
                                            if dfield == "SpecialBuild":
                                                infolist["SpecialBuild"] \
                                                    = dvalue
            # Get the OS this PE is designed towards.
            # Microsoft PE files distributed via Microsoft's Updates typically
            # use the ProductVersion file properties to indicate the OS a specific
            # PE file is built towards.
            # If this is a Microsoft binary, the Product version is typically
            # the OS version it was built towards, but other products this is not
            # necessarily true
            if infolist['ProductName'].find("Operating System") != -1:
                infolist['osver'] = "NT" + infolist['ProductVersion']
            else:
                infolist['osver'] = "UNKNOWN"

            unpefile.close()

            results = ((str(jobfile), updateid), hashes[0], hashes[1], infolist)
        else:
            # if jobfile is not a PE, then check if it's a cab. If not a cab, remove it.
            if not validatecab(str(jobfile)):
                logmsg = "[CLNMGR] cleantask: Removing " + str(jobfile)
                clnlogger.log(logging.DEBUG, logmsg)

                rmfile(jobfile)

                logmsg = "[CLNMGR] " + str(jobfile) + " removed, not PE or cab file"
                clnlogger.log(logging.DEBUG, logmsg)
            else:
                pass
                logmsg = "[CLNMGR] " + str(jobfile) + " is nested cab, skipping"
                clnlogger.log(logging.DEBUG, logmsg)
            return results

        logmsg = "[CLNMGR] completed one cleantask for " + str(jobfile)
        clnlogger.log(logging.DEBUG, logmsg)

        return results