from typing import Any, Dict from contrib.descriptions import VulnDescriptionProvider from contrib.report_builders import ReportBuilder from contrib.internal_types import ScanResult, SeverityLevels __all__ = ['LatexReportBuilder'] class LatexReportBuilder(ReportBuilder): """ Report builer for LaTeX format. Returns raw contents as string """ def __init__(self, description_provider: VulnDescriptionProvider): """ :param description_provider: A provider of vulnerability full description """ self.description_provider = description_provider self.buffer = self.header self.colors = {SeverityLevels.High: 'FD6864', SeverityLevels.Medium: 'F8A102', SeverityLevels.Low: '34CDF9'} def init_report(self, start_date: str, nmap_command: str): self._append('Flan Scan ran a network vulnerability scan with the following Nmap command on ' + start_date + 'UTC.\n\\begin{lstlisting}\n' + nmap_command + '\n\\end{lstlisting}\nTo find out what IPs were scanned see the end of this report.\n') def build(self) -> Any: return self.buffer @property def header(self) -> str: return self.report_header def add_vulnerable_services(self, scan_results: Dict[str, ScanResult]): for s, report in scan_results.items(): self._append('\\item \\textbf{\\large ' + s + ' \\large}') vulns = report.vulns locations = report.locations num_vulns = len(vulns) for v in vulns: description = self.description_provider.get_description(v.name, v.vuln_type) severity_name = v.severity_str self._append('\\begin{figure}[h!]\n') self._append('\\begin{tabular}{|p{16cm}|}\\rowcolor[HTML]{' + self.colors[severity_name] + '} \\begin{tabular}{@{}p{15cm}>{\\raggedleft\\arraybackslash} p{0.5cm}@{}}\\textbf{' + v.name + ' ' + severity_name + ' (' + str(v.severity) + ')} & \\href{' + description.url + '}{\\large \\faicon{link}}' + '\\end{tabular}\\\\\n Summary:' + description.text + '\\\\ \\hline \\end{tabular} ') self._append('\\end{figure}\n') self._append('\\FloatBarrier\n\\textbf{The above ' + str(num_vulns) + ' vulnerabilities apply to these network locations:}\n\\begin{itemize}\n') for addr in locations: self._append('\\item ' + addr + ' Ports: ' + str(locations[addr]) + '\n') self._append('\\\\ \\\\ \n \\end{itemize}\n') self._append('\\end{enumerate}\n') def add_non_vulnerable_services(self, scan_results: Dict[str, ScanResult]): for app_name, result in scan_results.items(): self._append('\\item \\textbf{\\large ' + app_name + ' \\large}\n\\begin{itemize}\n') locations = result.locations for addr in locations: self._append('\\item ' + addr + ' Ports: ' + str(locations[addr]) + '\n') self._append('\\end{itemize}\n') self._append('\\end{enumerate}\n') def initialize_section(self): self._append('\\begin{enumerate}[wide, labelwidth=!, labelindent=0pt, label=\\textbf{\\large \\arabic{enumi} ' '\\large}]\n') def add_vulnerable_section(self): self._append('\\section*{Services with Vulnerabilities}') def add_non_vulnerable_section(self): self._append('\\section*{Services With No Known Vulnerabilities}') def add_ips_section(self): self._append('\\section*{List of IPs Scanned}') self._append('\\begin{itemize}\n') def add_ip_address(self, ip: str): self._append('\\item ' + ip + '\n') def finalize(self): self._append('\\end{itemize}\n') self._append('\\end{document}') def _append(self, text: str): self.buffer += text # Don't want to depend on external file since this header is not so big. report_header = r"""\documentclass{article} \usepackage{enumitem} \usepackage[margin=1in]{geometry} \usepackage[utf8]{inputenc} \usepackage[table,xcdraw]{xcolor} \usepackage{placeins} \usepackage{hyperref} \usepackage{fontawesome} \usepackage{listings} \extrafloats{600} \maxdeadcycles 600 \lstset{ basicstyle=\small\ttfamily, columns=flexible, breaklines=true } \title{Flan Scan Report\\} \date{\today} \begin{document} \maketitle \section*{Summary} """