Ejemplo n.º 1
0
class Fuzzer(object):
    def __init__(self, requester, dictionary, testFailPath="youCannotBeHere7331", threads=1):
        self.requester = requester
        self.dictionary = dictionary
        self.testFailPath = testFailPath
        self.testedPaths = Queue()
        self.basePath = self.requester.basePath
        self.threads = []
        self.threadsCount = threads if len(self.dictionary) >= threads else len(self.dictionary)
        self.running = False
        self.testers = {}

    def wait(self):
        for thread in self.threads:
            thread.join()

    def testersSetup(self):
        if len(self.testers) != 0:
            self.testers = {}
        self.testers["/"] = NotFoundTester(self.requester, "{0}/".format(self.testFailPath))
        for extension in self.dictionary.extensions:
            self.testers[extension] = NotFoundTester(self.requester, "{0}.{1}".format(self.testFailPath, extension))

    def threadsSetup(self):
        if len(self.threads) != 0:
            self.threads = []
        for thread in range(self.threadsCount):
            newThread = threading.Thread(target=self.thread_proc)
            newThread.daemon = True
            self.threads.append(newThread)

    def getTester(self, path):
        for extension in list(self.testers.keys()):
            if path.endswith(extension):
                return self.testers[extension]
        # By default, returns folder tester
        return self.testers["/"]

    def start(self):
        # Setting up testers
        self.testersSetup()
        # Setting up threads
        self.threadsSetup()
        self.index = 0
        self.dictionary.reset()
        self.runningThreadsCount = len(self.threads)
        self.running = True
        self.playEvent = threading.Event()
        self.pausedSemaphore = threading.Semaphore(0)
        self.playEvent.clear()
        self.exit = False
        for thread in self.threads:
            thread.start()
        self.play()

    def play(self):
        self.playEvent.set()

    def pause(self):
        self.playEvent.clear()
        for thread in self.threads:
            if thread.is_alive():
                self.pausedSemaphore.acquire()

    def stop(self):
        self.running = False
        self.play()

    def testPath(self, path):
        response = self.requester.request(path)
        result = 0
        if self.getTester(path).test(response):
            result = 0 if response.status == 404 else response.status
        return result, response

    def isRunning(self):
        return self.running

    def finishThreads(self):
        self.running = False
        self.finishedEvent.set()

    def getPath(self):
        path = None
        if not self.empty():
            path = self.testedPaths.get()
        if not self.isFinished():
            path = self.testedPaths.get()
        return path

    def qsize(self):
        return self.testedPaths.qsize()

    def empty(self):
        return self.testedPaths.empty()

    def isFinished(self):
        return self.runningThreadsCount == 0

    def stopThread(self):
        self.runningThreadsCount -= 1
        if self.runningThreadsCount is 0:
            self.testedPaths.put(None)

    def thread_proc(self):

        self.playEvent.wait()
        try:
            path = next(self.dictionary)
            while path is not None:
                try:
                    status, response = self.testPath(path)
                    self.testedPaths.put(Path(path=path, status=status, response=response))
                except RequestException as e:
                    print("\nUnexpected error:\n{0}\n".format(e.args[0]["message"]))
                    sys.stdout.flush()
                    continue
                finally:
                    if not self.playEvent.isSet():
                        self.pausedSemaphore.release()
                        self.playEvent.wait()
                    path = next(self.dictionary)  # Raises StopIteration when finishes
                    if not self.running:
                        break
        except StopIteration:
            return
        finally:
            self.stopThread()
