167 lines
5.1 KiB
Python
167 lines
5.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
# MA 02110-1301, USA.
|
|
#
|
|
# Author: Mauro Soria
|
|
|
|
import threading
|
|
import logging
|
|
import sys
|
|
import signal
|
|
from lib.utils.Queue import Queue
|
|
from .Path import *
|
|
from lib.connection import *
|
|
from .FuzzerDictionary import *
|
|
from .NotFoundTester import *
|
|
from .ReportManager import *
|
|
from lib.reports import *
|
|
import threading
|
|
import time
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|