Esempio n. 1
0
def promptAndOutput(outputMessageNum, autogenerateAllClient=False):
    # How many of the messages to output to the .fuzzer
    if args.force or autogenerateAllClient:
        finalMessageNum = len(fuzzerData.messageCollection.messages) - 1
    else:
        finalMessageNum = promptInt(
            "What is the last message number you want output?",
            defaultResponse=len(fuzzerData.messageCollection.messages) - 1)

    # Any messages previously marked for fuzzing, unmark first
    # Inefficient as can be, but who cares
    for message in fuzzerData.messageCollection.messages:
        if message.isFuzzed:
            message.isFuzzed = False
            for subcomponent in message.subcomponents:
                subcomponent.isFuzzed = False

    if not autogenerateAllClient:
        while True:
            tmp = promptString(
                "Which message numbers should be fuzzed? Valid: 0-%d" %
                (finalMessageNum),
                defaultResponse=str(outputMessageNum),
                validateFunc=validateNumberRange)
            if len(tmp) > 0:
                outputFilenameEnd = tmp
                for messageIndex in validateNumberRange(tmp, flattenList=True):
                    fuzzerData.messageCollection.messages[
                        messageIndex].isFuzzed = True
                    for subcomponent in fuzzerData.messageCollection.messages[
                            messageIndex].subcomponents:
                        subcomponent.isFuzzed = True
                break
    else:
        outputFilenameEnd = str(outputMessageNum)
        fuzzerData.messageCollection.messages[outputMessageNum].isFuzzed = True
        for subcomponent in fuzzerData.messageCollection.messages[
                outputMessageNum].subcomponents:
            subcomponent.isFuzzed = True

    outputFilePath = "{0}-{1}.fuzzer".format(
        os.path.splitext(inputFilePath)[0], outputFilenameEnd)
    actualPath = fuzzerData.writeToFile(outputFilePath,
                                        defaultComments=True,
                                        finalMessageNum=finalMessageNum)
    print(GREEN)
    print("Wrote .fuzzer file: {0}".format(actualPath))
    print(CLEAR)

    if autogenerateAllClient:
        nextMessage = getNextMessage(outputMessageNum + 1,
                                     Message.Direction.Outbound)
        # Will return None when we're out of messages to auto-output
        if nextMessage:
            promptAndOutput(nextMessage, autogenerateAllClient=True)
    return finalMessageNum
Esempio n. 2
0
 def setMessagesToFuzzFromString(self, messagesToFuzzStr):
     self.messagesToFuzz = validateNumberRange(messagesToFuzzStr, flattenList=True)
Esempio n. 3
0
            sys.exit("Invalid test range given: %s" % args)
    else:
        # If they pass a non-int, allow this to bomb out
        return (int(strArgs), int(strArgs))


#----------------------------------------------------

#Populate global arguments from parseargs
fuzzerFilePath = args.prepped_fuzz
host = args.target_host
#Assign Lower/Upper bounds on test cases as needed
if args.range:
    (MIN_RUN_NUMBER, MAX_RUN_NUMBER) = getRunNumbersFromArgs(args.range)
elif args.loop:
    SEED_LOOP = validateNumberRange(args.loop, True)

#Check for dependency binaries
if not os.path.exists(RADAMSA):
    sys.exit("Could not find radamsa in %s... did you build it?" % RADAMSA)

#Logging options
isReproduce = False
logAll = False

if args.quiet:
    isReproduce = True
elif args.logAll:
    logAll = True

