PenetrationTestingScripts/dirs3arch/lib/controller/Controller.py

226 lines
10 KiB
Python

# -*- coding: utf-8 -*-
import configparser
import os
import sys
import time
from lib.utils import *
from lib.core import *
from lib.reports import *
from lib.utils import *
from lib.utils.Queue import Queue
import time
class SkipTargetInterrupt(Exception):
pass
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)