Beispiel #1
0
    def show(self, filter_service=None):
        """
        Display information about supported attack profiles

        :param str filter_service: Service name to filter with (default: no filter)
        """

        data = list()
        columns = [
            'Profile',
            'Description',
        ]

        for p in self.profiles:
            #print(p.checks)
            if not filter_service or p.is_service_supported(filter_service):
                data.append([
                    Output.colored(p.name, attrs='bold'),
                    StringUtils.wrap(p.description, 120)
                ])

        if filter_service:
            service = 'for service {}'.format(filter_service.upper())
        else:
            service = ''
        Output.title1('Attack Profiles {service}'.format(service=service))
        Output.table(columns, data, hrules=False)

        if not filter_service:
            print
            Output.print('Run "info --attack-profiles <service>" to see the attack ' \
                'profiles supported for a given service.')
Beispiel #2
0
    def show_products(self, filter_service=None):
        """
        Display supported products in a table

        :param list filter_service: Filter on services (default: all)
        """
        data = list()
        columns = [
            'Type',
            'Product Names',
        ]
        services = self.list_services() if filter_service is None else [
            filter_service
        ]
        for service in services:
            products = self.services[service]['products']
            for product_type in products:
                names = sorted(
                    self.services[service]['products'][product_type])
                names = StringUtils.wrap(', '.join(names), 100)

                data.append([product_type, names])

        Output.title1('Available products for {filter}'.format(
            filter='all services' if filter_service is None \
                   else 'service ' + filter_service))

        if not data:
            logger.warning('No product')
        else:
            Output.table(columns, data)
Beispiel #3
0
    def update_for_service(self, service, fast_mode=False):
        """
        Update the tools for a given service.

        :param str service: Name of the service targeted by the tools to update 
            (may be "multi")
        :param bool fast_mode: Set to true to disable prompts and install checks
        """
        if service not in self.services: return
        Output.title1(
            'Update tools for service: {service}'.format(service=service))

        if not self.tools[service]:
            logger.info('No tool specific to this service in the toolbox')
        else:
            i = 1
            for tool in self.tools[service]:
                if i > 1: print()
                Output.title2(
                    '[{svc}][{i:02}/{max:02}] Update {tool_name}:'.format(
                        svc=service,
                        i=i,
                        max=len(self.tools[service]),
                        tool_name=tool.name))

                tool.update(self.settings, fast_mode=fast_mode)
                i += 1
Beispiel #4
0
    def show_services(self, toolbox):
        """
        Display supported services in a table.

        :param Toolbox toolbox: Toolbox
        """
        data = list()
        columns = [
            'Service',
            'Default port',
            '# Tools',
            '# Checks',
        ]
        for service in self.list_services(multi=True):
            data.append([
                service,
                'N/A' if service == 'multi' else '{port}/{proto}'.format(
                    port  = self.services[service]['default_port'],
                    proto = self.services[service]['protocol']),
                '{nb_installed}/{nb_tools}'.format(
                    nb_installed = toolbox.nb_tools(filter_service=service,
                                                    only_installed=True),
                    nb_tools     = toolbox.nb_tools(filter_service=service)),
                'N/A' if service == 'multi' \
                      else self.services[service]['checks'].nb_checks(),
            ])

        Output.title1('Supported services')
        Output.table(columns, data, hrules=False)
Beispiel #5
0
    def check(self):
        """
        Check the toolbox: Run all check commands (when available) from all
        installed tools, in automatic mode (i.e. checks based on exit codes)

        In case of an error code returned by one check command (!= 0), the function
        stops and exits the program with exit code 1 (error). 
        Otherwise, if all check commands have returned a success exit code (0), 
        it exits the program with exit code 0 (success).

        Designed to be used for Continuous Integration.
        """
        Output.title1('Automatic check of installed tools')
        for service in self.services:
            for tool in self.tools[service]:
                if tool.installed:
                    # Automatic mode (no prompt), only based on exit status
                    status = tool.run_check_command(fast_mode=True)
                    if not status:
                        logger.error('An error occured with the tool "{tool}". Exit ' \
                            'check with exit code 1...'.format(tool=tool.name))
                        sys.exit(1)
                print()
                print()

        logger.success('No error has been detected with all tools check commands. ' \
            'Exit with success code 0...')
        sys.exit(0)
Beispiel #6
0
    def show_services(self, toolbox):
        """
        Show all supported services along with number of installed tools / total number
        :param toolbox: Toolbox object
        :return: None
        """
        data = list()
        columns = [
            'Service',
            'Default port',
            '# Tools',
            '# Checks',
        ]
        for service in self.list_services(multi=True):
            data.append([
                service,
                'N/A' if service == 'multi' else '{port}/{proto}'.format(
                    port=self.services[service]['default_port'],
                    proto=self.services[service]['protocol']),
                '{nb_installed}/{nb_tools}'.format(
                    nb_installed=toolbox.nb_tools_installed(service),
                    nb_tools=toolbox.nb_tools(service)),
                'N/A' if service == 'multi' else
                self.services[service]['checks'].nb_checks(),
            ])

        Output.title1('Supported services')
        Output.table(columns, data, hrules=False)