Ejemplo n.º 2
0
class Fuzzer(object):
    def __init__(self,
                 requester,
                 dictionary,
                 testFailPath="youCannotBeHere7331",
                 threads=1):
        self.requester = requester
        self.dictionary = dictionary
        self.testFailPath = testFailPath
        self.testedPaths = Queue()
        self.basePath = self.requester.basePath
        self.threads = []
        self.threadsCount = threads if len(
            self.dictionary) >= threads else len(self.dictionary)
        self.running = False
        self.testers = {}

    def wait(self):
        for thread in self.threads:
            thread.join()

    def testersSetup(self):
        if len(self.testers) != 0:
            self.testers = {}
        self.testers['/'] = NotFoundTester(self.requester,
                                           '{0}/'.format(self.testFailPath))
        for extension in self.dictionary.extensions:
            self.testers[extension] = NotFoundTester(
                self.requester, '{0}.{1}'.format(self.testFailPath, extension))

    def threadsSetup(self):
        if len(self.threads) != 0:
            self.threads = []
        for thread in range(self.threadsCount):
            newThread = threading.Thread(target=self.thread_proc)
            newThread.daemon = True
            self.threads.append(newThread)

    def getTester(self, path):
        for extension in list(self.testers.keys()):
            if path.endswith(extension):
                return self.testers[extension]
        # By default, returns folder tester
        return self.testers['/']

    def start(self):
        # Setting up testers
        self.testersSetup()
        # Setting up threads
        self.threadsSetup()
        self.index = 0
        self.dictionary.reset()
        self.runningThreadsCount = len(self.threads)
        self.running = True
        self.playEvent = threading.Event()
        self.pausedSemaphore = threading.Semaphore(0)
        self.playEvent.clear()
        self.exit = False
        for thread in self.threads:
            thread.start()
        self.play()

    def play(self):
        self.playEvent.set()

    def pause(self):
        self.playEvent.clear()
        for thread in self.threads:
            if thread.is_alive():
                self.pausedSemaphore.acquire()

    def stop(self):
        self.running = False
        self.play()

    def testPath(self, path):
        response = self.requester.request(path)
        result = 0
        if self.getTester(path).test(response):
            result = (0 if response.status == 404 else response.status)
        return result, response

    def isRunning(self):
        return self.running

    def finishThreads(self):
        self.running = False
        self.finishedEvent.set()

    def getPath(self):
        path = None
        if not self.empty():
            path = self.testedPaths.get()
        if not self.isFinished():
            path = self.testedPaths.get()
        return path

    def qsize(self):
        return self.testedPaths.qsize()

    def empty(self):
        return self.testedPaths.empty()

    def isFinished(self):
        return self.runningThreadsCount == 0

    def stopThread(self):
        self.runningThreadsCount -= 1
        if self.runningThreadsCount is 0:
            self.testedPaths.put(None)

    def thread_proc(self):

        self.playEvent.wait()
        try:
            path = next(self.dictionary)
            while path is not None:
                try:
                    status, response = self.testPath(path)
                    self.testedPaths.put(
                        Path(path=path, status=status, response=response))
                except RequestException as e:
                    print('\nUnexpected error:\n{0}\n'.format(
                        e.args[0]['message']))
                    sys.stdout.flush()
                    continue
                finally:
                    if not self.playEvent.isSet():
                        self.pausedSemaphore.release()
                        self.playEvent.wait()
                    path = next(
                        self.dictionary)  # Raises StopIteration when finishes
                    if not self.running:
                        break
        except StopIteration:
            return
        finally:
            self.stopThread()
