Beispiel #1
0
    def parseConfig(self):
        config = DefaultConfigParser()
        configPath = FileUtils.buildPath(self.script_path, "default.conf")
        config.read(configPath)

        # General
        self.threadsCount = config.safe_getint("general", "threads", 10, list(range(1, 50)))
        self.excludeStatusCodes = config.safe_get("general", "exclude-status", None)
        self.redirect = config.safe_getboolean("general", "follow-redirects", False)
        self.recursive = config.safe_getboolean("general", "recursive", False)
        self.recursive_level_max = config.safe_getint("general", "recursive-level-max", 1)
        self.suppressEmpty = config.safe_getboolean("general", "suppress-empty", False)
        self.testFailPath = config.safe_get("general", "scanner-fail-path", "").strip()
        self.saveHome = config.safe_getboolean("general", "save-logs-home", False)

        # Reports
        self.autoSave = config.safe_getboolean("reports", "autosave-report", False)
        self.autoSaveFormat = config.safe_get("reports", "autosave-report-format", "plain", ["plain", "json", "simple"])
        # Dictionary
        self.wordlist = config.safe_get("dictionary", "wordlist",
                                        FileUtils.buildPath(self.script_path, "db", "dicc.txt"))
        self.lowercase = config.safe_getboolean("dictionary", "lowercase", False)
        self.forceExtensions = config.safe_get("dictionary", "force-extensions", False)

        # Connection
        self.useRandomAgents = config.safe_get("connection", "random-user-agents", False)
        self.useragent = config.safe_get("connection", "user-agent", None)
        self.delay = config.safe_get("connection", "delay", 0)
        self.timeout = config.safe_getint("connection", "timeout", 30)
        self.maxRetries = config.safe_getint("connection", "max-retries", 5)
        self.proxy = config.safe_get("connection", "http-proxy", None)
        self.httpmethod = config.safe_get("connection", "httpmethod", "get", ["get", "head", "post"])
        self.requestByHostname = config.safe_get("connection", "request-by-hostname", False)
Beispiel #2
0
    def parseConfig(self):
        config = DefaultConfigParser()
        configPath = FileUtils.buildPath(self.script_path, "default.conf")
        config.read(configPath)

        # General
        self.threadsCount = config.safe_getint("general", "threads", 10,
                                               list(range(1, 50)))
        self.excludeStatusCodes = config.safe_get("general", "exclude-status",
                                                  None)
        self.redirect = config.safe_getboolean("general", "follow-redirects",
                                               False)
        self.recursive = config.safe_getboolean("general", "recursive", False)
        self.testFailPath = config.safe_get("general", "scanner-fail-path",
                                            "").strip()
        self.saveHome = config.safe_getboolean("general", "save-logs-home",
                                               False)

        # Reports
        self.autoSave = config.safe_getboolean("reports", "autosave-report",
                                               False)
        self.autoSaveFormat = config.safe_get("reports",
                                              "autosave-report-format",
                                              "plain",
                                              ["plain", "json", "simple"])
        # Dictionary
        self.wordlist = config.safe_get(
            "dictionary", "wordlist",
            FileUtils.buildPath(self.script_path, "db", "dicc.txt"))
        self.lowercase = config.safe_getboolean("dictionary", "lowercase",
                                                False)
        self.forceExtensions = config.safe_get("dictionary",
                                               "force-extensions", False)

        # Connection
        self.useRandomAgents = config.safe_get("connection",
                                               "random-user-agents", False)
        self.useragent = config.safe_get("connection", "user-agent", None)
        self.timeout = config.safe_getint("connection", "timeout", 30)
        self.maxRetries = config.safe_getint("connection", "max-retries", 5)
        self.proxy = config.safe_get("connection", "http-proxy", None)
Beispiel #3
0
    def __check_args_attack_bruteforce(self):
        """Check arguments for subcommand Attack > Bruteforce options"""

        #for f in self.args.userlist, self.args.passlist, self.args.weblist:
        for f in self.args.userlist, self.args.passlist:
            if f:
                if not FileUtils.can_read(f):
                    logger.error('File {file} does not exist or cannot be read'.format(
                        file=f))
                    return False

        return True
Beispiel #4
0
    def createToolDirectory(self, output):
        """
		Create the tool directory if necessary

		@Args		output: 	CLIOutput instance
		@Returns	Boolean indicating operation status
		"""
        if FileUtils.is_dir(self.tool_dir):
            output.printInfo('Directory "{0}" already exists'.format(
                self.tool_dir))
            return True

        try:
            FileUtils.create_directory(self.tool_dir)
        except Exception as e:
            output.printError(
                'Unable to create new directory "{0}": {1}'.format(
                    self.tool_dir, e))
            return False
        output.printInfo('New directory "{0}" created'.format(self.tool_dir))
        return True
Beispiel #5
0
    def __parse_all_conf_files(self, files):
        """
        Parse all configuration files into the settings directory.
        Initialize ServicesConfig object with list of supported services.

        :param list files: List of files in settings directory
        """
        services = list()
        for f in files:
            name = FileUtils.remove_ext(f).lower().strip()
            if name not in (INSTALL_STATUS_CONF_FILE, TOOLBOX_CONF_FILE,
                            ATTACK_PROFILES_CONF_FILE):
                services.append(name)

            full_path = FileUtils.concat_path(SETTINGS_DIR, f)
            self.config_parsers[name] = DefaultConfigParser()
            # Utf8 to avoid encoding issues
            self.config_parsers[name].read(full_path, 'utf8')

        services.append('multi')  # Add support for special "multi" service
        self.services = ServicesConfig(services)
