Esempio n. 1
0
    def change_bytes(self, original, fl):

        if len(self.currentTaintMap) == 0:
            return original

        cmp = self.getOffset(fl, original)

        if len(cmp) == 0:
            gautils.debug_print(
                "[-] Fail to find offset (it could be because of conflict)")
            return original

        cmp = cmp[0]

        gautils.debug_print("[*] Mutation will be on 0x%x" %
                            cmp.offsetsInInput[0])

        return self.change_bytes_from_cmp(original, fl, cmp)
Esempio n. 2
0
    def check_mutation_conflict_from_register_size(self, offset, size, file):
        ''' check if a new mutation will override an old one with the size of the register '''

        conflictList = []

        for mu in self.mutationHistory[file]:

            gautils.debug_print("[*] Checking 0x%x to 0x%x with 0x%x to 0x%x" %
                                (offset, offset + size, mu, mu +
                                 self.mutationHistory[file][mu][0].cmpSize))

            baseOffsetInMutation = offset >= mu and offset <= (
                mu + self.mutationHistory[file][mu][0].cmpSize)
            endOffsetInMutation = offset + size >= mu and offset + size <= (
                mu + self.mutationHistory[file][mu][0].cmpSize)

            if baseOffsetInMutation or endOffsetInMutation:
                conflictList.append(self.mutationHistory[file][mu][0])

        return conflictList
Esempio n. 3
0
    def write_child_input_update(self, name, inputBuffer):

        # compute its hash
        inputHash = hashlib.md5(inputBuffer).hexdigest()

        # check if the child input already exist
        if inputHash not in self.childMap.values():

            # override the file
            path = os.path.join(config.INPUTD, name)
            gautils.writeFile(path, inputBuffer)

            # change its hash in history
            self.childMap[name] = inputHash

            return True
        else:
            gautils.debug_print("[-] Child input %s already exist" %
                                (inputHash))

            return False
Esempio n. 4
0
def detectPatterns(cmpList, fpath):

    # test each patterns for each index ?
    # or test each index of each patterns ????
    # currently I choose each index of each patterns because of end offsets

    patternFound = 0

    for patternDef in patternDefinition:

        for pattern in patternDef.patternList:
                
            index = 0

            # loop through each offset of cmp for a pattern
            while index != len(cmpList):

                endOffset = pattern.executeFromCmpObjects(index, cmpList)

                # check if a pattern is found
                if endOffset != -1:

                    gau.debug_print( "\033[0;32m[+] Found %s (%s) from %d to %d" % (pattern.name, patternDef.name, (index),(endOffset)) + " !\033[0m" )
                    
                    # execute the effect of a found pattern
                    cmpList = patternDef.effect(pattern.name, cmpList, index, endOffset, fpath)

                    # jump to the end of the pattern
                    index = endOffset+1

                    patternFound += 1
                else:
                    index += 1

    if patternFound > 0:
        gau.log_print("\033[0;32m[+] %d pattern found\033[0m" % (patternFound))

    return cmpList
