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_results_page(self, service): """ Generate HTML code that contains command outputs of all the checks that have been run for the specified service. :param Service service: Service Model """ tpl = FileUtils.read(REPORT_TPL_DIR + '/results.tpl.html') # service_string = 'host <span class="font-weight-bold">{ip}</span> | ' \ # 'port <span class="font-weight-bold">{port}/{proto}</span> | ' \ # 'service <span class="font-weight-bold">{service}</span>'.format( # ip=str(service.host.ip), # port=service.port, # proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get( # service.protocol), # service=service.name) tpl = tpl.replace('{{MISSION_NAME}}', self.mission) tpl = tpl.replace('{{SERVICE_ICON}}', IconsMapping.get_icon_html('service', service.name)) tpl = tpl.replace('{{SERVICE_IP}}', str(service.host.ip)) tpl = tpl.replace('{{SERVICE_PORT}}', str(service.port)) tpl = tpl.replace('{{SERVICE_PROTO}}', { Protocol.TCP: 'tcp', Protocol.UDP: 'udp' }.get(service.protocol)) tpl = tpl.replace('{{SERVICE_NAME}}', service.name) tpl = tpl.replace('{{SIDEBAR_CHECKS}}', self.__generate_sidebar_checks(service)) tpl = tpl.replace('{{RESULTS}}', self.__generate_command_outputs(service)) return tpl
def __generate_table_products(self): """ Generate the table with all products registered in the mission """ req = ProductsRequester(self.sqlsession) req.select_mission(self.mission) products = req.get_results() if len(products) == 0: html = """ <tr class="notfound"> <td colspan="7">No record found</td> </tr> """ else: html = '' for product in products: # Service name service_name = IconsMapping.get_icon_html( 'service', product.service.name) service_name += str(product.service.name) html += """ <tr> <td>{ip}</td> <td>{hostname}</td> <td>{service}</td> <td>{port} /{proto}</td> <td class="font-weight-bold">{producttype}</td> <td class="font-weight-bold text-green">{productname}</td> <td class="font-weight-bold text-green">{productversion}</td> </tr> """.format( ip=product.service.host.ip, hostname=product.service.host.hostname \ if product.service.host.hostname != str(product.service.host.ip)\ else '', service=service_name, port=product.service.port, proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get( product.service.protocol), producttype=product.type, productname=product.name, productversion=product.version) return html
def __generate_table_options(self): """ Generate the table with all context-specific options registered in the mission """ req = OptionsRequester(self.sqlsession) req.select_mission(self.mission) options = req.get_results() if len(options) == 0: html = """ <tr class="notfound"> <td colspan="6">No record found</td> </tr> """ else: html = '' for option in options: # Service name service_name = IconsMapping.get_icon_html( 'service', option.service.name) service_name += str(option.service.name) html += """ <tr> <td>{ip}</td> <td>{hostname}</td> <td>{service}</td> <td>{port} /{proto}</td> <td class="font-weight-bold text-green">{optionname}</td> <td class="font-weight-bold text-green">{optionvalue}</td> </tr> """.format( ip=option.service.host.ip, hostname=option.service.host.hostname \ if option.service.host.hostname != str(option.service.host.ip) \ else '', service=service_name, port=option.service.port, proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get( option.service.protocol), optionname=option.name, optionvalue=option.value) return html
def __generate_table_vulns(self): """ Generate the table with all vulnerabilities registered in the mission """ req = VulnsRequester(self.sqlsession) req.select_mission(self.mission) vulnerabilities = req.get_results() if len(vulnerabilities) == 0: html = """ <tr class="notfound"> <td colspan="4">No record found</td> </tr> """ else: html = '' for vuln in vulnerabilities: # Service name service_name = IconsMapping.get_icon_html( 'service', vuln.service.name) service_name += str(vuln.service.name) html += """ <tr> <td>{ip}</td> <td>{service}</td> <td>{port} /{proto}</td> <td>{vulnerability}</td> </tr> """.format(ip=vuln.service.host.ip, service=service_name, port=vuln.service.port, proto={ Protocol.TCP: 'tcp', Protocol.UDP: 'udp' }.get(vuln.service.protocol), vulnerability=vuln.name) 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: # 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 __generate_table_credentials(self): """ Generate the table with all credentials registered in the mission """ req = CredentialsRequester(self.sqlsession) req.select_mission(self.mission) credentials = req.get_results() if len(credentials) == 0: html = """ <tr class="notfound"> <td colspan="9">No record found</td> </tr> """ else: html = '' for cred in credentials: # Service name service_name = IconsMapping.get_icon_html( 'service', cred.service.name) service_name += str(cred.service.name) # Add color to username/password username = '******' if cred.username == '' else cred.username username = '******'.format( color='green' if cred.password is not None else 'yellow', username=username) password = { '': '<empty>', None: '<???>' }.get(cred.password, cred.password) password = '******'.format( color='green' if cred.password is not None else 'yellow', password=password) html += """ <tr> <td>{ip}</td> <td>{hostname}</td> <td>{service}</td> <td>{port} /{proto}</td> <td>{type}</td> <td class="font-weight-bold">{username}</td> <td class="font-weight-bold">{password}</td> <td>{url}</td> <td>{comment}</td> </tr> """.format( ip=cred.service.host.ip, hostname=cred.service.host.hostname \ if cred.service.host.hostname != str(cred.service.host.ip)\ else '', service=service_name, port=cred.service.port, proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get( cred.service.protocol), type=cred.type or '', username=username, password=password, url='<a href="{}" title="{}">{}</a>'.format( cred.service.url, cred.service.url, StringUtils.shorten(cred.service.url, 50)) \ if cred.service.url else '', comment=cred.comment) return html
def __generate_table_hosts(self): """ Generate the table with all hosts registered in the mission """ req = HostsRequester(self.sqlsession) req.select_mission(self.mission) hosts = req.get_results() if len(hosts) == 0: html = """ <tr class="notfound"> <td colspan="10">No record found</td> </tr> """ else: html = '' for host in hosts: # OS os = IconsMapping.get_icon_html('os_family', host.os_family) os += str(host.os) # Device type device_type = IconsMapping.get_icon_html( 'device_type', host.type) device_type += str(host.type) # Number of creds nb_userpass = host.get_nb_credentials(single_username=False) nb_usernames = host.get_nb_credentials(single_username=True) nb_creds = '{}{}{}'.format( '<span class="text-green">{}</span>'.format(str(nb_userpass)) \ if nb_userpass > 0 else '', '/' if nb_userpass > 0 and nb_usernames > 0 else '', '<span class="text-yellow">{}</span>'.format( str(nb_usernames)) if nb_usernames > 0 else '') # Number of vulns nb_vulns = host.get_nb_vulns() if nb_vulns > 0: nb_vulns = '<span class="text-green">{}</span>'.format( nb_vulns) else: nb_vulns = '' html += """ <tr> <td class="font-weight-bold">{ip}</td> <td>{hostname}</td> <td>{os}</td> <td>{type}</td> <td>{vendor}</td> <td>{comment}</td> <td>{nb_tcp}</td> <td>{nb_udp}</td> <td>{nb_creds}</td> <td>{nb_vulns}</td> </tr> """.format(ip=host.ip, hostname=host.hostname if host.hostname != str(host.ip) else '', os=os, type=device_type, vendor=host.vendor, comment=host.comment, nb_tcp=host.get_nb_services(Protocol.TCP) or '', nb_udp=host.get_nb_services(Protocol.UDP) or '', nb_creds=nb_creds, nb_vulns=nb_vulns) return html
def __generate_table_services(self): """ Generate the table with all services registered in the mission """ req = ServicesRequester(self.sqlsession) req.select_mission(self.mission) services = req.get_results() if len(services) == 0: html = """ <tr class="notfound"> <td colspan="12">No record found</td> </tr> """ else: html = '' for service in services: hostname = service.host.hostname \ if service.host.ip != service.host.hostname else '' # Number of checks if len(service.results) > 0: nb_checks = len(service.results) else: nb_checks = '<span class="mdi mdi-window-close"></span>' # Number of creds nb_userpass = service.get_nb_credentials(single_username=False) nb_usernames = service.get_nb_credentials(single_username=True) nb_creds = '{}{}{}'.format( '<span class="text-green">{}</span>'.format(str(nb_userpass)) \ if nb_userpass > 0 else '', '/' if nb_userpass > 0 and nb_usernames > 0 else '', '<span class="text-yellow">{}</span>'.format( str(nb_usernames)) if nb_usernames > 0 else '') #if nb_creds == '': # nb_creds = '<span class="mdi mdi-window-close"></span>' # Number of vulns if len(service.vulns) > 0: nb_vulns = '<span class="text-green">{}</span>'.format( len(service.vulns)) else: #nb_vulns = '<span class="mdi mdi-window-close"></span>' nb_vulns = '' # Encrypted ? (SSL/TLS) enc = '<span class="mdi mdi-lock" title="SSL/TLS encrypted"></span>' \ if service.is_encrypted() else '' # Service name service_name = IconsMapping.get_icon_html( 'service', service.name) service_name += str(service.name) # Technologies technos = '' # For HTTP, respect a given order for technos for better readability if service.name == 'http': product_types = ( 'web-server', 'web-appserver', # 'web-application-firewall', Displayed only in "web" tab # for better readability 'web-cms', 'web-language', 'web-framework', 'web-jslib') for t in product_types: product = service.get_product(t) if product: technos += '<span class="badge badge-{type} badge-light">' \ '{name}{version}</span>'.format( type=t, name=product.name, version=' '+str(product.version) \ if product.version else '') else: for p in service.products: technos += '<span class="badge badge-generic badge-light">' \ '{name}{version}</span>'.format( type=p.type, name=p.name, version=' '+str(p.version) if p.version else '') # Col "Comment/Title" (title is for HTML title for HTTP) if service.html_title: comment = service.html_title else: comment = service.comment # Results HTML page name results = 'results-{ip}-{port}-{service}-{id}.html'.format( ip=str(service.host.ip), port=service.port, service=service.name, id=service.id) html += """ <tr{clickable}> <td class="font-weight-bold">{ip}</td> <td>{hostname}</th> <td class="font-weight-bold">{port} /{proto}</td> <td>{service}</td> <td>{enc}</td> <td>{banner}</td> <td>{technos}</td> <td>{url}</td> <td>{comment}</td> <td>{nb_checks}</td> <td>{nb_creds}</td> <td>{nb_vulns}</td> </tr> """.format( clickable=' class="clickable-row" data-href="{results}"'.format( results=results) if len(service.results) > 0 else '', ip=service.host.ip, hostname=hostname, port=service.port, proto={Protocol.TCP: 'tcp', Protocol.UDP: 'udp'}.get( service.protocol), service=service_name, enc=enc, banner=service.banner, technos=technos, url='<a href="{}" title="{}">{}</a>'.format( service.url, service.url, StringUtils.shorten(service.url, 40)) \ if service.url else '', comment=StringUtils.shorten(comment, 40), nb_checks=nb_checks, nb_creds=nb_creds, nb_vulns=nb_vulns) return html