Beispiel #6
0
    def parseConfig(self):
        config = DefaultConfigParser()
        configPath = FileUtils.buildPath(self.script_path, "default.conf")
        config.read(configPath)

        # General
        self.threadsCount = config.safe_getint("general", "threads", 10, range(1, 50))
        self.excludeStatusCodes = config.safe_get("general", "exclude-status", None)
        self.redirect  = config.safe_getboolean("general", "follow-redirects", False)
        self.recursive = config.safe_getboolean("general", "recursive", False)
        self.testFailPath = config.safe_get("general", "test-fail-path", "youCannotBeHere7331").strip()
        # Reports
        self.autoSave = config.safe_getboolean("reports", "autosave-report", False)
        self.autoSaveFormat = config.safe_get("reports", "autosave-report-format", "plain", ["plain", "json", "simple"])
        # Dictionary
        self.wordlist = config.safe_get("dictionary", "wordlist", FileUtils.buildPath(self.script_path, "db", "dicc.txt"))
        self.lowercase = config.safe_getboolean("dictionary", "lowercase", False)
        # Connection
        self.useragent = config.safe_get("connection", "user-agent", None)
        self.timeout = config.safe_getint("connection", "timeout", 30)
        self.maxRetries = config.safe_getint("connection", "max-retries", 5)
        self.proxy = config.safe_get("connection", "http-proxy", None)
Beispiel #7
0
    def __create_tool_dir(self):
        """
        Create the tool directory if necessary.

        :return: Status
        :rtype: bool
        """
        if self.tool_dir:
            if FileUtils.is_dir(self.tool_dir):
                logger.info('Directory "{dir}" already exists'.format(dir=self.tool_dir))
                return True

            try:
                FileUtils.create_directory(self.tool_dir)
            except Exception as e:
                logger.error('Unable to create new directory "{dir}": {exc}'.format(
                    dir=self.tool_dir, exc=e))
                return False
            logger.info('New directory "{dir}" created'.format(dir=self.tool_dir))
            return True
        else:
            return False
Beispiel #8
0
    def checkInstall(self, output):
        """
		Check if the tool is correctly installed.
		Basically, it runs the installed tool without any option
		@Args		output: 	CLIOutput instance
		@Returns	Boolean indicating status
		"""

        # Directory where the tool should be installed
        if not FileUtils.is_dir(self.tool_dir):
            output.printFail(
                'Directory where the tool should be installed (\'{0}\') does not exist !'
                .self.tool_dir)
            return False

        # Try to run the tool
        output.printInfo('Trying to run the tool {0}...'.format(self.name))
        splitted = self.command.strip().split(' ')

        cmd = ''
        if splitted[0].lower() == 'sudo' and len(splitted) > 1:
            cmd = 'sudo '
            splitted = splitted[1:]
        cmd += splitted[0]

        if splitted[0].lower() in ('python', 'python3', 'perl',
                                   'ruby') and len(splitted) > 1:
            if splitted[1] != '-m':
                cmd += ' {0}'.format(splitted[1])
            elif len(splitted) > 2:
                cmd += ' -m {0}'.format(splitted[2])

        elif splitted[0].lower() == 'java' and len(splitted) > 2:
            if splitted[1].lower() == '-jar':
                cmd += ' -jar {0}'.format(splitted[2])

        c = Command(self.tool_dir, cmd, None, self.toolbox_dir, None, None,
                    None, None)
        cmd_check = c.getStandardCommandLine()
        cmd_check_print = cmd_check[cmd_check.index(';') + 1:].strip()

        output.printBeginCmd(cmd_check_print)
        process = ProcessLauncher(cmd_check, output, None)
        process.start()
        output.printEndCmd()

        # Prompt
        output.printPrompt(
            'Does the tool {0} seem to be running correctly ? [Y/n]'.format(
                self.name))
        return CLIUtils.promptYesNo(output, default='Y')
Beispiel #9
0
    def remove(self, settings):
        """
        Remove the tool:
            - Remove tool directory into toolbox
            - Change install status to false.

        :param Settings settings: Settings from config files
        :return: Removal status
        :rtype: bool
        """

        # Delete tool directory if tool was installed inside toolbox directory
        if self.install_command:
            if not FileUtils.is_dir(self.tool_dir):
                logger.warning('Directory "{dir}" does not exist'.format(
                    dir=self.tool_dir))
                return False
            elif not FileUtils.remove_directory(self.tool_dir):
                logger.error('Unable to delete directory "{dir}". ' \
                    'Check permissions and/or re-run with sudo'.format(
                        dir=self.tool_dir))  
                return False
            else:
                logger.success('Tool directory "{dir}" deleted'.format(
                    dir=self.tool_dir))

        # Make sure "installed" option in config file is set to False
        if settings.change_installed_status(self.target_service, 
                                            self.name, 
                                            install_status=False):
            logger.success('Tool marked as uninstalled')
        else:
            logger.error('An unexpected error occured when trying to mark the tool ' \
                'as uninstalled !')
            return False

        self.installed = False
        return True