Esempio n. 5
0
def dry_run():

    ''' this function executes the initial test set to determine error handling BBs in the SUT. Such BBs are given zero weights during actual fuzzing.'''

    gau.log_print("[*] Starting dry run")
    tempbad = []
    dfiles = os.listdir(config.INITIALD)

    if len(dfiles) < 3:
        gau.die("[-] Not sufficient initial files")

    for fl in dfiles:
        tfl = os.path.join(config.INITIALD, fl)
        try:
            f = open(tfl, 'r')
            f.close()
        except:
            gau.die("[-] Can not open our own input %s !" % (tfl))
        (bbs, retc) = execute(tfl)
        if retc < 0:
            print "Signal: %d" % (retc,)
            gau.die("[-] Looks like we already got a crash !")
        config.GOODBB |= set(bbs.keys())

    gau.log_print("[*] Finished good inputs (%d BB)" % (len(config.GOODBB),))
    # now lets run SUT of probably invalid files. For that we need to create them first.
    gau.log_print("[*] Starting bad inputs")

    lp = 0
    badbb = set()
    while lp < 2:
        try:
            shutil.rmtree(config.INPUTD)
        except OSError:
            pass

        os.mkdir(config.INPUTD)
        gau.create_files_dry(30)
        dfiles = os.listdir(config.INPUTD)
        for fl in dfiles:
            tfl = os.path.join(config.INPUTD, fl)
            (bbs, retc) = execute(tfl)
            if retc < 0:
                gau.log_print( "Signal: %d" % (retc,))
                gau.die("[-] Looks like we already got a crash !")
            tempbad.append(set(bbs.keys()) - config.GOODBB)

        tempcomn = set(tempbad[0])
        for di in tempbad:
            tempcomn.intersection_update(set(di))
        badbb.update(tempcomn)
        lp += 1

    config.ERRORBBALL = badbb.copy()
    gau.log_print("[*] Finished common basic blocks (%d BB)" % (len(badbb)))

    for ebb in config.ERRORBBALL:
        gau.debug_print( "[-] Error on BB : 0x%x" % (ebb,))

    time.sleep(5)
    if config.LIBNUM == 2:
        baseadr = config.LIBOFFSETS[1]
        for ele in tempcomn:
            if ele < baseadr:
                config.ERRORBBAPP.add(ele)
            else:
                config.ERRORBBLIB.add(ele-baseadr)

    del tempbad
    del badbb
    # del tempgood
    return len(config.GOODBB), len(config.ERRORBBALL)
Esempio n. 6
0
def read_taint(fpath):
    ''' This function read cmp.out file and parses it to extract offsets and coresponding values and returns a tuple(alltaint, dict).
    dictionary: with key as offset and values as a set of hex values checked for that offset in the cmp instruction. Currently, we want to extract values s.t. one of the operands of CMP instruction is imm value for this set of values.
    ADDITION: we also read lea.out file to know offsets that were used in LEA instructions. There offsets are good candidates to fuzz with extreme values, like \xffffffff, \x80000000.
    '''

    #print "--------------------------------------------"

    gau.log_print( "[*] Parsing taint analysis of %s" % ( os.path.basename(fpath) ) )

    exploitableTaintedOffset = dict()

    allTaintedOffsets = dict()

    fsize = os.path.getsize(fpath)

    offlimit = 0

    # check if taint was generated, else exit
    if (os.path.getsize("cmp.out") == 0):
        gau.die("[-] Empty cmp.out file! Perhaps taint analysis did not run")

    cmpFD = open("cmp.out", "r")

    # each line of the cmp.out has the following format:
    # 32 reg imm 0xb640fb9d {155} {155} {155} {155} {} {} {} {} 0xc0 0xff
    # g1 g2 g3     g4        g5    g6    g7    g8  g9 g10 g11 g12 g13 g14
    # we need a regexp to parse this string.
    if config.BIT64 == False:
        pat = re.compile(
            r"(\d+) ([a-z]+) ([a-z]+) (\w+) \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} (\w+) (\w+)", re.I)
    else:
        pat = re.compile(
            r"(\d+) ([a-z]+) ([a-z]+) (\w+) \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} \{([0-9,]*)\} (\w+) (\w+)", re.I)

    cmpO.id = 0

    goodToProcessList = list()
    allTaintedOffsetsList = list()

    if config.FILTERDUPLICATED:
        rawCmpLines = set()
    else:
        rawCmpLines = list()

    cmpoutLineCount = 0

    # remove duplicates
    for line in cmpFD:
        cmpoutLineCount += 1

        if config.FILTERDUPLICATED:

            if line not in rawCmpLines:
                rawCmpLines.add(line)
        else:
            rawCmpLines.append(line)

    cmpFD.close()

    #print "original cmp.out size : " + str(cmpoutLineCount)
    #print "cmp.out after size : " + str(len(rawCmpLines))

    allCmps = list()

    for ln in rawCmpLines:

        if offlimit > config.MAXFILELINE:
            break

        offlimit += 1

        mat = pat.match(ln)

        try:  # this is a check to see if CMP entry is complete.
            if config.BIT64 == False:
                rr = mat.group(14)
            else:
                rr = mat.group(22)
        except:
            continue

        cmp = cmpO.cmpOperation(mat)

        # TODO : if cmp.offset == -1

        # the cmp is not valid or will not be handle
        if len(cmp.offsetsInInput) == 0:
            continue

        # save each valid cmp
        allCmps.append(cmp)

    # detect any pattern in cmp.out
    if config.USEPATTERNDETECTION == True:

        gau.log_print("[*] Running pattern detection for %s" % ( os.path.basename(fpath) ))

        # search and apply patterns
        allCmps = detectPatterns(allCmps, fpath)

    for cmp in allCmps:
        
        # if the cmp is valid and good to be used with taint based changes
        if cmp.isGoodToTaintChanges == True:
            goodToProcessList.append(cmp)

        # if it's just a normal cmp
        else:
            allTaintedOffsetsList.append(cmp)

    gau.debug_print("[*] allTaintedOffsetsList size : %d" % (len(allTaintedOffsetsList)))
    gau.debug_print("[*] goodToProcessList     size : %d" % (len(goodToProcessList)))

    return (allTaintedOffsetsList, goodToProcessList)