Beispiel #7
0
    def show_authentication_types(self, service='http'):
        """Display list of authentication types for HTTP."""
        Output.title1('Supported {service} authentication types'.format(
            service=service.upper()))

        if not self.is_service_supported(service, multi=False):
            logger.warning('The service {service} is not supported'.format(
                service=service))

        elif not self.services[service]['auth_types']:
            logger.warning('No special authentication type for this service')

        else:
            data = list()
            for t in sorted(self.services[service]['auth_types']):
                data.append([t])
            Output.table(['Authentication types'], data, hrules=False)
Beispiel #8
0
    def show_toolbox(self, filter_service=None):
        """
        Display a table showing the content of the toolbox.

        :param str filter_service: Service name to filter with (default: no filter)
        """
        if filter_service is not None and filter_service not in self.services:
            return

        data = list()
        columns = [
            'Name',
            'Service',
            'Status/Update',
            'Description',
        ]

        services = self.services if filter_service is None else [
            filter_service
        ]
        for service in services:
            for tool in self.tools[service]:

                # Install status style
                if tool.installed:
                    status = Output.colored('OK | ' +
                                            tool.last_update.split(' ')[0],
                                            color='green')
                else:
                    status = Output.colored('Not installed', color='red')

                # Add line for the tool
                data.append([
                    tool.name,
                    tool.target_service,
                    status,
                    StringUtils.wrap(tool.description, 120),  # Max line length
                ])

        Output.title1('Toolbox content - {filter}'.format(
            filter='all services' if filter_service is None \
                   else 'service ' + filter_service))

        Output.table(columns, data, hrules=False)
Beispiel #9
0
    def remove_for_service(self, service):
        """
        Remove the tools for a given service.

        :param str service: Name of the service targeted by the tools to remove
            (may be "multi")
        """
        if service not in self.services: return
        Output.title1(
            'Remove tools for service: {service}'.format(service=service))

        if not self.tools[service]:
            logger.info('No tool specific to this service in the toolbox')
        else:
            i = 1
            status = True
            for tool in self.tools[service]:
                if i > 1: print()
                Output.title2(
                    '[{svc}][{i:02}/{max:02}] Remove {tool_name}:'.format(
                        svc=service,
                        i=i,
                        max=len(self.tools[service]),
                        tool_name=tool.name))

                status &= tool.remove(self.settings)
                i += 1

            # Remove the service directory if all tools successfully removed
            if status:
                short_svc_path = '{toolbox}/{service}'.format(
                    toolbox=TOOLBOX_DIR, service=service)

                full_svc_path = FileUtils.absolute_path(short_svc_path)

                if FileUtils.remove_directory(full_svc_path):
                    logger.success(
                        'Toolbox service directory "{path}" deleted'.format(
                            path=short_svc_path))
                else:
                    logger.warning('Toolbox service directory "{path}" cannot be ' \
                        'deleted because it still stores some files'.format(
                            path=short_svc_path))
Beispiel #10
0
 def show_authentication_types(self, service):
     """
     Show list of authentication types for the given service.
     Actually relevant only for HTTP (for now ?)
     :param service: Service name
     :return: None
     """
     Output.title1('Supported {service} authentication types'.format(
         service=service.upper()))
     if not self.is_service_supported(service, multi=False):
         logger.warning('The service {service} is not supported'.format(
             service=service))
     elif not self.services[service]['auth_types']:
         logger.warning('No special authentication type for this service')
     else:
         data = list()
         for t in sorted(self.services[service]['auth_types']):
             data.append([t])
         Output.table(['Authentication types'], data, hrules=False)
Beispiel #11
0
    def show_specific_options(self, filter_service=None):
        """
        Display supported specific options in a table.

        :param list filter_service: Filter on services (default: all)
        """
        data = list()
        columns = [
            'Option',
            'Service',
            'Supported values',
        ]
        services = self.list_services() if filter_service is None else [
            filter_service
        ]
        for service in services:
            options = self.services[service]['specific_options']
            for opt in options:
                if options[opt] == OptionType.BOOLEAN:
                    values = 'true, false'

                elif options[opt] == OptionType.LIST:
                    values = sorted(
                        self.services[service]['supported_list_options'][opt])
                    values = StringUtils.wrap(', '.join(values), 80)

                else:
                    values = '<anything>'
                data.append([opt, service, values])

        Output.title1('Available context-specific options for {filter}'.format(
            filter='all services' if filter_service is None \
                   else 'service ' + filter_service))

        if not data:
            logger.warning('No specific option')
        else:
            Output.table(columns, data, hrules=False)
