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
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()
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
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
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()
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