Esempio n. 7
0
    def getOffset(self, file, org):

        org = list(org)

        usedFile = file

        if file not in self.currentTaintMap.keys():

            randomFile = self.r.choice(list(self.currentTaintMap.keys()))
            alloffset = self.currentTaintMap[randomFile][0]

            usedFile = randomFile
        else:
            alloffset = self.currentTaintMap[file][0]

        if len(alloffset) == 0:
            gautils.debug_print("[-] Fail to find offset in map")
            return []

        attemps = 10

        cmp = -1

        # I try to optimize the offset selection by selecting only not used offsets
        while attemps != 0:
            cmp = self.r.choice(alloffset)

            if cmp.offsetsInInput[0] in self.mutationHistory[file]:
                attemps -= 1
                continue
            else:
                break

        gautils.debug_print("[*] Testing offset 0x%x" %
                            (cmp.offsetsInInput[0]))

        conflictList = self.check_mutation_conflict_from_register_size(
            cmp.offsetsInInput[0], cmp.cmpSize, file)

        conflictWithParent = False

        createdChild = -1

        # create the mutation buffer
        self.currentMutation = self.r.sample(self.r.choice(self.allStrings),
                                             cmp.cmpSize)

        # is there is not offset without conflicts available
        if len(conflictList) > 0:

            gautils.debug_print("[-] There is conflict with the parent")

            createTheChild = random.uniform(
                0.1, 1.0) > (1.0 - config.CHILDINPUTCREATIONRANDOMNESS)

            # creating a child for each conflict
            if config.HEAVYCHILDINPUTCREATION == True and self.childCount < config.CHILDINPUTMAXSIZE and createTheChild:

                conflictWithParent = True

                # create the input child
                name, inputBuffer = self.create_child_input(
                    file, org, conflictList, cmp)

                # check is exist and write the file
                if not self.write_child_input(name, inputBuffer):
                    del self.mutationHistory[name]
                    createdChild = -1
                else:
                    gautils.debug_print("[+] Child input created %s" % (name))
                    createdChild = name
        else:
            gautils.debug_print("[+] There is no conflict in parent")

        # apply the cmp to the child inputs history
        if len(self.childMap) > 0 and config.HEAVYCHILDINPUTCREATION == True:

            # childMap will change during this
            tmpChildMap = self.childMap.copy()

            for childInput in tmpChildMap:

                if createdChild != -1 and childInput == createdChild:
                    continue

                # get conflicts for each child input
                conflictChildList = self.check_mutation_conflict_from_register_size(
                    cmp.offsetsInInput[0], cmp.cmpSize, childInput)

                path = os.path.join(config.INPUTD, childInput)

                # get child input buffer
                childInputBuffer = list(gautils.readFile(path))

                createTheChild = random.uniform(
                    0.1, 1.0) > (1.0 - config.CHILDINPUTCREATIONRANDOMNESS)

                # conflict found
                # NOTE : we still apply cmp to child inputs if there is no conflicts
                if len(
                        conflictChildList
                ) > 0 and self.childCount < config.CHILDINPUTMAXSIZE and createTheChild:

                    gautils.debug_print(
                        "[-] There is conflict with child inputs")

                    # create input name

                    # get the extension
                    # TODO : find a better way to do it
                    bn, ext = gautils.splitFilename(usedFile)
                    name = "heavy-child-g%d-%d.%s" % (config.CURRENTGEN,
                                                      self.childCount, ext)

                    # create the input child
                    inputBuffer = self.create_new_child_from_old(
                        name, childInput, childInputBuffer, conflictChildList,
                        cmp)

                    # check is exist and write the file
                    if not self.write_child_input(name, ''.join(inputBuffer)):
                        del self.mutationHistory[name]
                    else:
                        gautils.debug_print("[+] Child input created %s" %
                                            (name))

                # no conflict (maybe while self.childCount == config.CHILDINPUTMAXSIZE)
                elif len(conflictChildList) == 0:

                    gautils.debug_print(
                        "[+] There is no conflict in child inputs")
                    gautils.debug_print("[+] Updating child input %s" %
                                        (childInput))

                    # add the new mutation to the history
                    self.mutationHistory[childInput].update(
                        {cmp.offsetsInInput[0]: [cmp]})

                    # apply the changes and add it to history
                    childInputBuffer = self.change_bytes_from_cmp(
                        childInputBuffer, childInput, cmp)

                    # check is exist and write the file
                    if not self.write_child_input_update(
                            childInput, ''.join(childInputBuffer)):
                        del self.mutationHistory[childInput][
                            cmp.offsetsInInput[0]]
                    else:
                        gautils.debug_print("[+] Child input updated %s" %
                                            (childInput))

        # true only if config.HEAVYCHILDINPUTCREATION == True
        if conflictWithParent == True:
            # the parent will not use the mutation because of the conflict
            return []

        else:
            # TODO : improve
            self.mutationHistory[file].update({cmp.offsetsInInput[0]: [cmp]})

            # we will not use this cmp again
            self.currentTaintMap[usedFile][0].remove(cmp)

        # python tricks to not access to cmp function is it None
        return [cmp]