Beispiel #12
0
 def show(self):
     """Display a table with all the checks for the service."""
     data = list()
     columns = [
         'Name',
         'Category',
         'Description',
         'Tool used',
         #'# Commands',
     ]
     for category in self.categories:
         for check in self.checks[category]:
             color_tool = 'grey_19' if not check.tool.installed else None
             data.append([
                 check.name,
                 category,
                 check.description,
                 Output.colored(check.tool.name, color=color_tool),
                 #len(check.commands),
             ])
             
     Output.title1('Checks for service {service}'.format(service=self.service))
     Output.table(columns, data, hrules=False)
Beispiel #13
0
    def __run_standard_mode(self,
                            target, 
                            arguments,
                            sqlsession,
                            filter_categories, 
                            fast_mode=False,
                            attack_progress=None):
        """
        Run checks for the service in standard mode, i.e. when all or a subset of
        categories of checks must be run against the target.

        :param Target target: Target
        :param ArgumentsParser arguments: Arguments from command-line
        :param Session sqlsession: SQLAlchemy session
        :param list categories: Sorted list of categories to run
        :param enlighten.Counter attack_progress: Attack progress
        """

        # logger.info('Categories of checks that will be run: {cats}'.format(
        #     cats=', '.join(categories)))

        nb_checks = self.nb_checks()

        # Initialize sub status/progress bar
        checks_progress = manager.counter(total=nb_checks+1, 
                                          desc='', 
                                          unit='check',
                                          leave=False,
                                          bar_format=STATUSBAR_FORMAT)
        time.sleep(.5) # hack for progress bar display

        j = 1
        for category in self.categories:
            # Apply filter on categories
            if category not in filter_categories:
                continue

            Output.title1('Category > {cat}'.format(cat=category.capitalize()))

            i = 1
            for check in self.checks[category]:

                # Update status/progress bar
                status = ' +--> Current check [{cur}/{total}]: {category} > ' \
                    '{checkname}'.format(
                        cur       = j,
                        total     = nb_checks,
                        category  = check.category,
                        checkname = check.name)

                checks_progress.desc = '{status}{fill}'.format(
                    status = status,
                    fill   = ' '*(DESC_LENGTH-len(status)))
                checks_progress.update()
                if attack_progress:
                    # Hack to refresh the attack progress bar without incrementing
                    # useful if the tool run during the check has cleared the screen
                    attack_progress.refresh()


                # Run the check if and only if:
                #   - The check has not been already run for this target (except 
                #       if --recheck is specified in command-line)
                #   - Target is compliant with the check,
                #   - The tool used for the check is well installed.
                if i > 1: print()
                
                results_req = ResultsRequester(sqlsession)
                results_req.select_mission(target.service.host.mission.name)
                filter_ = Filter(FilterOperator.AND)
                filter_.add_condition(Condition(target.service.id, 
                    FilterData.SERVICE_ID))
                filter_.add_condition(Condition(check.name, FilterData.CHECK_NAME))
                results_req.add_filter(filter_)
                result = results_req.get_first_result()

                if result is None or arguments.args.recheck == True:

                    if check.check_target_compliance(target):
                        Output.title2('[{category}][Check {num:02}/{total:02}] ' \
                            '{name} > {description}'.format(
                                category    = category.capitalize(),
                                num         = j,
                                total       = nb_checks,
                                name        = check.name,
                                description = check.description))

                        if not check.tool.installed:
                            logger.warning('Skipped: the tool "{tool}" used by ' \
                                'this check is not installed yet'.format(
                                    tool=check.tool.name))
                        else:
                            try:
                                check.run(target, 
                                          arguments,
                                          sqlsession,
                                          fast_mode=fast_mode)

                            except KeyboardInterrupt:
                                print()
                                logger.warning('Check {check} skipped !'.format(
                                    check=check.name))

                    else:
                        logger.info('[{category}][Check {num:02}/{total:02}] ' \
                            '{name} > Skipped because context requirements are ' \
                            'not matching the target'.format(
                                name     = check.name,
                                category = category.capitalize(),
                                num      = j,
                                total    = nb_checks))
                        time.sleep(.2)
                else:

                    logger.info('[{category}][Check {num:02}/{total:02}] ' \
                            '{name} > Skipped because the check has already ' \
                            'been run'.format(
                                name     = check.name,
                                category = category.capitalize(),
                                num      = j,
                                total    = nb_checks))
                    time.sleep(.2)

                i += 1
                j += 1

        checks_progress.update()
        time.sleep(.5)

        checks_progress.close()
        return
    def run(self, 
            target, 
            smartmodules_loader, 
            results_requester, 
            filter_categories=None, 
            filter_checks=None, 
            fast_mode=False,
            attack_progress=None):
        """
        Run checks for the service.
        By default, all the categories of checks are runned. Otherwise, only a list of categories
        can be runned.
        :param target: Target object
        :param results_requester: ResultsRequester object
        :param filter_categories: list of categories to run (None for all)
        :param filter_checks: list of checks to run (None for all) 
        """
        categories = self.categories if filter_categories is None else filter_categories

        # Standard mode 
        # Selected/all categories of checks are run
        if filter_checks is None:
            nb_checks = self.nb_checks()

            # Initialize sub status/progress bar
            checks_progress = manager.counter(total=nb_checks+1, 
                                              desc='', 
                                              unit='check',
                                              leave=False,
                                              bar_format=STATUSBAR_FORMAT)
            time.sleep(.5) # hack for progress bar display

            j = 1
            for category in categories:
                Output.title1('Category > {cat}'.format(cat=category.capitalize()))

                i = 1
                for check in self.checks[category]:

                    # Update status/progress bar
                    status = ' +--> Current check [{cur}/{total}]: {category} > {checkname}'.format(
                        cur       = j,
                        total     = nb_checks,
                        category  = check.category,
                        checkname = check.name)
                    checks_progress.desc = '{status}{fill}'.format(
                        status = status,
                        fill   = ' '*(DESC_LENGTH-len(status)))
                    checks_progress.update()
                    if attack_progress:
                        # Hack to refresh the attack progress bar without incrementing
                        # useful if the tool run during the check has cleared the screen
                        attack_progress.refresh()


                    # Run the check if and only if:
                    #   - Check is matching context (i.e. at least one of its command is matching context),
                    #   - The tool used for the check is well installed
                    if i > 1: print()
                    if check.is_matching_context(target):
                        Output.title2('[{category}][Check {num:02}/{total:02}] {name} > {description}'.format(
                            category    = category.capitalize(),
                            num         = i,
                            total       = len(self.checks[category]),
                            name        = check.name,
                            description = check.description))

                        if not check.tool.installed:
                            logger.warning('Skipped: the tool "{tool}" used by this check is not installed yet ' \
                                '(according to config)'.format(tool=check.tool.name_display))
                        else:
                            try:
                                check.run(target, smartmodules_loader, results_requester, fast_mode=fast_mode)
                            except KeyboardInterrupt:
                                print()
                                logger.warning('Check {check} skipped !'.format(check=check.name))

                    else:
                        logger.info('[{category}][Check {num:02}/{total:02}] {name} > Skipped because target\'s context is not matching'.format(
                            name     = check.name,
                            category = category.capitalize(),
                            num      = i,
                            total    = len(self.checks[category])))
                        time.sleep(.2)
                    i += 1
                    j += 1

            checks_progress.update()
            time.sleep(.5)

            checks_progress.close()     

        # Special mode
        # User has provided list of checks to run (may be one single check)
        else:
            filter_checks = list(filter(lambda x: self.is_existing_check(x), filter_checks))
            if not filter_checks:
                logger.warning('None of the selected checks is existing for the service {service}'.format(service=target.get_service_name()))
                return

            # Initialize sub status/progress bar
            checks_progress = manager.counter(total=len(filter_checks)+1, 
                                              desc='', 
                                              unit='check',
                                              leave=False,
                                              bar_format=STATUSBAR_FORMAT)
            time.sleep(.5) # hack for progress bar display

            i = 1
            for checkname in filter_checks:
                print()
                check = self.get_check(checkname)

                # Update status/progress bar
                status = ' +--> Current check [{cur}/{total}]: {category} > {checkname}'.format(
                    cur       = i,
                    total     = len(filter_checks),
                    category  = check.category,
                    checkname = checkname)
                checks_progress.desc = '{status}{fill}'.format(
                    status = status,
                    fill   = ' '*(DESC_LENGTH-len(status)))
                checks_progress.update()
                if attack_progress:
                    # Hack to refresh the attack progress bar without incrementing
                    # useful if the tool run during the check has cleared the screen
                    attack_progress.update(incr=0, force=True) 

                # Run the check
                Output.title2('[Check {num:02}/{total:02}] {name} > {description}'.format(
                        num         = i,
                        total       = len(filter_checks),
                        name        = check.name,
                        description = check.description))
                try:
                    check.run(target, smartmodules_loader, results_requester, fast_mode=fast_mode)
                except KeyboardInterrupt:
                    print()
                    logger.warning('Check {check} skipped !'.format(check=check.name))
                i += 1     

            checks_progress.update()
            time.sleep(.5)

            checks_progress.close()