Beispiel #10
0
    def __init__(self, settings_dir, toolbox_dir, output):
        """
		Initialize Settings object

		@Args		settings_dir: 	directory where config files are stored
					toolbox_dir: 	directory where the toolbox is stored
					output: 		Instance of CLIOutput

		"""
        self.settings_dir = settings_dir
        self.toolbox_dir = toolbox_dir
        self.output = output

        # config_parsers: dict of config_parsers indexed by conf_filename
        self.config_parsers = {}
        # general_settings: 2 dimensions dict - [service_name][option_name]
        self.general_settings = {}
        self.toolbox = Toolbox(self)

        # Check directory and presence of *.conf files
        if not FileUtils.is_dir(settings_dir):
            self.output.printError(
                'Configuration directory ({0}) does not exist'.format(
                    settings_dir))
            raise ValueError

        files = FileUtils.list_directory(settings_dir)
        for f in files:
            if not FileUtils.check_extension(f, CONF_EXT):
                files.remove(f)
        if not files:
            self.output.printError(
                'Configuration directory ({0}) does not store any *.conf file'.
                format(settings_dir))
            raise ValueError

        # Parse config files
        self.parseAllConfFiles(files)
Beispiel #11
0
    def defineOutputDir(self, output_dir, host, port, protocol, service):
        """
		Define the output directory name for storing results
		@Args 		output_dir:		name coming from argument (if defined by user)
					host:			target host name
					port:			target port number
					protocol:		protocol tcp or udp
					service: 		
		@Returns 	the final name to use as directory name
		"""
        if output_dir:
            return output_dir
        return FileUtils.concat_path(DEFAULT_OUTPUT_DIR, \
         'output_{0}-{1}{2}_{3}_{4}'.format(host, port, protocol, service, str(time.time()).split('.')[0]))
Beispiel #12
0
    def removeTool(self, settings, output):
        """
		Remove the tool:
			- Remove tool directory into toolbox
			- Change install status to false
		
		@Args		settings: 	Settings instance
					output: 	CLIOutput instance
		@Returns	Boolean indicating operation status
		"""

        if self.tooltype == ToolType.USE_MULTI:
            output.printInfo('"{0}" is a reference to the tool "{1}" used for multi services. Not deleted'.format(\
             self.name, self.tool_ref_name))
            return False

        if not FileUtils.is_dir(self.tool_dir):
            output.printInfo('Directory "{0}" does not exist'.format(
                self.tool_dir))
        else:
            if not FileUtils.remove_directory(self.tool_dir):
                output.printFail(
                    'Unable to delete directory "{0}". Check permissions and/or re-run with sudo'
                    .format(self.tool_dir))
                return False
            else:
                output.printInfo('Directory "{0}" deleted'.format(
                    self.tool_dir))

        # Make sure "installed" option in config file is set to False
        if not settings.changeInstalledOption(self.service_name, self.name,
                                              False):
            output.printError(
                'An unexpected error occured when trying to mark the tool as uninstalled !'
            )
        self.installed = False
        return True
Beispiel #13
0
    def statusReport(self, path, response):
        """
        @brief      Given URL Path Response Status Report

        @pattern      [23:59:59] Status Code (e.g. 302) - File Size (e.g. 222 B)  - /php  ->  Target URL
        """
        with self.mutex:
            contentLength = None
            status = response.status

            # Check Blacklist
            if status in self.blacklists and path in self.blacklists[status]:
                return

            # Format Messages
            try:
                size = int(response.headers['content-length'])
            except (KeyError, ValueError):
                size = len(response.body)
            finally:
                contentLength = FileUtils.sizeIEC(size)

            if self.basePath is None:
                showPath = urllib.parse.urljoin("/", path)
            else:
                showPath = urllib.parse.urljoin("/", self.basePath)
                showPath = urllib.parse.urljoin(showPath, path)

            # Concatenate The URL Response Report Message
            message = '[{0}] {1} - {2} - {3}'.format(
                time.strftime('%H:%M:%S'), status, contentLength.rjust(6, ' '),
                showPath)

            # HTTP Response Code List
            if status == 200:  # OK
                message = Fore.GREEN + message + Style.RESET_ALL
            elif status == 401:  # Unauthorized
                message = Fore.YELLOW + message + Style.RESET_ALL
            elif status == 403:  # Forbidden
                message = Fore.RED + message + Style.RESET_ALL
            # Check If Redirect --> Response Code
            # 301 (Moved Permanently), 302 (Found -> Moved temporarily"), 307 (Temporary Redirect)
            elif (status in [301, 302, 307]) and ('location' in [
                    h.lower() for h in response.headers
            ]):
                message = Fore.CYAN + message + Style.RESET_ALL
                message += '  ->  {0}'.format(response.headers['location'])

            self.newLine(message)
