Skip to content
Snippets Groups Projects
Commit 827aa432 authored by shadow's avatar shadow
Browse files

vulnerability descriptions with urls and markdown report generator

parent 520e7bb3
Branches
No related tags found
No related merge requests found
from .description_provider import VulnDescriptionProvider
from .description_provider import VulnDescription, VulnDescriptionProvider
from .cveproject import CveProjectProvider
from requests import Session, HTTPError
from contrib.descriptions import VulnDescriptionProvider
from contrib.descriptions import VulnDescriptionProvider, VulnDescription
__all__ = ['CveProjectProvider']
......@@ -16,7 +15,7 @@ class CveProjectProvider(VulnDescriptionProvider):
self.sess = session
self.cache = {}
def get_description(self, vuln: str, vuln_type: str) -> str:
def get_description(self, vuln: str, vuln_type: str) -> VulnDescription:
if vuln in self.cache:
return self.cache[vuln]
......@@ -30,8 +29,8 @@ class CveProjectProvider(VulnDescriptionProvider):
cve_json = response.json()
description = cve_json['description']['description_data'][0]['value']
self.cache[vuln] = description
return description
return VulnDescription(description, url)
except HTTPError as he:
return 'Description fetching error: ' + str(he)
return VulnDescription('', 'Description fetching error: ' + str(he))
return ''
return VulnDescription('', '')
import abc
from typing import Optional
__all__ = ['VulnDescriptionProvider']
__all__ = ['VulnDescriptionProvider', 'VulnDescription']
class VulnDescription:
def __init__(self, text: str, url: Optional[str] = None):
self.text = text
self.url = url
class VulnDescriptionProvider(metaclass=abc.ABCMeta):
......@@ -8,5 +15,5 @@ class VulnDescriptionProvider(metaclass=abc.ABCMeta):
Provides extended vulnerability description by vulnerablity identifier and type
"""
@abc.abstractmethod
def get_description(self, vuln: str, vuln_type: str) -> str:
def get_description(self, vuln: str, vuln_type: str) -> VulnDescription:
pass
from collections import defaultdict
from typing import List, Dict
__all__ = ['SeverityLevels', 'Vuln', 'ScanResult']
......@@ -46,5 +46,5 @@ class ScanResult:
Scan result representation
"""
def __init__(self):
self.locations = defaultdict(list)
self.vulns = []
self.locations = defaultdict(list) # type: Dict[str, List[str]]
self.vulns = [] # type: List[Vuln]
from .report_builder import ReportBuilder
from .latex_report_builder import LatexReportBuilder
from .markdown_report_builder import MarkdownReportBuilder
......@@ -42,7 +42,8 @@ class LatexReportBuilder(ReportBuilder):
locations = report.locations
num_vulns = len(vulns)
for i, v in enumerate(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]{'
......@@ -50,10 +51,10 @@ class LatexReportBuilder(ReportBuilder):
+ '} \\begin{tabular}{@{}p{15cm}>{\\raggedleft\\arraybackslash} p{0.5cm}@{}}\\textbf{'
+ v.name + ' ' + severity_name + ' ('
+ str(v.severity)
+ ')} & \href{https://nvd.nist.gov/vuln/detail/'
+ v.name + '}{\large \\faicon{link}}'
+ ')} & \href{' + description.url
+ '}{\large \\faicon{link}}'
+ '\end{tabular}\\\\\n Summary:'
+ self.description_provider.get_description(v.name, v.vuln_type)
+ description.text
+ '\\\\ \hline \end{tabular} ')
self._append('\end{figure}\n')
......
from datetime import datetime
from typing import Any, Dict, List
from contrib.descriptions import VulnDescriptionProvider
from contrib.internal_types import ScanResult
from contrib.report_builders import ReportBuilder
__all__ = ['MarkdownReportBuilder']
class MarkdownReportBuilder(ReportBuilder):
def __init__(self, description_provider: VulnDescriptionProvider):
self.description_provider = description_provider
self._buffer = ''
def init_report(self, start_date: str, nmap_command: str):
self._append_line(self.header)
self._append_line('## {date:%B %d, %Y}'.format(date=datetime.utcnow()))
self._append_line('### **Summary**')
self._append_line('Flan Scan ran a network vulnerability scan with the following Nmap command on {date}'
.format(date=start_date))
self._append_line('`{command}`'.format(command=nmap_command))
def build(self) -> Any:
return self._buffer
def add_vulnerable_section(self):
self._append_line('### Services with vulnerabilities')
def add_non_vulnerable_section(self):
self._append_line('### Services with no *known* vulnerabilities')
def add_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
for i, pair in enumerate(scan_results.items(), start=1):
app_name, report = pair # type: str, ScanResult
self._append_service(i, app_name)
num_vulns = len(report.vulns)
for v in report.vulns:
description = self.description_provider.get_description(v.name, v.vuln_type)
self._append_line('- [**{name}** {severity} ({severity_num})]({link} "{title}")'
.format(name=v.name, severity=v.severity_str, severity_num=v.severity,
link=description.url, title=v.name), spaces=4)
self._append_line('```text', separators=1, spaces=6)
self._append_line(description.text, separators=1, spaces=6)
self._append_line('```', spaces=6)
self._append_line('The above {num} vulnerabilities apply to these network locations'.format(num=num_vulns),
spaces=4)
self._append_line('```text', separators=1, spaces=4)
for addr, ports in report.locations.items():
self._append_location(addr, ports, spaces=4)
self._append_line('```', spaces=4)
def add_non_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
for i, pair in enumerate(scan_results.items(), start=1):
app_name, report = pair # type: str, ScanResult
self._append_service(i, app_name)
for addr, ports in report.locations.items():
self._append_location(addr, ports, spaces=4)
self._append('\n')
def initialize_section(self):
pass
def add_ips_section(self):
self._append_line('### List of IPs Scanned')
def add_ip_address(self, ip: str):
self._append_line('- {ip}'.format(ip=ip), separators=1)
def finalize(self):
pass
@property
def header(self) -> Any:
return '# Flan scan report'
def _append(self, text: str, spaces: int = 0):
if spaces:
self._buffer += ' ' * spaces
self._buffer += text
def _append_line(self, text: str, separators: int = 2, spaces: int = 0):
self._append(text, spaces)
self._append('\n' * separators)
def _append_service(self, index: int, name: str, spaces: int = 0):
self._append_line('{index}. **{service}**'.format(index=index, service=name.strip()), spaces=spaces,
separators=1)
def _append_location(self, address: str, ports: List[str], spaces: int):
self._append_line('- {address} Ports: {ports}'.format(address=address, ports=', '.join(ports)), spaces=spaces,
separators=1)
......@@ -6,7 +6,7 @@ from requests import Session
from contrib.descriptions import CveProjectProvider
from contrib.parsers import FlanXmlParser
from contrib.report_builders import ReportBuilder, LatexReportBuilder
from contrib.report_builders import ReportBuilder, LatexReportBuilder, MarkdownReportBuilder
def create_report(parser: FlanXmlParser, builder: ReportBuilder, nmap_command: str, start_date: str, output_writer: IO,
......@@ -38,12 +38,15 @@ def parse_nmap_command(raw_command: str) -> str:
return ' '.join(nmap_split)
def create_default_provider():
return CveProjectProvider(Session())
def create_report_builder(report_type: str) -> ReportBuilder:
if report_type == 'latex':
session = Session()
description_provider = CveProjectProvider(session)
report_bilder = LatexReportBuilder(description_provider)
return report_bilder
return LatexReportBuilder(create_default_provider())
if report_type == 'md':
return MarkdownReportBuilder(create_default_provider())
raise NotImplementedError(report_type)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment