Example #1
0
    def show_command_outputs_for_check(self):
        """
        Display command outputs text for selected result/check
        This method must call only when filtering on one Result.id, i.e. 
        Condition(xxx, FilterData.CHECK_ID)
        """
        result = self.get_first_result()

        if not result:
            logger.error('Invalid check id (not existing)')
        else:
            Output.title2('Results for check {category} > {check}:'.format(
                category=result.category, check=result.check))

            if result.service.host.hostname:
                hostname = ' (' + result.service.host.hostname + ')'
            else:
                hostname = ''

            Output.title2('Target: host={ip}{hostname} | port={port}/{proto} | ' \
                'service {service}'.format(
                ip       = result.service.host.ip,
                hostname = hostname,
                port     = result.service.port,
                proto    = {Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                    result.service.protocol),
                service  = result.service.name))

            print()
            for o in result.command_outputs:
                Output.title3(o.cmdline)
                print()
                print(o.output)
                print()
Example #2
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
Example #3
0
    def show(self):
        """Display selected results"""
        results = self.get_results()

        Output.title2('Attacks results:')

        if not results:
            logger.warning('No results to display')
        else:
            data = list()
            columns = [
                'IP',
                'Port',
                'Proto',
                'Service',
                'Check id',
                'Category',
                'Check',
                '# Commands run',
            ]
            for r in results:
                data.append([
                    r.service.host.ip,
                    r.service.port,
                    {
                        Protocol.TCP: 'tcp',
                        Protocol.UDP: 'udp'
                    }.get(r.service.protocol),
                    r.service.name,
                    r.id,
                    r.category,
                    r.check,
                    len(r.command_outputs),
                ])
            Output.table(columns, data, hrules=False)
Example #4
0
    def show_command_outputs(self, result_id):
        result_check = self.sqlsess.query(Result).join(Service).join(
            Host).filter(Result.id == result_id).first()
        if not result_check:
            logger.error('Invalid check id')
            return

        command_outputs = self.sqlsess.query(CommandOutput).filter(
            CommandOutput.result_id == result_id).all()

        Output.title2('Results for check {category} > {check}:'.format(
            category=result_check.category, check=result_check.check))
        Output.title2(
            'Target: host={ip}{hostname} | port={port}/{proto} | service {service}'
            .format(ip=result_check.service.host.ip,
                    hostname=' (' + result_check.service.host.hostname +
                    ')' if result_check.service.host.hostname else '',
                    port=result_check.service.port,
                    proto={
                        Protocol.TCP: 'tcp',
                        Protocol.UDP: 'udp'
                    }.get(result_check.service.protocol),
                    service=result_check.service.name))

        print()
        for o in command_outputs:
            Output.title3(o.cmdline)
            print()
            print(o.output)
            print()
Example #5
0
    def remove_tool(self, tool_name):
        """
        Remove one tool from the toolbox.

        :param str tool_name: Name of the tool to remove
        :return: Status of removal
        :rtype: bool
        """
        tool = self.get_tool(tool_name)
        if not tool:
            logger.warning('No tool with this name in the toolbox')
            return False
        else:
            Output.title2('Remove {tool_name}:'.format(tool_name=tool.name))
            return tool.remove(self.settings)