Beispiel #14
0
    def getBlacklists(self):
        """
        @brief      Get The Local Preset Status Code Related Blacklist

        @param      self  The Object

        @return     Target Blacklist Dictionary
        """
        blacklists = {}  # Target Dictionary (Consists of Status Code Lists)
        # 400 -> Bad Request, 403 -> Forbidden, 500 ->Internal Server Error
        db_Path = FileUtils.createPath(self.script_path, 'db')  # Local DB Path
        for status in [400, 403, 500]:
            blacklistFileName = FileUtils.createPath(  # Join Status Code as Filename (e.g. 403_blacklist.txt)
                db_Path, '{}_blacklist.txt'.format(status))
            blacklists[status] = []  # Status Code List Contained In Dictionary

            if not FileUtils.canRead(blacklistFileName):
                continue  # Skip Unreadable File
            for line in FileUtils.getLines(blacklistFileName):
                if line.lstrip().startswith('#'):
                    continue  # Skip Comments In The File
                blacklists[status].append(line)

        return blacklists
Beispiel #15
0
    def checkArgsOutput(self):
        """
		Check arguments related to Output
		"""
        if not self.contparsing or self.args.list_specific:
            return

        if self.args.output_dir:
            self.args.output_dir = self.args.output_dir.strip()
        else:
            self.args.output_dir = self.defineOutputDir(
                self.args.output_dir, self.target.host, self.target.port,
                self.target.protocol, self.target.service)

        if FileUtils.is_dir(self.args.output_dir):
            self.output.printError(
                'Directory "{0}" already exists. Choose another name.'.format(
                    self.args.output_dir))
            sys.exit(0)
        if not FileUtils.create_directory(self.args.output_dir):
            self.output.printError(
                'Impossible to create output directory "{0}". Check permissions'
                .format(self.args.output_dir))
            sys.exit(0)
Beispiel #16
0
    def __init__(self, settings_dir, toolbox_dir, output):
        """
		Constructor of Settings object
		@Args		settings_dir: 	directory where config files are stored
					toolbox_dir: 	directory where the toolbox is stored
					output: 		Instance of CLIOutput
		"""
        self.settings_dir = settings_dir
        self.toolbox_dir = toolbox_dir
        self.output = output
        # config_parsers: dict of config_parsers indexed by service_name
        self.config_parsers = {}
        # general_settings: 2 dimensions dict - [service_name][setting]
        self.general_settings = {}
        self.toolbox = Toolbox(self)

        # Check directory and presence of *.conf files
        if not FileUtils.is_dir(settings_dir):
            self.output.printError(
                'Configuration directory ({0}) does not exist'.format(
                    settings_dir))
            sys.exit(0)

        files = FileUtils.list_directory(settings_dir)
        for f in files:
            if not FileUtils.check_extension(f, CONF_EXT):
                files.remove(f)
        if not files:
            self.output.printError(
                'Configuration directory ({0}) does not store any *.conf file'.
                format(settings_dir))
            sys.exit(0)

        # Parse config files
        # i.e. extract tools categories and optional/specific settings for each service
        self.parseConfFiles(files)
Beispiel #17
0
    def recording(self):  # Override
        """
        @report_pattern
        HTTP Response Status Code + Package Size + URL + Path
        """

        record = ''
        # self.pathList.append((path, status, contentLength))
        for path, status, contentLength in self.pathList:
            record += '{0}  '.format(status)
            record += '{0}  '.format(
                FileUtils.sizeIEC(contentLength).rjust(6, ' '))
            record += '{0}://{1}:{2}/'.format(self.protocol, self.host,
                                              self.port)
            record += ('{0}\n'.format(path) if self.basePath is '' else
                       '{0}/{1}\n'.format(self.basePath, path))
        return record
Beispiel #18
0
    def generate(self):
        result = ""

        for path, status, contentLength, location in self.getPathIterator():
            result += "{0}  ".format(status)
            result += "{0}  ".format(
                FileUtils.sizeHuman(contentLength).rjust(6, " "))
            result += "{0}://{1}:{2}/".format(self.protocol, self.host,
                                              self.port)
            result += ("{0}".format(path) if self.basePath == "" else
                       "{0}/{1}".format(self.basePath, path))
            if location:
                result += "    -> REDIRECTS TO: {0}".format(location)

            result += "\n"

        return result
Beispiel #19
0
 def save(self, conf_filename):
     """
     Save change permanently into the file
     :param conf_filename: Settings filename without extension
     :return: Boolean indicating status
     """
     try:
         config_file = FileUtils.concat_path(SETTINGS_DIR, conf_filename+CONF_EXT)
         with open(config_file, 'w') as handle:
             self.config_parsers[conf_filename].write(handle)
             # Re-read to take change into account
             self.config_parsers[conf_filename].read(config_file, 'utf8') # warning: takes filename as param
         return True
     except:
         logger.error('Error occured when saving changes in settings file named "{filename}"'.format(
             filename=conf_filename))
         traceback.print_exc()
         return False        
Beispiel #20
0
    def saveSettings(self, service_name):
        """
		Save settings into config file.
		Make sure changes are thus taken into account.
		@Args		service_name: service targeted by the tool
		@Returns	Boolean indicating operation status
		"""
        try:
            config_file = FileUtils.concat_path(self.settings_dir,
                                                service_name + '.conf')
            with open(config_file, 'w') as handle:
                self.config_parsers[service_name].write(handle)
                # Re-read to take change into account
                self.config_parsers[service_name].read(
                    config_file)  # warning: takes filename as param
            return True
        except:
            traceback.print_exc()
            return False
