Projects STRLCPY flan Commits 8f103c1d
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    Makefile
    skipped 4 lines
    5 5  start :
    6 6   docker run --name $(container_name) -v "$(CURDIR)/shared:/shared:Z" flan_scan
    7 7   
     8 +md :
     9 + docker run --name $(container_name) -v "$(CURDIR)/shared:/shared:Z" -e format=md flan_scan
     10 + 
     11 +html :
     12 + docker run --name $(container_name) -v "$(CURDIR)/shared:/shared:Z" -e format=html flan_scan
     13 + 
     14 +json :
     15 + docker run --name $(container_name) -v "$(CURDIR)/shared:/shared:Z" -e format=json flan_scan
  • ■ ■ ■ ■ ■
    README.md
    skipped 25 lines
    26 26  $ make start
    27 27  ```
    28 28   
     29 +6. To use another output format:
     30 +```
     31 +$ make html
     32 +```
     33 +Additional supported formats are *md* (markdown), *html* and *json*.
     34 + 
    29 35  When the scan finishes you will find a Latex report of the summarizing the scan in `shared/reports`. You can also see the raw XML output from Nmap in `shared/xml_files`.
    30 36   
    31 37  <div>
    skipped 10 lines
    42 48  ```
    43 49  The `-oX` flag adds an XML version of the scan results to the `/shared/xml_files` directory and the `-oN -` flag outputs "normal" Nmap results to the console. The `-v1` flag increases the verbosity to 1 and the `-sV` flag runs a service detection scan (aside from Nmap's default port and SYN scans). The `--script=vulners/vulners.nse` is the script that matches the services detected with relevant CVEs.
    44 50   
    45  -Nmap also allows you to run UDP scans and to scan IPv6 addresses. To add these and other flags to Scan Flan's Nmap command after running `make build` run the container and pass in you Nmap flags like so:
     51 +Nmap also allows you to run UDP scans and to scan IPv6 addresses. To add these and other flags to Scan Flan's Nmap command after running `make build` run the container and pass in your Nmap flags like so:
    46 52   
    47 53  ```bash
    48 54  $ docker run -v $(pwd)/shared:/shared flan_scan <Nmap-flags>
    skipped 8 lines
    57 63   -v $(pwd)/shared:/shared \
    58 64   -e upload=<gcp or aws> \
    59 65   -e bucket=<bucket-name> \
     66 + -e format=<optional, one of: md, html or json> \
    60 67   flan_scan
    61 68  ```
    62 69   
    skipped 50 lines
  • ■ ■ ■ ■ ■ ■
    contrib/internal_types/flan_types.py
    skipped 21 lines
    22 22   self.vuln_type = vuln_type
    23 23   self.severity = severity
    24 24   
     25 + def to_dict(self):
     26 + return {
     27 + 'name': self.name,
     28 + 'type': self.vuln_type,
     29 + 'severity': self.severity,
     30 + 'severity_str': self.severity_str
     31 + }
     32 + 
    25 33   @staticmethod
    26 34   def convert_severity(severity: float) -> str:
    27 35   """
    skipped 24 lines
  • ■ ■ ■ ■ ■ ■
    contrib/report_builders/__init__.py
    1 1  from .report_builder import ReportBuilder
    2 2  from .latex_report_builder import LatexReportBuilder
    3 3  from .markdown_report_builder import MarkdownReportBuilder
     4 +from .json_report_builder import JsonReportBuilder
     5 +from .html_report_builder import JinjaHtmlReportBuilder
    4 6   
  • ■ ■ ■ ■ ■ ■
    contrib/report_builders/html_report_builder.py
     1 +import os
     2 +from typing import Any
     3 + 
     4 +from jinja2 import Template, FileSystemLoader, Environment
     5 + 
     6 +from contrib.descriptions import VulnDescriptionProvider
     7 +from contrib.report_builders import JsonReportBuilder
     8 + 
     9 + 
     10 +class JinjaHtmlReportBuilder(JsonReportBuilder):
     11 + def __init__(self, description_provider: VulnDescriptionProvider):
     12 + super().__init__(description_provider)
     13 + self.template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
     14 + self.template_name = 'jinja2_report.html'
     15 + self._read_template() # type: Template
     16 + 
     17 + def build(self) -> Any:
     18 + return self._template.render(data=self._buffer)
     19 + 
     20 + def _read_template(self):
     21 + template_loader = FileSystemLoader(searchpath=self.template_path)
     22 + template_env = Environment(loader=template_loader, autoescape=True)
     23 + self._template = template_env.get_template(self.template_name)
     24 + 
  • ■ ■ ■ ■ ■ ■
    contrib/report_builders/json_report_builder.py
     1 +import json
     2 +from typing import Any, Dict, List
     3 + 
     4 +from contrib.descriptions import VulnDescriptionProvider
     5 +from contrib.internal_types import ScanResult
     6 +from contrib.report_builders import ReportBuilder
     7 + 
     8 + 
     9 +class JsonReportBuilder(ReportBuilder):
     10 + def __init__(self, description_provider: VulnDescriptionProvider):
     11 + self.description_provider = description_provider
     12 + self._buffer = {'ips': [], 'vulnerable': {}, 'not_vulnerable': {}}
     13 + 
     14 + def init_report(self, start_date: str, nmap_command: str):
     15 + self._buffer['start_date'] = start_date
     16 + self._buffer['nmap_command'] = nmap_command
     17 + 
     18 + def build(self) -> Any:
     19 + return json.dumps(self._buffer)
     20 + 
     21 + def add_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
     22 + for app_name, result in scan_results.items():
     23 + self._buffer['vulnerable'][app_name] = {
     24 + 'vulnerabilities': [],
     25 + 'locations': self._serialize_locations(result.locations)
     26 + }
     27 + 
     28 + for v in result.vulns:
     29 + data = v.to_dict()
     30 + description = self.description_provider.get_description(v.name, v.vuln_type)
     31 + data['description'], data['url'] = description.text, description.url
     32 + self._buffer['vulnerable'][app_name]['vulnerabilities'].append(data)
     33 + 
     34 + def add_non_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
     35 + for app_name, result in scan_results.items():
     36 + self._buffer['not_vulnerable'][app_name] = {
     37 + 'locations': self._serialize_locations(result.locations)
     38 + }
     39 + 
     40 + def add_ip_address(self, ip: str):
     41 + self._buffer['ips'].append(ip)
     42 + 
     43 + @staticmethod
     44 + def _serialize_locations(locations: Dict[str, List[str]]):
     45 + return {loc: [int(port) for port in ports] for loc, ports in locations.items()}
     46 + 
  • ■ ■ ■ ■ ■ ■
    contrib/report_builders/report_builder.py
    skipped 7 lines
    8 8   
    9 9   
    10 10  class ReportBuilder(metaclass=abc.ABCMeta):
    11  - @abc.abstractmethod
    12 11   def init_report(self, start_date: str, nmap_command: str):
    13 12   """
    14 13   Creates document section with report overview
    15 14   """
    16 15   pass
    17 16   
    18  - @abc.abstractmethod
    19 17   def build(self) -> Any:
    20 18   """
    21 19   :return: Ready report in specific format
    22 20   """
    23 21   pass
    24 22   
    25  - @abc.abstractmethod
    26 23   def add_vulnerable_section(self):
    27 24   """
    28 25   Adds header for section with vulnerable services
    29 26   """
    30 27   pass
    31 28   
    32  - @abc.abstractmethod
    33 29   def add_non_vulnerable_section(self):
    34 30   """
    35 31   Adds header for section with services without detected vulnerabilities
    36 32   """
    37 33   pass
    38 34   
    39  - @abc.abstractmethod
    40 35   def add_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
    41 36   """
    42 37   Adds descriptions of vulnerable services
    43 38   """
    44 39   pass
    45 40   
    46  - @abc.abstractmethod
    47 41   def add_non_vulnerable_services(self, scan_results: Dict[str, ScanResult]):
    48 42   """
    49 43   Adds descriptions of services without detected vulnerabilities
    50 44   """
    51 45   pass
    52 46   
    53  - @abc.abstractmethod
    54 47   def initialize_section(self):
    55 48   """
    56 49   Adds begin of report section
    57 50   """
    58 51   pass
    59 52   
    60  - @abc.abstractmethod
    61 53   def add_ips_section(self):
    62 54   """
    63 55   Adds section with list of scanned ip addresses
    64 56   """
    65 57   pass
    66 58   
    67  - @abc.abstractmethod
    68 59   def add_ip_address(self, ip: str):
    69 60   """
    70 61   Adds IP-address to scanned addresses section
    71 62   """
    72 63   pass
    73 64   
    74  - @abc.abstractmethod
    75 65   def finalize(self):
    76 66   """
    77 67   Adds report footer
    78 68   """
    79 69   pass
    80 70   
    81  - @property
    82  - @abc.abstractmethod
    83  - def header(self) -> Any:
    84  - """
    85  - :return: Common document header for format type (e.g. for latex report)
    86  - """
    87  - pass
    88  - 
  • ■ ■ ■ ■ ■ ■
    contrib/report_builders/templates/jinja2_report.html
     1 +<html lang="en">
     2 +<head>
     3 + <title>Flan scan report</title>
     4 + 
     5 + <style type="text/css">
     6 + body {
     7 + margin: 22pt;
     8 + }
     9 + 
     10 + h1, h2, h3 {
     11 + text-align: center;
     12 + }
     13 + 
     14 + #summary_review, #command {
     15 + font-size: 18px;
     16 + }
     17 + 
     18 + #command code {
     19 + font-family: Monospaced, monospace;
     20 + font-weight: bolder;
     21 + color: darkslategray;
     22 + }
     23 + 
     24 + .section_head {
     25 + font-family: 'helvetica', san-serif, serif;
     26 + font-size: 20px;
     27 + font-weight: bolder;
     28 + font-stretch: expanded;
     29 + }
     30 + 
     31 + .services_list {
     32 + font-family: 'helvetica', serif;
     33 + padding-left: 20px;
     34 + }
     35 + 
     36 + .service_cpe {
     37 + font-size: 16px;
     38 + font-family: 'helvetica', serif;
     39 + font-weight: bold;
     40 + }
     41 + 
     42 + .vuln_short {
     43 + border: 1px solid #1d1d1d;
     44 + padding: 8px 0 7px 6px;
     45 + text-align: left;
     46 + font-weight: bold;
     47 + }
     48 + 
     49 + .vuln_short a {
     50 + color: black;
     51 + }
     52 + 
     53 + .vuln_short.high {
     54 + background: #FD6865;
     55 + }
     56 + 
     57 + .vuln_short.medium {
     58 + background: #F8A101;
     59 + }
     60 + 
     61 + .vuln_short.low {
     62 + background: #33CDF9;
     63 + }
     64 + 
     65 + .vulns_list li {
     66 + display: inline-block;
     67 + padding: 10px;
     68 + vertical-align: top;
     69 + width: 100%;
     70 + margin: 10px 0 10px -60px;
     71 + border: 1px solid black;
     72 + }
     73 + 
     74 + .vuln_desc {
     75 + padding-top: 7px;
     76 + }
     77 + 
     78 + .locations_head {
     79 + font-size: 18px;
     80 + font-style: oblique;
     81 + font-weight: bold;
     82 + margin-left: -20px;
     83 + margin-bottom: 10px;
     84 + }
     85 + 
     86 + .locations_container {
     87 + margin-bottom: 20px;
     88 + }
     89 + 
     90 + .locations_list li {
     91 + margin-left: -70px;
     92 + list-style: none;
     93 + padding: 10px;
     94 + }
     95 + 
     96 + .ip_vulnerable {
     97 + font-size: 18px;
     98 + font-weight: bolder;
     99 + color: #9c0000;
     100 + }
     101 + 
     102 + .ip {
     103 + font-size: 18px;
     104 + color: #193232;
     105 + }
     106 + 
     107 + .non_vuln_service_list li {
     108 + margin-bottom: 10px;
     109 + margin-left: -40px;
     110 + list-style: none;
     111 + }
     112 + 
     113 + .service_name {
     114 + font-size: 16px;
     115 + font-family: helvetica, serif;
     116 + font-weight: bold;
     117 + margin-bottom: 5px;
     118 + }
     119 + 
     120 + .ip_list li {
     121 + margin-left: -25px;
     122 + }
     123 + </style>
     124 +</head>
     125 +<body>
     126 +<h1>Flan scan report</h1>
     127 +<h2>{{ data.start_date }}</h2>
     128 +<h2>Summary</h2>
     129 +<div id="summary_review">
     130 + Flan Scan ran a network vulnerability scan with the following Nmap command on {{ data.start_date }}:
     131 + <div id="command">
     132 + <code>{{ data.nmap_command }}</code>
     133 + </div>
     134 +</div>
     135 +<div id="vulnerable_services">
     136 + <h4 class="section_head">Services with vulnerabilities:</h4>
     137 + <ol class="services_list">
     138 + {% for service, report in data.vulnerable.items() %}
     139 + <li>
     140 + <div class="service_cpe">{{ service }}</div>
     141 + <div class="service_vulns">
     142 + <ul class="vulns_list">
     143 + {% for vuln in report.vulnerabilities %}
     144 + <li>
     145 + <div class="vuln_short {{ vuln.severity_str.lower() }}">
     146 + <a class="vuln_link"
     147 + href="{{ vuln.url }}">{{ vuln.name }}</a> {{ vuln.severity_str }}
     148 + ({{ vuln.severity }})
     149 + </div>
     150 + <div class="vuln_desc">{{ vuln.description }}</div>
     151 + </li>
     152 + {% endfor %}
     153 + </ul>
     154 + <div class="locations_container">
     155 + <div class="locations_head">The above {{ report.vulnerabilities|length }} vulnerabilities apply
     156 + to these network locations:
     157 + </div>
     158 + <ul class="locations_list">
     159 + {% for loc, ports in report.locations.items() %}
     160 + <li> <span class="ip_vulnerable"> {{ loc }} </span> Ports: <span class="ports"> {{ ports }} </span></li>
     161 + {% endfor %}
     162 + </ul>
     163 + </div>
     164 + </div>
     165 + </li>
     166 + {% endfor %}
     167 + </ol>
     168 + 
     169 +</div>
     170 +<div id="non_vuln">
     171 + <h4 class="section_head">Services with no known vulnerabilities:</h4>
     172 + <ul class="non_vuln_service_list">
     173 + {% for service, report in data.not_vulnerable.items() %}
     174 + <li>
     175 + <div class="service_name">{{ service }}</div>
     176 + <ul class="locations_list">
     177 + {% for loc, ports in report.locations.items() %}
     178 + <li><span class="ip">{{ loc }}</span> Ports: <span class="ports">{{ ports }}</span></li>
     179 + {% endfor %}
     180 + </ul>
     181 + </li>
     182 + {% endfor %}
     183 + </ul>
     184 +</div>
     185 +<div id="ips">
     186 + <div class="section_head">List of addresses scanned:</div>
     187 + <ol class="ip_list">
     188 + {% for ip in data.ips %}
     189 + <li>{{ ip }}</li>
     190 + {% endfor %}
     191 + </ol>
     192 +</div>
     193 +</body>
     194 +</html>
  • ■ ■ ■ ■ ■ ■
    kubernetes_templates/cron_job.yaml
    skipped 32 lines
    33 33   value: <GCP_OR_AWS>
    34 34   - name: bucket
    35 35   value: <BUCKET_NAME>
     36 + - name: format
     37 + value: <REPORT_FORMAT>
    36 38   
  • ■ ■ ■ ■ ■ ■
    kubernetes_templates/deployment.yaml
    skipped 34 lines
    35 35   value: <GCP_OR_AWS>
    36 36   - name: bucket
    37 37   value: <BUCKET_NAME>
     38 + - name: format
     39 + value: <REPORT_FORMAT>
    38 40   
  • ■ ■ ■ ■ ■ ■
    output_report.py
    skipped 3 lines
    4 4   
    5 5  from requests import Session
    6 6   
    7  -from contrib.descriptions import CveProjectProvider
     7 +from contrib.descriptions import CveProjectProvider, VulnDescriptionProvider
    8 8  from contrib.parsers import FlanXmlParser
    9  -from contrib.report_builders import ReportBuilder, LatexReportBuilder, MarkdownReportBuilder
     9 +from contrib.report_builders import ReportBuilder, LatexReportBuilder, MarkdownReportBuilder, JinjaHtmlReportBuilder, \
     10 + JsonReportBuilder
    10 11   
    11 12   
    12 13  def create_report(parser: FlanXmlParser, builder: ReportBuilder, nmap_command: str, start_date: str, output_writer: IO,
    skipped 13 lines
    26 27   
    27 28   builder.add_ips_section()
    28 29   for ip in ip_reader:
    29  - builder.add_ip_address(ip)
     30 + builder.add_ip_address(ip.strip())
    30 31   
    31 32   builder.finalize()
    32 33   output_writer.write(builder.build())
    skipped 5 lines
    38 39   return ' '.join(nmap_split)
    39 40   
    40 41   
    41  -def create_default_provider():
     42 +def create_default_provider() -> VulnDescriptionProvider:
    42 43   return CveProjectProvider(Session())
    43 44   
    44 45   
    45 46  def create_report_builder(report_type: str) -> ReportBuilder:
    46  - if report_type == 'latex':
    47  - return LatexReportBuilder(create_default_provider())
    48  - if report_type == 'md':
    49  - return MarkdownReportBuilder(create_default_provider())
    50  - raise NotImplementedError(report_type)
     47 + builder_map = {
     48 + 'tex': lambda p: LatexReportBuilder(p),
     49 + 'md': lambda p: MarkdownReportBuilder(p),
     50 + 'html': lambda p: JinjaHtmlReportBuilder(p),
     51 + 'json': lambda p: JsonReportBuilder(p)
     52 + }
     53 + 
     54 + if report_type not in builder_map:
     55 + raise NotImplementedError(report_type)
    51 56   
     57 + provider = create_default_provider()
     58 + return builder_map[report_type](provider)
    52 59   
    53  -def main(dirname: str, output_file: str, ip_file: str, report_type: str = 'latex'):
     60 + 
     61 +def main(dirname: str, output_file: str, ip_file: str, report_type: str = 'tex'):
    54 62   nmap_command = ''
    55 63   start_date = ''
    56 64   builder = create_report_builder(report_type)
    skipped 12 lines
    69 77   
    70 78   
    71 79  if __name__ == '__main__':
    72  - main(*sys.argv[1:4], report_type='latex')
     80 + report_format = os.getenv('format', 'tex')
     81 + main(*sys.argv[1:4], report_type=report_format)
    73 82   
  • ■ ■ ■ ■
    requirements.txt
    1 1  xmltodict==0.12.0
    2 2  google-cloud-storage==1.23.0
    3 3  boto3==1.12.15
    4  - 
     4 +Jinja2==2.10.3
  • ■ ■ ■ ■ ■
    run.sh
    skipped 9 lines
    10 10   mkdir /reports
    11 11  fi
    12 12   
     13 +report_extension="tex"
     14 + 
     15 +if [[ ! -z $format ]]
     16 +then
     17 + report_extension=$format
     18 +fi
     19 + 
    13 20  xml_dir=xml_files/$current_time
    14  -report_file=reports/report_$current_time.tex
     21 +report_file=reports/report_$current_time.$report_extension
    15 22   
    16 23  function upload {
    17 24   if [[ -z $upload ]]
    skipped 22 lines
    40 47  done < /shared/ips.txt
    41 48   
    42 49  python /output_report.py $root_dir$xml_dir $root_dir$report_file /shared/ips.txt
    43  -sed -i 's/_/\\_/g' $root_dir$report_file
    44  -sed -i 's/\$/\\\$/g' $root_dir$report_file
    45  -sed -i 's/#/\\#/g' $root_dir$report_file
    46  -sed -i 's/%/\\%/g' $root_dir$report_file
     50 +if [[ $report_extension = "tex" ]]
     51 +then
     52 + sed -i 's/_/\\_/g' $root_dir$report_file
     53 + sed -i 's/\$/\\\$/g' $root_dir$report_file
     54 + sed -i 's/#/\\#/g' $root_dir$report_file
     55 + sed -i 's/%/\\%/g' $root_dir$report_file
     56 +fi
    47 57  upload $report_file
    48 58   
Please wait...
Page is in error, reload to recover