Ejemplo n.º 3
0
class Controller(object):

    def __init__(self, script_path, arguments, output):
        self.script_path = script_path
        self.exit = False
        self.arguments = arguments
        self.output = output
        self.blacklists = self.getBlacklists()
        self.fuzzer = None
        self.recursive = self.arguments.recursive
        self.excludeStatusCodes = self.arguments.excludeStatusCodes
        self.recursive = self.arguments.recursive
        self.directories = Queue()
        self.excludeSubdirs = (arguments.excludeSubdirs if arguments.excludeSubdirs is not None else [])
        self.output.printHeader(PROGRAM_BANNER)
        self.dictionary = FuzzerDictionary(self.arguments.wordlist, self.arguments.extensions,
                self.arguments.lowercase)
        self.printConfig()
        try:
            for url in self.arguments.urlList:
                try:
                    self.currentUrl = url
                    self.reportManager = ReportManager()
                    self.requester = Requester(url, cookie=self.arguments.cookie,
                                               useragent=self.arguments.useragent, maxPool=self.arguments.threadsCount,
                                               maxRetries=self.arguments.maxRetries, timeout=self.arguments.timeout,
                                               ip=self.arguments.ip, proxy=self.arguments.proxy,
                                               redirect=self.arguments.redirect)
                    for key, value in arguments.headers.items():
                        self.requester.setHeader(key, value)
                    # Initialize directories Queue with start Path
                    self.basePath = self.requester.basePath
                    if self.arguments.scanSubdirs is not None:
                        for subdir in self.arguments.scanSubdirs:
                            self.directories.put(subdir)
                    else:
                        self.directories.put('')
                    self.setupReports(self.requester)

                    self.output.printTarget(self.currentUrl)
                    self.fuzzer = Fuzzer(self.requester, self.dictionary, testFailPath=self.arguments.testFailPath,
                                         threads=self.arguments.threadsCount)
                    self.wait()
                except SkipTargetInterrupt:
                    continue
        except RequestException as e:
            self.output.printError('Unexpected error:\n{0}'.format(e.args[0]['message']))
            exit(0)
        except KeyboardInterrupt as SystemExit:
            self.output.printError('\nCanceled by the user')
            exit(0)
        finally:
            self.reportManager.save()
            self.reportManager.close()
        self.output.printWarning('\nTask Completed')

    def printConfig(self):
        self.output.printConfig( ', '.join(self.arguments.extensions), str(self.arguments.threadsCount),
                                str(len(self.dictionary)))

    def getBlacklists(self):
        blacklists = {}
        for status in [400, 403, 500]:
            blacklistFileName = FileUtils.buildPath(self.script_path, 'db')
            blacklistFileName = FileUtils.buildPath(blacklistFileName, '{0}_blacklist.txt'.format(status))
            if not FileUtils.canRead(blacklistFileName):
                continue
            blacklists[status] = []
            for line in FileUtils.getLines(blacklistFileName):
                # Skip comments
                if line.startswith('#'):
                    continue
                blacklists[status].append(line)
        return blacklists

    def setupReports(self, requester):
        if self.arguments.autoSave:
            basePath = ('/' if requester.basePath is '' else requester.basePath)
            basePath = basePath.replace(os.path.sep, '.')[1:-1]
            fileName = ('{0}_'.format(basePath) if basePath is not '' else '')
            fileName += time.strftime('%y-%m-%d_%H-%M-%S.txt')
            directoryName = '{0}'.format(requester.host)
            directoryPath = FileUtils.buildPath(self.script_path, 'reports', directoryName)
            outputFile = FileUtils.buildPath(directoryPath, fileName)
            if not FileUtils.exists(directoryPath):
                FileUtils.createDirectory(directoryPath)
                if not FileUtils.exists(directoryPath):
                    self.output.printError("Couldn't create reports folder {0}".format(directoryPath))
                    sys.exit(1)
            if FileUtils.canWrite(directoryPath):
                report = None
                if self.arguments.autoSaveFormat == 'simple':
                    report = SimpleReport(requester.host, requester.port, requester.protocol, requester.basePath,
                                          outputFile)
                if self.arguments.autoSaveFormat == 'json':
                    report = JSONReport(requester.host, requester.port, requester.protocol, requester.basePath,
                                        outputFile)
                else:
                    report = PlainTextReport(requester.host, requester.port, requester.protocol, requester.basePath,
                                             outputFile)
                self.reportManager.addOutput(report)
            else:
                self.output.printError("Can't write reports to {0}".format(directoryPath))
                sys.exit(1)
        if self.arguments.simpleOutputFile is not None:
            self.reportManager.addOutput(SimpleReport(requester.host, requester.port, requester.protocol,
                                         requester.basePath, self.arguments.simpleOutputFile))
        if self.arguments.plainTextOutputFile is not None:
            self.reportManager.addOutput(PlainTextReport(requester.host, requester.port, requester.protocol,
                                         requester.basePath, self.arguments.plainTextOutputFile))
        if self.arguments.jsonOutputFile is not None:
            self.reportManager.addOutput(JSONReport(requester.host, requester.port, requester.protocol,
                                         requester.basePath, self.arguments.jsonOutputFile))

    def handleInterrupt(self):
        self.output.printWarning('CTRL+C detected: Pausing threads, please wait...')
        self.fuzzer.pause()
        try:
            while True:
                msg = "[e]xit / [c]ontinue"
                if not self.directories.empty():
                    msg += " / [n]ext"
                if len(self.arguments.urlList) > 1:
                    msg += " / [s]kip target"
                self.output.printInLine(msg + ': ')
                    
                option = input()
                if option.lower() == 'e':
                    self.exit = True
                    self.fuzzer.stop()
                    raise KeyboardInterrupt
                elif option.lower() == 'c':
                    self.fuzzer.play()
                    return
                elif not self.directories.empty() and option.lower() == 'n':
                    self.fuzzer.stop()
                    return
                elif len(self.arguments.urlList) > 1 and option.lower() == 's':
                    raise SkipTargetInterrupt
                else:
                    continue
        except KeyboardInterrupt as SystemExit:
            self.exit = True
            raise KeyboardInterrupt

    def processPaths(self):
        try:
            path = self.fuzzer.getPath()
            while path is not None:
                try:
                    if path.status is not 0:
                        if path.status not in self.excludeStatusCodes and (self.blacklists.get(path.status) is None
                                or path.path not in self.blacklists.get(path.status)):
                            self.output.printStatusReport(path.path, path.response)
                            self.addDirectory(path.path)
                            self.reportManager.addPath(self.currentDirectory + path.path, path.status, path.response)
                    self.index += 1
                    self.output.printLastPathEntry(path, self.index, len(self.dictionary))
                    path = self.fuzzer.getPath()
                except (KeyboardInterrupt, SystemExit) as e:
                    self.handleInterrupt()
                    if self.exit:
                        raise e
                    else:
                        pass
        except (KeyboardInterrupt, SystemExit) as e:
            if self.exit:
                raise e
            self.handleInterrupt()
            if self.exit:
                raise e
            else:
                pass
        self.fuzzer.wait()

    def wait(self):
        while not self.directories.empty():
            self.index = 0
            self.currentDirectory = self.directories.get()
            self.output.printWarning('[{1}] Starting: {0}'.format(self.currentDirectory, time.strftime('%H:%M:%S')))
            self.fuzzer.requester.basePath = '{0}{1}'.format(self.basePath, self.currentDirectory)
            self.output.basePath = '{0}{1}'.format(self.basePath, self.currentDirectory)
            self.fuzzer.start()
            self.processPaths()
        return

    def addDirectory(self, path):
        if self.recursive == False:
            return False
        if path.endswith('/'):
            if path in [directory + '/' for directory in self.excludeSubdirs]:
                return False
            if self.currentDirectory == '':
                self.directories.put(path)
            else:
                self.directories.put('{0}{1}'.format(self.currentDirectory, path))
            return True
        else:
            return False


    MAYOR_VERSION = 0
    MINOR_VERSION = 3
    REVISION = 0
    global PROGRAM_BANNER
    PROGRAM_BANNER = \