Beispiel #21
0
    def saveSettings(self, conf_filename):
        """
		Save settings into config file.
		Make sure changes are thus taken into account.

		@Args		conf_filename: configuration filename (without extension)
		@Returns	Boolean indicating operation status
		"""
        try:
            config_file = FileUtils.concat_path(self.settings_dir,
                                                conf_filename + CONF_EXT)
            with open(config_file, 'w') as handle:
                self.config_parsers[conf_filename].write(handle)
                # Re-read to take change into account
                self.config_parsers[conf_filename].read(
                    config_file)  # warning: takes filename as param
            return True
        except:
            traceback.print_exc()
            return False
Beispiel #22
0
    def __init__(self, script_path):

        global VERSION
        self.script_path = script_path
        self.arguments = self.parse_arguments()
        self.scanners = [HttpAuthScanner, FormDataScanner]
        self.running = False
        self.setup_logger()
        PROGRAM_BANNER = open(
            FileUtils.build_path(script_path, "lib", "controller",
                                 "commandline",
                                 "banner.txt")).read().format(**VERSION)
        print(PROGRAM_BANNER)
        self.exit = False
        self.dictionary = Dictionary()
        self.parse_settings()
        self.print_lock = threading.Lock()
        for wordlist in self.get_wordlists():
            self.dictionary.append_from_wordlist(wordlist)
        self.start_loop()
        self.logger.info("Finished")
Beispiel #23
0
    def getReportsPath(self, requester):
        if self.arguments.autoSave:  # Default True
            basePath = ('/'
                        if requester.basePath is '' else requester.basePath)
            basePath = basePath.replace(os.path.sep, '.')[1:-1]

            # Generate File Name & Directory Path
            fileName = None
            directoryPath = None
            if self.batch:
                fileName = requester.host
                directoryPath = self.batchDirectoryPath
            else:
                fileName = ('{}_'.format(basePath)
                            if basePath is not '' else '')
                fileName += time.strftime('%y-%m-%d_%H-%M-%S')
                directoryPath = FileUtils.createPath(self.savePath, 'reports',
                                                     requester.host)

            if not FileUtils.exists(directoryPath):
                FileUtils.createDirectory(directoryPath)
                if not FileUtils.exists(directoryPath):
                    self.output.error("Cannot Create Reports Folder {}".format(
                        directoryPath))
                    sys.exit(1)

            # Generate Reports File Path
            outputFile = FileUtils.createPath(directoryPath, fileName)

            # Rename If Duplicate File is Found In Target Directory
            if FileUtils.exists(outputFile):
                i = 2
                while FileUtils.exists(outputFile + "_" + str(i)):
                    i += 1
                outputFile += "_" + str(i)

        return outputFile, directoryPath
Beispiel #24
0
    def __generate_index(self):
        """
        Generate HTML index code from template "index.tpl.html"
        """
        tpl = FileUtils.read(REPORT_TPL_DIR + '/index.tpl.html')

        tpl = tpl.replace('{{MISSION_NAME}}', self.mission)
        tpl = tpl.replace('{{TABLE_SERVICES_CONTENT}}',
                          self.__generate_table_services())
        tpl = tpl.replace('{{TABLE_HOSTS_CONTENT}}',
                          self.__generate_table_hosts())
        tpl = tpl.replace('{{TABLE_WEB_CONTENT}}', self.__generate_table_web())
        tpl = tpl.replace('{{TABLE_OPTIONS_CONTENT}}',
                          self.__generate_table_options())
        tpl = tpl.replace('{{TABLE_PRODUCTS_CONTENT}}',
                          self.__generate_table_products())
        tpl = tpl.replace('{{TABLE_CREDS_CONTENT}}',
                          self.__generate_table_credentials())
        tpl = tpl.replace('{{TABLE_VULNS_CONTENT}}',
                          self.__generate_table_vulns())

        return tpl
Beispiel #25
0
 def saveHomeOption(self):
     # If saveHome == True --> Get 'savePath' Path
     savePath = self.getSavePath()
     if not FileUtils.exists(savePath):  # Check Existence
         FileUtils.createDirectory(savePath)
     if FileUtils.exists(
             savePath) and not FileUtils.isDir(savePath):  # Check Status
         self.output.error(
             "NOT Available ! {} is a File, Should be a Directory.\nPlease Check Again."
             .format(savePath))
         exit(1)
     if not FileUtils.canWrite(savePath):  # Check Writability
         self.output.error(
             "Directory {} is Not Writable.\nPlease Check Again.".format(
                 savePath))
         exit(1)
     return savePath
Beispiel #26
0
    def __init__(self,
                 name,
                 description,
                 target_service,
                 installed,
                 last_update='',
                 virtualenv='',
                 install_command=None,
                 update_command=None,
                 check_command=None):
        """
        Construct the Tool object.

        :param str name: Name of the tool ([a-zA-Z0-9-_])
        :param str description: Short description of the tool
        :param str target_service: Name of service targeted by this tool
            (might be "multi" for tools that could be used against various services)
        :param bool installed: Install status
        :param str last_update: Datetime of the last updated ('' if not installed)
        :param str virtualenv: Language of virtual environment to use (optional)
        :param Command install_command: Install command (optional)
        :param Command update_command: Update command (optional)
        :param Command check_command: Command to check install (optional)
        """
        self.name = name
        self.description = description
        self.target_service = target_service
        self.installed = installed if isinstance(installed, bool) else False
        self.last_update = last_update
        self.virtualenv = virtualenv
        self.install_command = install_command
        self.update_command = update_command
        self.check_command = check_command
        self.tool_dir = FileUtils.absolute_path(
            '{toolbox}/{service}/{name}'.format(
                toolbox=TOOLBOX_DIR,
                service=self.target_service,
                name=self.name)) if self.install_command else ''