Example #6
0
    def update_tool(self, tool_name, fast_mode=False):
        """
        Update one tool from the toolbox.

        :param str tool_name: Name of the tool to update
        :param bool fast_mode: Set to true to disable prompts and install checks
        :return: Status of update
        :rtype: bool
        """
        tool = self.get_tool(tool_name)
        if not tool:
            logger.warning('No tool with this name in the toolbox')
            return False
        else:
            Output.title2('Update {tool_name}:'.format(tool_name=tool.name))
            return tool.update(self.settings, fast_mode)
    def show_search_results(self, string, nb_words=12):
        """
        Display command outputs search results.
        For good readability, only some words surrounding the search string are 
        displayed.

        :param str string: Search string (accepts wildcard "%")
        :param int nb_words: Number of words surrounding the search string to show
        """
        results = self.query.filter(CommandOutput.output.ilike('%'+string+'%'))
        if not results:
            logger.error('No result')
        else:
            Output.title2('Search results:')

            data = list()
            columns = [
                'IP',
                'Port',
                'Proto',
                'Service',
                'Check id',
                'Category',
                'Check',
                'Matching text',
            ]
            for r in results:
                match = StringUtils.surrounding_text(r.outputraw, string, nb_words)
                # There might have several matches in one command result (one row
                # per match)
                for m in match:
                    data.append([
                        r.result.service.host.ip,
                        r.result.service.port,
                        {Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get(
                            r.result.service.protocol),
                        r.result.service.name,
                        r.result.id,
                        r.result.category,
                        r.result.check,
                        StringUtils.wrap(m, 70),
                    ])

        print()
        Output.table(columns, data, hrules=False)
Example #8
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))
Example #9
0
    def show_results(self, service_id):
        service = self.sqlsess.query(Service).filter(
            Service.id == service_id).first()
        if not service:
            logger.error('Invalid service id')
        else:

            Output.title2('Attacks results:')
            Output.title2(
                'Target: host={ip}{hostname} | port={port}/{proto} | service {service}'
                .format(ip=service.host.ip,
                        hostname=' (' + service.host.hostname +
                        ')' if service.host.hostname else '',
                        port=service.port,
                        proto={
                            Protocol.TCP: 'tcp',
                            Protocol.UDP: 'udp'
                        }.get(service.protocol),
                        service=service.name))

            results = self.sqlsess.query(Result).filter(
                Result.service_id == service_id).all()
            if not results:
                logger.warning('No results to display')
            else:
                data = list()
                columns = [
                    'Check id',
                    'Category',
                    'Check',
                    '# Commands',
                ]
                for r in results:
                    data.append([
                        r.id,
                        r.category,
                        r.check,
                        len(r.command_outputs),
                    ])
                Output.table(columns, data, hrules=False)
Example #10
0
    def __run_special_mode(self,
                           target, 
                           arguments,
                           sqlsession,
                           filter_checks=None, 
                           attack_profile=None,
                           fast_mode=False,
                           attack_progress=None):
        """
        Run checks for the service in special mode, i.e. when user has provided
        either an attack profile (pre-selection of checks) or a list of checks
        (may even be one single check to run)

        :param Target target: Target
        :param ArgumentsParser arguments: Arguments from command-line
        :param Session sqlsession: SQLAlchemy session
        :param list filter_checks: Selection of checks to run (default: all)
        :param AttackProfile attack_profile: Attack profile (default: no profile)
        :param bool fast_mode: Set to true to disable prompts
        :param enlighten.Counter attack_progress: Attack progress        
        """

        # User has submitted list of checks
        if filter_checks:
            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

            logger.info('Selected check(s) that will be run:')
            for c in filter_checks:
                check = self.get_check(c)
                if check:
                    Output.print('    | - {name} ({category})'.format(
                        name=c, category=check.category))

        # User has submitted an attack profile
        else:
            if not attack_profile.is_service_supported(target.get_service_name()):
                logger.warning('The attack profile {profile} is not supported for ' \
                    'target service {service}'.format(
                        profile=attack_profile, service=target.get_service_name()))
                return
            else:
                filter_checks = attack_profile.get_checks_for_service(
                    target.get_service_name())

                logger.info('Selected attack profile: {}'.format(attack_profile))


        # 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 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.

            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('[Check {num:02}/{total:02}] {name} > ' \
                        '{description}'.format(
                            num         = i,
                            total       = len(filter_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('[Check {num:02}/{total:02}] ' \
                        '{name} > Skipped because context requirements are ' \
                        'not matching the target'.format(
                            name     = check.name,
                            num      = i,
                            total    = len(filter_checks)))
                    time.sleep(.2)

            else:

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

            i += 1     

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

        checks_progress.close()  
Example #11
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()