r"""         __           
 _|. _ _  _) _  _ _|_    v{0}.{1}.{2}
(_||| _) __)(_|| (_| )
""".format(MAYOR_VERSION, MINOR_VERSION, REVISION)
Ejemplo n.º 4
0
class Controller(object):
    def __init__(self, script_path, arguments, output):
        self.script_path = script_path
        self.exit = False
        self.arguments = arguments
        self.output = output
        self.blacklists = self.getBlacklists()
        self.fuzzer = None
        self.recursive = self.arguments.recursive
        self.excludeStatusCodes = self.arguments.excludeStatusCodes
        self.recursive = self.arguments.recursive
        self.directories = Queue()
        self.excludeSubdirs = (arguments.excludeSubdirs
                               if arguments.excludeSubdirs is not None else [])
        self.output.printHeader(PROGRAM_BANNER)
        self.dictionary = FuzzerDictionary(self.arguments.wordlist,
                                           self.arguments.extensions,
                                           self.arguments.lowercase)
        self.printConfig()
        try:
            for url in self.arguments.urlList:
                try:
                    self.currentUrl = url
                    self.reportManager = ReportManager()
                    self.requester = Requester(
                        url,
                        cookie=self.arguments.cookie,
                        useragent=self.arguments.useragent,
                        maxPool=self.arguments.threadsCount,
                        maxRetries=self.arguments.maxRetries,
                        timeout=self.arguments.timeout,
                        ip=self.arguments.ip,
                        proxy=self.arguments.proxy,
                        redirect=self.arguments.redirect)
                    for key, value in arguments.headers.items():
                        self.requester.setHeader(key, value)
                    # Initialize directories Queue with start Path
                    self.basePath = self.requester.basePath
                    if self.arguments.scanSubdirs is not None:
                        for subdir in self.arguments.scanSubdirs:
                            self.directories.put(subdir)
                    else:
                        self.directories.put('')
                    self.setupReports(self.requester)

                    self.output.printTarget(self.currentUrl)
                    self.fuzzer = Fuzzer(
                        self.requester,
                        self.dictionary,
                        testFailPath=self.arguments.testFailPath,
                        threads=self.arguments.threadsCount)
                    self.wait()
                except SkipTargetInterrupt:
                    continue
        except RequestException as e:
            self.output.printError('Unexpected error:\n{0}'.format(
                e.args[0]['message']))
            exit(0)
        except KeyboardInterrupt as SystemExit:
            self.output.printError('\nCanceled by the user')
            exit(0)
        finally:
            self.reportManager.save()
            self.reportManager.close()
        self.output.printWarning('\nTask Completed')

    def printConfig(self):
        self.output.printConfig(', '.join(self.arguments.extensions),
                                str(self.arguments.threadsCount),
                                str(len(self.dictionary)))

    def getBlacklists(self):
        blacklists = {}
        for status in [400, 403, 500]:
            blacklistFileName = FileUtils.buildPath(self.script_path, 'db')
            blacklistFileName = FileUtils.buildPath(
                blacklistFileName, '{0}_blacklist.txt'.format(status))
            if not FileUtils.canRead(blacklistFileName):
                continue
            blacklists[status] = []
            for line in FileUtils.getLines(blacklistFileName):
                # Skip comments
                if line.startswith('#'):
                    continue
                blacklists[status].append(line)
        return blacklists

    def setupReports(self, requester):
        if self.arguments.autoSave:
            basePath = ('/'
                        if requester.basePath is '' else requester.basePath)
            basePath = basePath.replace(os.path.sep, '.')[1:-1]
            fileName = ('{0}_'.format(basePath) if basePath is not '' else '')
            fileName += time.strftime('%y-%m-%d_%H-%M-%S.txt')
            directoryName = '{0}'.format(requester.host)
            directoryPath = FileUtils.buildPath(self.script_path, 'reports',
                                                directoryName)
            outputFile = FileUtils.buildPath(directoryPath, fileName)
            if not FileUtils.exists(directoryPath):
                FileUtils.createDirectory(directoryPath)
                if not FileUtils.exists(directoryPath):
                    self.output.printError(
                        "Couldn't create reports folder {0}".format(
                            directoryPath))
                    sys.exit(1)
            if FileUtils.canWrite(directoryPath):
                report = None
                if self.arguments.autoSaveFormat == 'simple':
                    report = SimpleReport(requester.host, requester.port,
                                          requester.protocol,
                                          requester.basePath, outputFile)
                if self.arguments.autoSaveFormat == 'json':
                    report = JSONReport(requester.host, requester.port,
                                        requester.protocol, requester.basePath,
                                        outputFile)
                else:
                    report = PlainTextReport(requester.host, requester.port,
                                             requester.protocol,
                                             requester.basePath, outputFile)
                self.reportManager.addOutput(report)
            else:
                self.output.printError(
                    "Can't write reports to {0}".format(directoryPath))
                sys.exit(1)
        if self.arguments.simpleOutputFile is not None:
            self.reportManager.addOutput(
                SimpleReport(requester.host, requester.port,
                             requester.protocol, requester.basePath,
                             self.arguments.simpleOutputFile))
        if self.arguments.plainTextOutputFile is not None:
            self.reportManager.addOutput(
                PlainTextReport(requester.host, requester.port,
                                requester.protocol, requester.basePath,
                                self.arguments.plainTextOutputFile))
        if self.arguments.jsonOutputFile is not None:
            self.reportManager.addOutput(
                JSONReport(requester.host, requester.port, requester.protocol,
                           requester.basePath, self.arguments.jsonOutputFile))

    def handleInterrupt(self):
        self.output.printWarning(
            'CTRL+C detected: Pausing threads, please wait...')
        self.fuzzer.pause()
        try:
            while True:
                msg = "[e]xit / [c]ontinue"
                if not self.directories.empty():
                    msg += " / [n]ext"
                if len(self.arguments.urlList) > 1:
                    msg += " / [s]kip target"
                self.output.printInLine(msg + ': ')

                option = input()
                if option.lower() == 'e':
                    self.exit = True
                    self.fuzzer.stop()
                    raise KeyboardInterrupt
                elif option.lower() == 'c':
                    self.fuzzer.play()
                    return
                elif not self.directories.empty() and option.lower() == 'n':
                    self.fuzzer.stop()
                    return
                elif len(self.arguments.urlList) > 1 and option.lower() == 's':
                    raise SkipTargetInterrupt
                else:
                    continue
        except KeyboardInterrupt as SystemExit:
            self.exit = True
            raise KeyboardInterrupt

    def processPaths(self):
        try:
            path = self.fuzzer.getPath()
            while path is not None:
                try:
                    if path.status is not 0:
                        if path.status not in self.excludeStatusCodes and (
                                self.blacklists.get(path.status) is None
                                or path.path not in self.blacklists.get(
                                    path.status)):
                            self.output.printStatusReport(
                                path.path, path.response)
                            self.addDirectory(path.path)
                            self.reportManager.addPath(
                                self.currentDirectory + path.path, path.status,
                                path.response)
                    self.index += 1
                    self.output.printLastPathEntry(path, self.index,
                                                   len(self.dictionary))
                    path = self.fuzzer.getPath()
                except (KeyboardInterrupt, SystemExit) as e:
                    self.handleInterrupt()
                    if self.exit:
                        raise e
                    else:
                        pass
        except (KeyboardInterrupt, SystemExit) as e:
            if self.exit:
                raise e
            self.handleInterrupt()
            if self.exit:
                raise e
            else:
                pass
        self.fuzzer.wait()

    def wait(self):
        while not self.directories.empty():
            self.index = 0
            self.currentDirectory = self.directories.get()
            self.output.printWarning('[{1}] Starting: {0}'.format(
                self.currentDirectory, time.strftime('%H:%M:%S')))
            self.fuzzer.requester.basePath = '{0}{1}'.format(
                self.basePath, self.currentDirectory)
            self.output.basePath = '{0}{1}'.format(self.basePath,
                                                   self.currentDirectory)
            self.fuzzer.start()
            self.processPaths()
        return

    def addDirectory(self, path):
        if self.recursive == False:
            return False
        if path.endswith('/'):
            if path in [directory + '/' for directory in self.excludeSubdirs]:
                return False
            if self.currentDirectory == '':
                self.directories.put(path)
            else:
                self.directories.put('{0}{1}'.format(self.currentDirectory,
                                                     path))
            return True
        else:
            return False

    MAYOR_VERSION = 0
    MINOR_VERSION = 3
    REVISION = 0
    global PROGRAM_BANNER
    PROGRAM_BANNER = \
r"""         __           
 _|. _ _  _) _  _ _|_    v{0}.{1}.{2}
(_||| _) __)(_|| (_| )
""".format(MAYOR_VERSION, MINOR_VERSION, REVISION)