Beispiel #27
0
    def setupReports(self, requester):
        if self.arguments.autoSave:  # Default True
            # Auto Save Format Option
            if FileUtils.canWrite(self.directoryPath):
                report = None
                if self.arguments.autoSaveFormat == 'simple':
                    report = SimpleReport(requester.host, requester.port,
                                          requester.protocol,
                                          requester.basePath, self.reportsPath)
                if self.arguments.autoSaveFormat == 'json':
                    report = JSONReport(requester.host, requester.port,
                                        requester.protocol, requester.basePath,
                                        self.reportsPath)
                else:  # PlainTextReport
                    report = PlainTextReport(
                        requester.host, requester.port, requester.protocol,
                        requester.basePath, self.reportsPath)
                self.reportController.addReport(report)
            else:
                self.output.error("Cannot Write Reports to {}".format(
                    self.directoryPath))
                sys.exit(1)

        # Save Format Option
        if self.arguments.simpleOutputFile is not None:  # Simple Format
            self.reportController.addReport(
                SimpleReport(requester.host, requester.port,
                             requester.protocol, requester.basePath,
                             self.arguments.simpleOutputFile))
        if self.arguments.plainTextOutputFile is not None:  # Plain Text Format
            self.reportController.addReport(
                PlainTextReport(requester.host, requester.port,
                                requester.protocol, requester.basePath,
                                self.arguments.plainTextOutputFile))
        if self.arguments.jsonOutputFile is not None:  # JSON Format
            self.reportController.addReport(
                JSONReport(requester.host, requester.port, requester.protocol,
                           requester.basePath, self.arguments.jsonOutputFile))
Beispiel #28
0
    def parseConfig(self):
        config = DefaultConfigParser()
        configPath = FileUtils.buildPath(os.path.expanduser('~'), ".dirsearch", "dirsearch.conf")

        if not FileUtils.exists(configPath):
            FileUtils.createDirectory(os.path.dirname(configPath))
            shutil.copyfile(FileUtils.buildPath(self.script_path, 'default.conf'), configPath)

        config.read(configPath)

        # General
        self.threadsCount = config.safe_getint("general", "threads", 10, list(range(1, 50)))
        self.excludeStatusCodes = config.safe_get("general", "exclude-status", None)
        self.redirect = config.safe_getboolean("general", "follow-redirects", False)
        self.recursive = config.safe_getboolean("general", "recursive", False)
        self.recursive_level_max = config.safe_getint("general", "recursive-level-max", 1)
        self.suppressEmpty = config.safe_getboolean("general", "suppress-empty", False)
        self.testFailPath = config.safe_get("general", "scanner-fail-path", "").strip()
        self.saveHome = config.safe_getboolean("general", "save-logs-home", False)

        # Reports
        self.autoSave = config.safe_getboolean("reports", "autosave-report", False)
        self.autoSaveFormat = config.safe_get("reports", "autosave-report-format", "plain", ["plain", "json", "simple"])
        # Dictionary
        self.wordlist = config.safe_get("dictionary", "wordlist",
                                        FileUtils.buildPath(self.script_path, "db", "dicc.txt"))
        self.lowercase = config.safe_getboolean("dictionary", "lowercase", False)
        self.forceExtensions = config.safe_get("dictionary", "force-extensions", False)

        # Connection
        self.useRandomAgents = config.safe_get("connection", "random-user-agents", False)
        self.useragent = config.safe_get("connection", "user-agent", None)
        self.delay = config.safe_get("connection", "delay", 0)
        self.timeout = config.safe_getint("connection", "timeout", 30)
        self.maxRetries = config.safe_getint("connection", "max-retries", 5)
        self.proxy = config.safe_get("connection", "http-proxy", None)
        self.httpmethod = config.safe_get("connection", "httpmethod", "get", ["get", "head", "post"])
        self.requestByHostname = config.safe_get("connection", "request-by-hostname", False)
Beispiel #29
0
	def parser(self):
		tmp_dict = []
		for line in FileUtils.getLines(self.dicfile):
			#line的格式为admin:admin
			tmp_dict.append(line)
		return tmp_dict
