示例#1
0
    def __generate_sidebar_checks(self, service):
        """
        Generate the sidebar with the list of checks that have been run for the
        specified service.

        :param Service service: Service Model
        """
        req = ResultsRequester(self.sqlsession)
        req.select_mission(self.mission)

        # Filter on service id
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition(service.id, FilterData.SERVICE_ID))
        req.add_filter(filter_)
        results = req.get_results()

        html = ''
        i = 0
        for r in results:

            # Icon category
            icon = IconsMapping.get_icon_html('category', r.category)

            html += """
            <li{class_}>
                <a href="#{id}">{icon}{check}</a>
            </li>  
            """.format(class_=' class="active"' if i == 0 else '',
                       id=r.check,
                       icon=icon,
                       check=StringUtils.shorten(r.check, 28))
            i += 1

        return html
示例#2
0
    def __generate_command_outputs(self, service):
        """
        Generate HTML code with all command outputs for the specified service.

        :param Service service: Service Model
        """
        req = ResultsRequester(self.sqlsession)
        req.select_mission(self.mission)

        # Filter on service id
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition(service.id, FilterData.SERVICE_ID))
        req.add_filter(filter_)
        results = req.get_results()

        html = ''
        i = 0
        for r in results:
            html += """
            <div class="tab-pane{active}" id="{id}">
                <div class="container-fluid">
                    <div class="row">
                        <div class="col-lg-12">
                            <h1 class="title-page">{category} > {check}</h1>
            """.format(active=' active' if i == 0 else '',
                       id=r.check,
                       category=r.category,
                       check=r.check)

            for o in r.command_outputs:
                # Convert command output (with ANSI codes) to HTML
                conv = ansi2html.Ansi2HTMLConverter(inline=True,
                                                    scheme='solarized',
                                                    linkify=True)
                output = conv.convert(o.output)
                # Warning: ansi2html generates HTML document with <html>, <style>...
                # tags. We only keep the content inside <pre> ... </pre>
                m = re.search('<pre class="ansi2html-content">(?P<output>.*)' \
                    '</pre>\n</body>', output, re.DOTALL)
                if m:
                    output = m.group('output')

                    html += """
                    <pre class="cmdline">{cmdline}</pre>
                    <pre>{output}</pre>
                    """.format(cmdline=o.cmdline, output=output)

            html += """
                        </div>
                    </div>
                </div>
            </div>
            """
            i += 1

        return html
    def run(self):
        args = self.arguments.args
        self.creds = defaultdict(list)
        self.users = defaultdict(list)
        self.options = defaultdict(list)

        # Load smart modules
        self.smartmodules_loader = SmartModulesLoader(self.sqlsess,
                                                      self.settings.services)

        # Initialize provided credentials
        if args.creds:
            for c in args.creds:
                self.creds[c['service']].append(
                    Credential(type=c['auth_type'],
                               username=c['username'],
                               password=c['password']))

        # Initialize provided single usernames
        if args.users:
            for u in args.users:
                self.users[c['service']].append(
                    Credential(type=u['auth_type'],
                               username=u['username'],
                               password=None))

        # Initialize provided context-specific options
        if args.specific:
            for option_name in args.specific:
                service = self.settings.services.get_service_for_specific_option(
                    option_name)
                if service:
                    self.options[service].append(
                        Option(name=option_name,
                               value=args.specific[option_name]))

        # Run the attack
        self.attack_scope = AttackScope(self.settings,
                                        ResultsRequester(self.sqlsess),
                                        self.smartmodules_loader,
                                        args.cat_only,
                                        args.checks,
                                        fast_mode=args.fast_mode)

        begin = time.time()
        if args.target_ip_or_url:
            self.__run_for_single_target(args)
        else:
            self.__run_for_multi_targets(args)

        print()
        logger.info('Done. Time spent: {0} seconds'.format(time.time() -
                                                           begin))
    def do_results(self, args):
        """Attacks results"""
        print()

        req = ResultsRequester(self.sqlsess)
        #req.select_mission(self.current_mission)

        if args.show:
            try:
                check_id = int(args.show)
            except:
                logger.error('Invalid check id')
                return
            req.show_command_outputs(check_id)
        elif args.service_id:
            try:
                service_id = int(args.service_id)
            except:
                logger.error('Invalid service id')
                return
            req.show_results(service_id)

        print()             