outputDataFolderPath = os.path.join(
Esempio n. 4
0
 def readFromFD(self, fileDescriptor, quiet=False):
     messageNum = 0
     
     # This is used to track multiline messages
     lastMessage = None
     # Build up comments in this string until we're ready to push them out to the dictionary
     # Basically, we build lines and lines of comments, then when a command is encountered,
     # push them into the dictionary using that command as a key
     # Thus, when we go to write them back out, we can print them all before a given key
     self._readComments = ""
     
     for line in fileDescriptor:
         # Record comments on read so we can play them back on write if applicable
         if line.startswith("#") or line == "\n":
             self._readComments += line
             # Skip all further processing for this line
             continue
         
         line = line.replace("\n", "")
         
         # Skip comments and whitespace
         if not line.startswith("#") and not line == "" and not line.isspace():
             args = line.split(" ")
             
             # Populate FuzzerData obj with any settings we can parse out
             try:
                 if args[0] == "processor_dir":
                     self.processorDirectory = args[1]
                     self._pushComments("processor_dir")
                 elif args[0] == "failureThreshold":
                     self.failureThreshold = int(args[1])
                     self._pushComments("failureThreshold")
                 elif args[0] == "failureTimeout":
                     self.failureTimeout = int(args[1])
                     self._pushComments("failureTimeout")
                 elif args[0] == "proto":
                     self.proto = args[1]
                     self._pushComments("proto")
                 elif args[0] == "port":
                     self.port = int(args[1])
                     self._pushComments("port")
                 elif args[0] == "sourcePort":
                     self.sourcePort = int(args[1])
                     self._pushComments("sourcePort")
                 elif args[0] == "sourceIP":
                     self.sourceIP = args[1]
                     self._pushComments("sourceIP")
                 elif args[0] == "shouldPerformTestRun":
                     # Use 0 or 1 for setting
                     if args[1] == "0":
                         self.shouldPerformTestRun = False
                     elif args[1] == "1":
                         self.shouldPerformTestRun = True
                     else:
                         raise RuntimeError("shouldPerformTestRun must be 0 or 1")
                     self._pushComments("shouldPerformTestRun")
                 elif args[0] == "receiveTimeout":
                     self.receiveTimeout = float(args[1])
                     self._pushComments("receiveTimeout")
                 elif args[0] == "messagesToFuzz":
                     print("WARNING: It looks like you're using a legacy .fuzzer file with messagesToFuzz set.  This is now deprecated, so please update to the new format")
                     self.messagesToFuzz = validateNumberRange(args[1], flattenList=True)
                     # Slight kludge: store comments above messagesToFuzz with the first message.  *shrug*
                     # Comment saving is best effort anyway, right?
                     self._pushComments("message0")
                 elif args[0] == "unfuzzedBytes":
                     print("ERROR: It looks like you're using a legacy .fuzzer file with unfuzzedBytes set.  This has been replaced by the new multi-line format.  Please update your .fuzzer file.")
                     sys.exit(-1)
                 elif args[0] == "inbound" or args[0] == "outbound":
                     message = Message()
                     message.setFromSerialized(line)
                     self.messageCollection.addMessage(message)
                     # Legacy code to handle old messagesToFuzz format
                     if messageNum in self.messagesToFuzz:
                         message.isFuzzed = True
                     if not quiet:
                         print "\tMessage #{0}: {1} bytes {2}".format(messageNum, len(message.getOriginalMessage()), message.direction)
                     self._pushComments("message{0}".format(messageNum))
                     messageNum += 1
                     lastMessage = message
                 # "sub" means this is a subcomponent
                 elif args[0] == "sub":
                     if not 'message' in locals():
                         print "\tERROR: 'sub' line declared before any 'message' lines, throwing subcomponent out: {0}".format(line)
                     else:
                         message.appendFromSerialized(line)
                         if not quiet:
                             print "\t\tSubcomponent: {1} additional bytes".format(messageNum, len(message.subcomponents[-1].message))
                 elif line.lstrip()[0] == "'" and 'message' in locals():
                     # If the line begins with ' and a message line has been found,
                     # assume that this is additional message data
                     # (Different from a subcomponent because it can't have additional data 
                     # tacked on)
                     message.appendFromSerialized(line.lstrip(), createNewSubcomponent=False)
                 else:
                     if not quiet:
                         print "Unknown setting in .fuzzer file: {0}".format(args[0])
                 # Slap any messages between "message" and "sub", etc (ascii same way) above message
                 # It's way too annoying to print these out properly, as they get
                 # automagically outserialized by the Message object
                 # Plus they may change... eh, forget it, user can fix up themselves if they want
                 self._appendComments("message{0}".format(messageNum-1))
             except Exception as e:
                 print "Invalid line: {0}".format(line)
                 raise e
     # Catch any comments below the last line
     self._pushComments("endcomments")
Esempio n. 5
0
    def __init__(self, args):
        self.args = args
        # Test number to start from, 0 default
        self.MIN_RUN_NUMBER = 0
        # Test number to go to, -1 is unlimited
        self.MAX_RUN_NUMBER = -1
        # For seed loop, finite range to repeat
        self.SEED_LOOP = []
        # For dumpraw option, dump into log directory by default, else 'dumpraw'
        self.DUMPDIR = ""

        #Populate global arguments from parseargs
        self.fuzzerFilePath = args.prepped_fuzz
        self.host = args.target_host

        #Assign Lower/Upper bounds on test cases as needed
        if args.range:
            (self.MIN_RUN_NUMBER,
             self.MAX_RUN_NUMBER) = getRunNumbersFromArgs(args, args.range)
        elif args.loop:
            self.SEED_LOOP = validateNumberRange(args.loop, True)

        #Check for dependency binaries
        if not os.path.exists(RADAMSA):
            sys.exit("Could not find radamsa in %s... did you build it?" %
                     RADAMSA)

        #Logging options
        self.isReproduce = False
        self.logAll = False

        if args.quiet:
            self.isReproduce = True
        elif args.logAll:
            self.logAll = True

        self.outputDataFolderPath = os.path.join(
            "%s_%s" % (os.path.splitext(self.fuzzerFilePath)[0], "logs"),
            datetime.datetime.now().strftime("%Y-%m-%d,%H%M%S"))
        self.fuzzerFolder = os.path.abspath(
            os.path.dirname(self.fuzzerFilePath))

        ########## Declare variables for scoping, "None"s will be assigned below
        self.messageProcessor = None

        ###Here we read in the fuzzer file into a dictionary for easier variable propagation
        self.optionDict = {"unfuzzedBytes": {}, "message": []}

        self.fuzzerData = FuzzerData()
        print "Reading in fuzzer data from %s..." % (self.fuzzerFilePath)
        self.fuzzerData.readFromFile(self.fuzzerFilePath)

        #clumsden TODO - make this pretty, maybe add field to fuzzerData
        #clumsden - hacky way to start http fuzzer at a different seed
        if self.fuzzerData.port == 80 and self.fuzzerData.proto == "tcp":
            self.MIN_RUN_NUMBER = 58247530
        if self.fuzzerData.proto == "udp":  #clumsden, set udp fuzzer at different seed
            self.MIN_RUN_NUMBER = 13243441
        #clumsden end

        ######## Processor Setup ################
        # The processor just acts as a container #
        # class that will import custom versions #
        # messageProcessor/exceptionProessor/    #
        # monitor, if they are found in the      #
        # process_dir specified in the .fuzzer   #
        # file generated by fuzz_prep.py         #
        ##########################################

        # Assign options to variables, error on anything that's missing/invalid
        self.processorDirectory = self.fuzzerData.processorDirectory
        if self.processorDirectory == "default":
            # Default to fuzzer file folder
            self.processorDirectory = self.fuzzerFolder
        else:
            # Make sure fuzzer file path is prepended
            self.processorDirectory = os.path.join(self.fuzzerFolder,
                                                   self.processorDirectory)

        #Create class director, which import/overrides processors as appropriate
        self.procDirector = ProcDirector(self.processorDirectory)

        global global_monitor
        self.monitor = None
        ########## Launch child monitor thread
        ### monitor.task = spawned thread
        ### monitor.crashEvent = threading.Event()
        if wantGlobalMonitor == True and global_monitor == None:
            global_monitor = self.procDirector.startMonitor(
                self.host, self.fuzzerData.port)
            print global_monitor
            time.sleep(
                10
            )  #clumsden added so pid_watcher has time to connect to monitor

        #! make it so logging message does not appear if reproducing (i.e. -r x-y cmdline arg is set)
        self.logger = None

        if not self.isReproduce:
            print "Logging to %s" % (self.outputDataFolderPath)
            self.logger = Logger(self.outputDataFolderPath)

        if self.args.dumpraw:
            if not isReproduce:
                self.DUMPDIR = self.outputDataFolderPath
            else:
                self.DUMPDIR = "dumpraw"
                try:
                    os.mkdir("dumpraw")
                except:
                    print "Unable to create dumpraw dir"
                    pass

        self.exceptionProcessor = self.procDirector.exceptionProcessor()
        self.messageProcessor = self.procDirector.messageProcessor()

        ########## Begin fuzzing
        self.i = self.MIN_RUN_NUMBER - 1 if self.fuzzerData.shouldPerformTestRun else self.MIN_RUN_NUMBER
        self.failureCount = 0
        self.loop_len = len(self.SEED_LOOP)  # if --loop