Beispiel #30
0
    def run(self):

        # Create report directory
        dirname = '{mission}-{datetime}'.format(
            mission=StringUtils.clean(self.mission.replace(' ', '_'),
                                      allowed_specials=('_', '-')),
            datetime=datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
        self.output_path = self.output_path + '/' + dirname

        if not FileUtils.create_directory(self.output_path):
            logger.error('Unable to create report directory: "{path}"'.format(
                path=self.output_path))
            return False

        # Retrieve all services in selected mission
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        services = req.get_results()

        # Generate screenshots
        processor = ScreenshotsProcessor(self.mission, self.sqlsession)
        processor.run()

        screens_dir = self.output_path + '/screenshots'
        if not FileUtils.create_directory(screens_dir):
            logger.warning(
                'Unable to create screenshots directory: "{path}"'.format(
                    path=screens_dir))
        else:
            for service in services:
                if service.name == 'http' and service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK:

                    img_name = 'scren-{ip}-{port}-{id}'.format(
                        ip=str(service.host.ip),
                        port=service.port,
                        id=service.id)
                    path = screens_dir + '/' + img_name

                    ImageUtils.save_image(service.screenshot.image,
                                          path + '.png')
                    ImageUtils.save_image(service.screenshot.thumbnail,
                                          path + '.thumb.png')

        # Create index.html
        html = self.__generate_index()
        if FileUtils.write(self.output_path + '/index.html', html):
            logger.info('index.html file generated')
        else:
            logger.error('An error occured while generating index.html')
            return False

        # Create results-<service>.html (1 for each service)
        for service in services:
            # Useless to create page when no check has been run for the service
            if len(service.results) == 0:
                continue

            html = self.__generate_results_page(service)
            # Create a unique name for the service HTML file
            filename = 'results-{ip}-{port}-{service}-{id}.html'.format(
                ip=str(service.host.ip),
                port=service.port,
                service=service.name,
                id=service.id)
            if FileUtils.write(self.output_path + '/' + filename, html):
                logger.info(
                    '{filename} file generated'.format(filename=filename))
            else:
                logger.error(
                    'An error occured while generating {filename}'.format(
                        filename=filename))
                return False

        logger.success('HTML Report written with success in: {path}'.format(
            path=self.output_path))
        logger.info('Important: If running from Docker container, make sure to run ' \
            '"xhost +" on the host before')
        if Output.prompt_confirm('Would you like to open the report now ?',
                                 default=True):
            webbrowser.open(self.output_path + '/index.html')

        return True
Beispiel #31
0
    def __generate_table_web(self):
        """
        Generate the table with HTTP services registered in the mission
        """
        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition('http', FilterData.SERVICE_EXACT))
        req.add_filter(filter_)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="7">No record found</td>
            </tr>
            """
        else:
            html = ''

            # Unavailable thumbnail
            with open(REPORT_TPL_DIR + '/../img/unavailable.png', 'rb') as f:
                unavailable_b64 = base64.b64encode(f.read()).decode('ascii')

            for service in services:

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                # Encrypted ? (SSL/TLS)
                enc = '<span class="mdi mdi-lock" title="SSL/TLS encrypted"></span>' \
                    if service.is_encrypted() else ''

                # Web technos (in a specific order)

                # try:
                #     technos = ast.literal_eval(service.web_technos)
                # except Exception as e:
                #     logger.debug('Error when retrieving "web_technos" field ' \
                #         'from db: {exc} for {service}'.format(
                #             exc=e, service=service))
                #     technos = list()

                # tmp = list()
                # for t in technos:
                #     tmp.append('{}{}{}'.format(
                #         t['name'],
                #         ' ' if t['version'] else '',
                #         t['version'] if t['version'] else ''))
                # webtechnos = ' | '.join(tmp)

                webtechnos = ''
                product_types = ('web-server', 'web-appserver', 'web-cms',
                                 'web-language', 'web-framework', 'web-jslib')
                for t in product_types:
                    product = service.get_product(t)
                    if product:
                        webtechnos += '<span class="badge badge-{type} badge-light">' \
                            '{name}{version}</span>'.format(
                                type=t,
                                name=product.name,
                                version=' '+str(product.version) \
                                    if product.version else '')

                # Web Application Firewall
                product = service.get_product('web-application-firewall')
                waf = ''
                if product:
                    waf = '<span class="badge badge-web-application-firewall ' \
                        'badge-light">{name}{version}</span>'.format(
                            name=product.name,
                            version=' '+str(product.version) \
                                if product.version else '')

                # Screenshot
                img_name = 'scren-{ip}-{port}-{id}'.format(ip=str(
                    service.host.ip),
                                                           port=service.port,
                                                           id=service.id)
                path = self.output_path + '/screenshots'

                if service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK \
                        and FileUtils.exists(path + '/' + img_name + '.png') \
                        and FileUtils.exists(path + '/' + img_name + '.thumb.png'):

                    screenshot = """
                    <a href="{screenlarge}" title="{url} - {title}" class="image-link">
                        <img src="{screenthumb}" class="border rounded">
                    </a>
                    """.format(url=service.url,
                               screenlarge='screenshots/' + img_name + '.png',
                               title=service.html_title,
                               screenthumb='screenshots/' + img_name +
                               '.thumb.png')

                else:
                    screenshot = """
                    <img src="data:image/png;base64,{unavailable}">
                    """.format(unavailable=unavailable_b64)

                # HTML for table row
                html += """
                <tr{clickable}>
                    <td>{url}</td>
                    <td>{enc}</td>
                    <td>{title}</td>
                    <td>{webtechnos}</td>
                    <td>{waf}</td>
                    <td>{screenshot}</td>
                    <td>{checks}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 50)) \
                        if service.url else '',
                    enc=enc,
                    title=StringUtils.shorten(service.html_title, 40),
                    webtechnos=webtechnos,
                    waf=waf,
                    screenshot=screenshot,
                    checks=len(service.results))

        return html