示例#5
0
    def __generate_command_outputs(self, service):
        """
        Generate HTML code with all command outputs for the specified service.

        :param Service service: Service Model
        """
        req = ResultsRequester(self.sqlsession)
        req.select_mission(self.mission)

        # Filter on service id
        filter_ = Filter(FilterOperator.AND)
        filter_.add_condition(Condition(service.id, FilterData.SERVICE_ID))
        req.add_filter(filter_)
        results = req.get_results()

        html = ''
        i = 0
        for r in results:

            # Icon category
            icon = IconsMapping.get_icon_html('category', r.category)

            # Description/Tool of check
            if service.name in self.settings.services:
                check = self.settings.services[
                    service.name]['checks'].get_check(r.check)
                if check is not None:
                    description = check.description
                    tool = check.tool.name
                else:
                    description = tool = ''

            html += """
            <div class="tab-pane{active}" id="{id}">
                <div class="container-fluid">
                    <div class="row">
                        <div class="col-lg-12">
                            <h1 class="title-page">{icon}{category} > {check}</h1>
                            <p class="check-description rounded">
                                <span class="mdi mdi-information-outline"></span> 
                                {description} 
                                (using tool: {tool}).
                            </p>
            """.format(active=' active' if i == 0 else '',
                       id=r.check,
                       icon=icon,
                       category=r.category,
                       check=r.check,
                       description=description,
                       tool=tool)

            for o in r.command_outputs:
                # Convert command output (with ANSI codes) to HTML
                conv = ansi2html.Ansi2HTMLConverter(inline=True,
                                                    scheme='solarized',
                                                    linkify=True)
                output = conv.convert(o.output)

                # Warning: ansi2html generates HTML document with <html>, <style>...
                # tags. We only keep the content inside <pre> ... </pre>
                m = re.search('<pre class="ansi2html-content">(?P<output>.*)' \
                    '</pre>\n</body>', output, re.DOTALL)
                if m:
                    output = m.group('output')

                    html += """
                    <pre class="cmdline rounded"># {cmdline}</pre>
                    <pre>{output}</pre>
                    """.format(cmdline=o.cmdline, output=output)

            html += """
                        </div>
                    </div>
                </div>
            </div>
            """
            i += 1

        return html
示例#6
0
    def run(self, target, arguments, sqlsession, fast_mode=False):
        """
        Run the security check.
        It consists in running commands with context requirements matching with the
        target's context.

        :param Target target: Target
        :param ArgumentsParser arguments: Arguments from command-line
        :param Session sqlsession: SQLAlchemy session
        :param SmartModulesLoader smartmodules_loader: Loader of SmartModules
        :param bool fast_mode: Set to true to disable prompts
        :return: Status
        :rtype: bool
        """
        if not self.tool.installed:
            return False

        i = 1
        command_outputs = list()
        for command in self.commands:
            if command.context_requirements.check_target_compliance(target):
                if not command.context_requirements.is_empty:
                    logger.info('Command #{num:02} matches requirements: ' \
                        '{context}'.format(num=i, context=command.context_requirements))

                cmdline = command.get_cmdline(self.tool.tool_dir, target,
                                              arguments)

                if fast_mode:
                    logger.info('Run command #{num:02}'.format(num=i))
                    mode = 'y'
                else:
                    mode = Output.prompt_choice(
                        'Run command {num}? [Y/n/f/q] '.format(
                            num='' if len(self.commands) == 1 else \
                                '#{num:02} '.format(num=i)),
                        choices={
                            'y': 'Yes',
                            'n': 'No',
                            #'t': 'New tab',
                            #'w': 'New window',
                            'f': 'Switch to fast mode (do not prompt anymore)',
                            'q': 'Quit the program',
                        },
                        default='y')

                if mode == 'q':
                    logger.warning('Exit !')
                    sys.exit(0)
                elif mode == 'n':
                    logger.info('Skipping this command')
                    continue
                else:
                    if mode == 'f':
                        logger.info('Switch to fast mode')
                        arguments.args.fast_mode = True

                    Output.begin_cmd(cmdline)
                    process = ProcessLauncher(cmdline)
                    if mode == 'y' or mode == 'f':
                        output = process.start()
                    # elif mode == 't':
                    #     output = process.start_in_new_tab()
                    #     logger.info('Command started in new tab')
                    # else:
                    #     output = process.start_in_new_window(self.name)
                    #     logger.info('Command started in new window')
                    Output.delimiter()
                    print()

                    output = StringUtils.interpret_ansi_escape_clear_lines(
                        output)
                    outputraw = StringUtils.remove_ansi_escape(output)
                    command_outputs.append(
                        CommandOutput(cmdline=cmdline,
                                      output=output,
                                      outputraw=outputraw))

                    # Run smartmodule method on output
                    postcheck = SmartPostcheck(
                        target.service, sqlsession, self.tool.name,
                        '{0}\n{1}'.format(cmdline, outputraw))
                    postcheck.run()

            else:
                logger.info('Command #{num:02} does not match requirements: ' \
                    '{context}'.format(num=i, context=command.context_requirements))
                logger.debug('Context string: {rawstr}'.format(
                    rawstr=command.context_requirements))

            i += 1

        # Add outputs in database
        if command_outputs:
            results_requester = ResultsRequester(sqlsession)
            results_requester.add_result(target.service.id, self.name,
                                         self.category, command_outputs)

        return True
示例#7
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()  
示例#8
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