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)) # Remove virtualenv files if necessary virtualenv_dir = '{}/{}'.format(VIRTUALENVS_DIR, self.name) if FileUtils.is_dir(virtualenv_dir): if FileUtils.remove_directory(virtualenv_dir): logger.success('Virtualenv directory deleted') else: logger.warning('Unable to delete Virtualenv directory') if self.virtualenv.startswith('ruby'): logger.info('Delete RVM environment ({ruby}@{name})...'.format( ruby=self.virtualenv, name=self.name)) cmd = 'source /usr/local/rvm/scripts/rvm; rvm use {ruby} && ' \ 'rvm gemset delete {name} --force'.format( ruby=self.virtualenv, name=self.name) returncode, _ = ProcessLauncher(cmd).start() if returncode == 0: logger.success('RVM environment deleted with success') else: logger.warning('Unable to delete RVM environment') # 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
def __check_pre_update(self, settings, fast_mode=False): """ Perform some checks before trying to update the tool (already installed ?, update command ?). :param Settings settings: Settings from config files :param bool fast_mode: Set to true to disable prompts :return: Result of checks :rtype: bool """ if not self.installed: logger.info('{tool} is not installed yet (according to settings), ' \ 'skipped'.format(tool=self.name)) return False elif not self.update_command: logger.warning('No tool update command specified in config file, skipped.') return False # Create directory for the tool if necessary # (should not be necessary because only update) if self.install_command and not FileUtils.is_dir(self.tool_dir): logger.warning('Tool directory does not exist but tool marked as ' \ 'installed. Trying to re-install it...') return self.install(settings, fast_mode) return True
def __check_pre_update(self, settings, fast_mode): """ Checks to run before updating the tool :param settings: Settings instance :param fast_mode: Boolean indicating whether prompts must be displayed or not :return: Boolean indicating status """ if not self.installed: logger.info( '{tool} is not installed yet (according to settings), skipped'. format(tool=self.name_display)) return False elif not self.update_command: logger.warning( 'No tool update command specified in config file, skipped.') return False # Create directory for the tool if necessary (should not be necessary because only update) if self.install_command and not FileUtils.is_dir(self.tool_dir): logger.warning( 'Tool directory does not exist but tool marked as installed. Trying to re-install it...' ) return self.install(settings, fast_mode) return True
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
def createToolDirectory(self, output): """ Create the tool reserved directory if necessary @Args output: CLIOutput instance @Returns Boolean indicating if dir was successfully created """ # if FileUtils.is_dir(self.tool_dir): # 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)) # else: # output.printInfo('Directory \'{0}\' deleted'.format(self.tool_dir)) 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
def removeTool(self, settings, output): """ Remove tool directory and all files it contains @Args settings: Settings instance output: CLIOutput instance @Returns Boolean indicating status """ 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.section_name, 'False'): output.printError( 'An unexpected error occured when trying to mark the tool as uninstalled !' ) self.installed = False return True
def __init__(self): """ :raises SettingsException: """ self.config_parsers = dict() # dict of DefaultConfigParser indexed by filename self.toolbox = None # Receives Toolbox object self.services = None # Receives ServicesConfig object # Check directory and presence of *.conf files if not FileUtils.is_dir(SETTINGS_DIR): raise SettingsException('Configuration directory ({dir}) does not exist'.format(dir=SETTINGS_DIR)) files = FileUtils.list_directory(SETTINGS_DIR) for f in files: if not FileUtils.check_extension(f, CONF_EXT): files.remove(f) if not files: raise SettingsException('Configuration directory ({dir}) does not store any *.conf file'.format( dir=SETTINGS_DIR)) if TOOLBOX_CONF_FILE+CONF_EXT not in files: raise SettingsException('Missing mandatory {toolbox}{ext} settings file in directory "{dir}"'.format( toolbox=TOOLBOX_CONF_FILE, ext=CONF_EXT, dir=SETTINGS_DIR)) if INSTALL_STATUS_CONF_FILE+CONF_EXT not in files: open(SETTINGS_DIR+'/'+INSTALL_STATUS_CONF_FILE+CONF_EXT, 'a').close() logger.info('{status}{ext} settings file created in directory "{dir}"'.format( status=INSTALL_STATUS_CONF_FILE, ext=CONF_EXT, dir=SETTINGS_DIR)) files.append(INSTALL_STATUS_CONF_FILE+CONF_EXT) # Parse settings files, add tools inside toolbox and create scan configs self.__parse_all_conf_files(files) self.__create_toolbox() self.__create_all_services_checks()
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
def __init__(self): """ Start the parsing of settings files and create the Settings object. :raises SettingsException: Exception raised if any error is encountered while parsing files (syntax error, missing mandatory file...) """ self.config_parsers = dict( ) # Dict of DefaultConfigParser indexed by filename self.toolbox = None # Receives Toolbox object self.services = None # Receives ServicesConfig object self.attack_profiles = None # Receives AttackProfiles object # Check directory if not FileUtils.is_dir(SETTINGS_DIR): raise SettingsException('Configuration directory ({dir}) does not ' \ 'exist'.format(dir=SETTINGS_DIR)) # Check presence of *.conf files files = FileUtils.list_directory(SETTINGS_DIR) for f in files: if not FileUtils.check_extension(f, CONF_EXT): files.remove(f) if not files: raise SettingsException('Configuration directory ({dir}) does not ' \ 'store any *.conf file'.format(dir=SETTINGS_DIR)) if TOOLBOX_CONF_FILE + CONF_EXT not in files: raise SettingsException('Missing mandatory {toolbox}{ext} settings ' \ 'file in directory "{dir}"'.format( toolbox=TOOLBOX_CONF_FILE, ext=CONF_EXT, dir=SETTINGS_DIR)) if ATTACK_PROFILES_CONF_FILE + CONF_EXT not in files: raise SettingsException('Missing mandatory {profiles}{ext} settings ' \ 'file in directory "{dir}"'.format( profiles=ATTACK_PROFILES_CONF_FILE, ext=CONF_EXT, dir=SETTINGS_DIR)) # Create _install_status.conf file if necessary if INSTALL_STATUS_CONF_FILE + CONF_EXT not in files: open(SETTINGS_DIR + '/' + INSTALL_STATUS_CONF_FILE + CONF_EXT, 'a').close() logger.info('{status}{ext} settings file created in directory ' \ '"{dir}"'.format(status=INSTALL_STATUS_CONF_FILE, ext=CONF_EXT, dir=SETTINGS_DIR)) files.append(INSTALL_STATUS_CONF_FILE + CONF_EXT) # Parse configuration files and create objects from them self.__parse_all_conf_files(files) self.__create_toolbox() self.__create_all_services_config_and_checks() self.__create_attack_profiles()
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')
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
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
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)
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)
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)
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
def runUpdate(self, settings, output, fast_mode=False, referencing_tool=None): """ Run the update for the tool @Args settings: Settings instance output: CLIOutput instance @Returns Boolean indicating status """ # Check for cases where no update will be run if not self.installed: output.printInfo('{0} is not installed yet (according to config), skipped.'.format(self.name)) print return False elif self.tooltype == ToolType.USE_MULTI: output.printInfo('This is a reference to the tool "{0}", which is not specific to the service {1}'.format(self.tool_ref_name, self.service_name)) ref_tool = settings.toolbox.searchInToolboxForService(self.tool_ref_name, Constants.MULTI_SERVICES_CONF_FILE) if ref_tool: return ref_tool.runUpdate(settings, output, fast_mode=fast_mode, referencing_tool=self) else: output.printFail('The tool "{0}" has not been found inside the conf file "{1}{2}"'.format(self.tool_ref_name, \ Constants.MULTI_SERVICES_CONF_FILE, Constants.CONF_EXT)) return False 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, fast_mode) # Print basic info and prompt confirmation cmd, cmd_short = self.update.getParsedCmdline() output.printInfo('Description : {0}'.format(self.description)) output.printInfo('Install command : {0}'.format(cmd_short)) if not fast_mode: output.printPrompt('Update ? [Y/n]') # Run update command if wanted if fast_mode or CLIUtils.promptYesNo(output, default='Y'): output.printBeginCmd(cmd_short) process = ProcessLauncher(cmd, output, None) process.start() output.printEndCmd() output.printSuccess('Tool update has finished') # Check install ? update_ok = True if not (self.tooltype == ToolType.MULTI_SERVICES and not referencing_tool) and not fast_mode: output.printInfo('Now, checking if {0} has been updateed correctly. Hit any key to run test...'.format(self.name)) CLIUtils.getch() try: update_ok = self.checkInstall(output, referencing_tool=referencing_tool) except Exception as e: update_ok = False output.printError('An unexpected error occured when checking install: {0}'.format(e)) # Change install status in configuration file if update_ok: try: if settings.changeInstalledOption(self.service_name, self.name, True): output.printSuccess('Tool {0} has been marked as successfully updated'.format(self.name)) else: output.printError('Error when saving "{0}{1}" configuration file'.format(Constants.INSTALL_STATUS_CONF_FILE, Constants.CONF_EXT)) except Exception as e: output.printError('An unexpected error occured when trying to change the last update date: {0}'.format(e)) #self.removeTool(settings, output) else: output.printFail('Tool {0} has not been marked as updated'.format(self.name)) #self.removeTool(settings, output) output.printPrompt('Do you want to try to re-install {0} ? [Y/n]'.format(self.name)) if CLIUtils.promptYesNo(output, default='Y'): self.reinstallTool(settings, output, referencing_tool=referencing_tool) else: output.printFail('Tool has not been updated') print