Beispiel #32
0
    def __generate_table_web(self):
        """
        Generate the table with HTTP services registered in the mission
        """

        req = ServicesRequester(self.sqlsession)
        req.select_mission(self.mission)
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition('http', FilterData.SERVICE_EXACT))
        req.add_filter(filter_)
        services = req.get_results()

        if len(services) == 0:
            html = """
            <tr class="notfound">
                <td colspan="5">No record found</td>
            </tr>
            """
        else:
            html = ''

            # Unavailable thumbnail
            with open(REPORT_TPL_DIR + '/../img/unavailable.png', 'rb') as f:
                unavailable_b64 = base64.b64encode(f.read()).decode('ascii')

            for service in services:

                # Results HTML page name
                results = 'results-{ip}-{port}-{service}-{id}.html'.format(
                    ip=str(service.host.ip),
                    port=service.port,
                    service=service.name,
                    id=service.id)

                # Web technos
                try:
                    technos = ast.literal_eval(service.web_technos)
                except Exception as e:
                    logger.debug('Error when retrieving "web_technos" field ' \
                        'from db: {exc} for {service}'.format(
                            exc=e, service=service))
                    technos = list()

                tmp = list()
                for t in technos:
                    tmp.append('{}{}{}'.format(
                        t['name'], ' ' if t['version'] else '',
                        t['version'] if t['version'] else ''))
                webtechnos = ' | '.join(tmp)

                # Screenshot
                img_name = 'scren-{ip}-{port}-{id}'.format(ip=str(
                    service.host.ip),
                                                           port=service.port,
                                                           id=service.id)
                path = self.output_path + '/screenshots'

                if service.screenshot is not None \
                        and service.screenshot.status == ScreenStatus.OK \
                        and FileUtils.exists(path + '/' + img_name + '.png') \
                        and FileUtils.exists(path + '/' + img_name + '.thumb.png'):

                    screenshot = """
                    <a href="{screenlarge}" title="{title}" class="image-link">
                        <img src="{screenthumb}" class="border rounded">
                    </a>
                    """.format(screenlarge='screenshots/' + img_name + '.png',
                               title=service.html_title,
                               screenthumb='screenshots/' + img_name +
                               '.thumb.png')

                else:
                    screenshot = """
                    <img src="data:image/png;base64,{unavailable}">
                    """.format(unavailable=unavailable_b64)

                # HTML for table row
                html += """
                <tr{clickable}>
                    <td>{url}</td>
                    <td>{title}</td>
                    <td>{webtechnos}</td>
                    <td>{screenshot}</td>
                    <td>{checks}</td>
                </tr>
                """.format(
                    clickable=' class="clickable-row" data-href="{results}"'.format(
                        results=results) if len(service.results) > 0 else '',
                    url='<a href="{}" title="{}">{}</a>'.format(
                        service.url, service.url, StringUtils.shorten(service.url, 50)) \
                        if service.url else '',
                    title=StringUtils.shorten(service.html_title, 40),
                    webtechnos=webtechnos,
                    screenshot=screenshot,
                    checks=len(service.results))

        return html
Beispiel #33
0
    def runUpdate(self, settings, output):
        """
		Run the update for the tool 
		@Args		settings: 	Settings instance
					output: 	CLIOutput instance
		@Returns	Boolean indicating status
		"""
        # Tool not installed yet
        if not self.installed:
            output.printInfo(
                '{0} is not installed yet (according to config), skipped.'.
                format(self.name))
            print
            return False

        # Not installed, but no update command specified
        elif not self.update:
            output.printWarning(
                'No tool update command specified in config file, skipped.')
            print
            return False

        # Create directory for the tool if necessary (should not be necessary because only update)
        if not FileUtils.is_dir(self.tool_dir):
            output.printFail(
                'Tool directory does not exist but tool marked as installed. Trying to re-install it...'
            )
            return self.runInstall(settings, output)

        # Update command parsing
        cmd_update = self.getUpdateCmd()
        cmd_update_print = cmd_update[cmd_update.index(';') + 1:].strip()
        output.printInfo('Update Command:')
        output.printInfo(cmd_update_print)
        output.printPrompt('{0} > {1} - Update ? [Y/n]'.format(
            self.category, self.name))
        # Prompt
        to_update = CLIUtils.promptYesNo(output, default='Y')

        # Run update command if wanted
        if to_update:
            output.printBeginCmd(cmd_update_print)
            process = ProcessLauncher(cmd_update, output, None)
            process.start()
            output.printEndCmd()

            output.printSuccess('Tool update has finished')

            output.printInfo('Now, checking if {0} has been updated correctly. '.format(self.name) + \
             'Hit any key to run test...')
            CLIUtils.getch()

            # Check update, update config options
            if self.checkInstall(output):
                if not settings.changeLastUpdateOption(self.service_name,
                                                       self.section_name):
                    output.printWarning(
                        'An unexpected error occured when trying to last update date.'
                    )
                else:
                    output.printSuccess(
                        'Tool {0} has been marked as successfully updated.'.
                        format(self.name))
            else:
                # If test fails, ask user if re-install ?
                output.printFail(
                    'Tool {0} has not been marked as updated.'.format(
                        self.name))
                output.printPrompt(
                    'Do you want to try to re-install {0} ? [Y/n]'.format(
                        self.name))

                # Prompt
                to_reinstall = CLIUtils.promptYesNo(output, default='Y')

                # Re-Install
                if to_reinstall:
                    self.reinstallTool(settings, output)
        else:
            output.printFail('Tool has not been updated')

        print