Esempio n. 8
0
    def change_bytes_from_cmp(self, original, fl, cmp):

        if len(self.currentTaintMap) == 0:
            return original

        if self.currentMutation == -1:
            gautils.die("[-] Mutation not created : impossible !")
            return original

        buffer = list(original)

        if cmp.cmpSize == -1:
            #print "change_bytes: cmp.cmpSize == -1"
            return original

        bytesChanged = 0

        mutationHistory = self.mutationHistory[fl][cmp.offsetsInInput[0]]

        if cmp.offsetsInInput[0] in self.mutationHistory[fl] and len(
                mutationHistory) == 1:
            mutationHistory.append(dict())

        mutationHistoryData = mutationHistory[1]

        for offset in cmp.offsetsInInput:

            if offset >= len(buffer):
                continue

            mutationHistoryData.update({offset: []})

            mutationHistoryDataCurrent = mutationHistoryData[offset]

            for i in range(0, cmp.cmpSize):

                currentOffset = int(offset + i)

                if currentOffset >= len(buffer):
                    break

                if cmp.taintType == taintTypeEnum.UNKNOWN:

                    # save the value
                    mutationHistoryDataCurrent.append(buffer[currentOffset])

                    buffer[currentOffset] = self.currentMutation[i]
                    bytesChanged += 1

                elif cmp.taintType == taintTypeEnum.SINGLE_BYTE:

                    # save the value
                    mutationHistoryDataCurrent.append(buffer[currentOffset])

                    buffer[currentOffset] = self.currentMutation[0]
                    bytesChanged += 1

                elif cmp.taintType == taintTypeEnum.ARRAY:

                    # save the value
                    mutationHistoryDataCurrent.append(buffer[currentOffset])

                    # TODO : improve strategy
                    buffer[currentOffset] = self.currentMutation[i]
                    bytesChanged += 1

            gautils.debug_print("[+] Mutation applied 0x%x to 0x%x" %
                                (offset, offset + bytesChanged))

        return ''.join([e for e in buffer])