diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9ea526d9f710326c7b98267b30624635e1090305 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +**.swp +wiser-wcs-reports/.idea/* +wiser-wcs-reports/env/* +wiser-wcs-reports/example_nmap_output/* + diff --git a/Dockerfile b/Dockerfile index 5fcc1c9628417abf0cada75532ae17ab383e7a55..df6977cb0fcdb56bd6846bc6b9d6304beee0bc55 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,10 +14,13 @@ COPY install/zap-plugin.patch install/w3af-plugin.patch install/cscan.patch /tmp COPY install/cscan.sh /tmp/install/ RUN chmod +x /tmp/install/cscan.sh && /tmp/install/cscan.sh +COPY wiser-wcs-reports /service/wiser-wcs-reports/ +COPY install/wiser-wcs.sh /tmp/install/ +RUN chmod +x /tmp/install/wiser-wcs.sh && /tmp/install/wiser-wcs.sh + COPY install/cleanup.sh /tmp/install/ RUN chmod +x /tmp/install/cleanup.sh && /tmp/install/cleanup.sh -COPY wiser-wcs-reports /service/wiser-wcs-reports/ COPY run-cscan.sh configure.py config-example.json /service/ RUN chmod +x /service/run-cscan.sh diff --git a/MANIFEST b/MANIFEST index e40de4a6b598f9a44da8a48446ab31c3465ecd78..63404cf9c776af5c408cfd53b4e326701fafb8d0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,3 +1,3 @@ -VERSION=v1.3.2 +VERSION=v1.3.3 SERVICE=vat-genscan diff --git a/install/wiser-wcs.sh b/install/wiser-wcs.sh new file mode 100644 index 0000000000000000000000000000000000000000..38e5129ec8fde162eb2a992e4265e09358d3bc99 --- /dev/null +++ b/install/wiser-wcs.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -e + +pip3 install -r /service/wiser-wcs-reports/requirements.txt + diff --git a/run-cscan.sh b/run-cscan.sh index abaf1b537ebfca45f0995b30815904f8712fbaa2..86d8999a588da1c960442e846752f5197fe3449b 100644 --- a/run-cscan.sh +++ b/run-cscan.sh @@ -20,7 +20,7 @@ if [ $RESULT -ne 0 ]; then fi cd /service/wiser-wcs-reports -python wiser-wcs.py | tail -n 1 > /root/out/genscan-out.json +python3 wiser-wcs.py | tail -n 1 > /root/out/genscan-out.json # outputting the scan result cat /root/out/genscan-out.json diff --git a/wiser-wcs-reports/requirements.py b/wiser-wcs-reports/requirements.py deleted file mode 100644 index 0e710fc5785dcca707e400bcdf116794f89980b0..0000000000000000000000000000000000000000 --- a/wiser-wcs-reports/requirements.py +++ /dev/null @@ -1,4 +0,0 @@ -argparse==1.2.1 -simplejson==3.8.0 -wsgiref==0.1.2 -xml2json==0.1 diff --git a/wiser-wcs-reports/requirements.txt b/wiser-wcs-reports/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ed018b26028451bb38c1266215486b01f7c15d6 --- /dev/null +++ b/wiser-wcs-reports/requirements.txt @@ -0,0 +1,2 @@ +configparser==4.0.2 +xmljson==0.2.0 diff --git a/wiser-wcs-reports/wiser-wcs.py b/wiser-wcs-reports/wiser-wcs.py index f4dc5b5f04ad9f308b421c3e5e7f7800a30e926c..f5027ebcb82e3e9214a52412d7f1e46bac7066b1 100644 --- a/wiser-wcs-reports/wiser-wcs.py +++ b/wiser-wcs-reports/wiser-wcs.py @@ -1,262 +1,266 @@ -from xml2json import json2xml, xml2json +from xmljson import badgerfish +from xml.etree.ElementTree import fromstring from os import listdir from os.path import isfile, join -import ConfigParser +from collections import OrderedDict +import configparser import json import re class Options(object): - """ - Dummy class - """ - pass + """ + Dummy class + """ + pass class IterMixin(object): - def __iter__(self): - for attr, value in self.__dict__.iteritems(): - yield attr, value + def __iter__(self): + for attr, value in self.__dict__.iteritems(): + yield attr, value class WiserVulnerability(IterMixin): - """ - Super class of WISER vulnerabilities. - """ - - """ short description of the vulnerability """ - short_desc = dict() - """ long description """ - desc = dict() - """ reference url """ - reference = dict() - """ how to solve """ - solution = dict() - """ risk level """ - risk_level = dict() - """ WISER risk level """ - w_risk_level = dict() - """id of the vuln """ - wascid = dict() - """ Source pen_test """ - source_pentest = dict() - - def __init__(self): - pass - - def parse_from_alert(self, alert_dict, type): - pass - - def parse_report(self, report_dict): - pass - - """ - Sets WISER risk level to the Vulnerability. - """ - def set_wiser_risk_level(self): - pass - - def __str__(self): - return json.dumps(dict(self)) + """ + Super class of WISER vulnerabilities. + """ + + """ short description of the vulnerability """ + short_desc = dict() + """ long description """ + desc = dict() + """ reference url """ + reference = dict() + """ how to solve """ + solution = dict() + """ risk level """ + risk_level = dict() + """ WISER risk level """ + w_risk_level = dict() + """id of the vuln """ + wascid = dict() + """ Source pen_test """ + source_pentest = dict() + + def __init__(self): + pass + + def parse_from_alert(self, alert_dict, type): + pass + + def parse_report(self, report_dict): + pass + + """ + Sets WISER risk level to the Vulnerability. + """ + def set_wiser_risk_level(self): + pass + + def __str__(self): + return json.dumps(self.__dict__) class WiserReport(IterMixin): - report = list() - report_json = dict() + report = list() + report_json = dict() - def __init__(self): - pass + def __init__(self): + pass - def parse_report(self, report_dict): - pass + def parse_report(self, report_dict): + pass - """ Gets the report from the parsed list of vulnerabilities. - """ - def get_report(self): - return self.report + """ Gets the report from the parsed list of vulnerabilities. + """ + def get_report(self): + return self.report class WiserZapVulnerability(WiserVulnerability): - def __init__(self, alert): - self.parse_report(alert) - - def parse_report(self, alert): - self.short_desc = alert['alert']['#text'] - self.desc = alert['desc']['#text'] - self.reference = alert['reference']['#text'] - self.risk_level = alert['riskdesc']['#text'] - self.solution = alert['solution']['#text'] - if 'wascid' in alert: - self.wascid = alert['wascid']['#text'] - self.source_pentest="OWASP ZAP" - self.set_wiser_risk_level() - - def set_wiser_risk_level(self): - if self.risk_level == "Low (Low)": - self.w_risk_level = 10 - if self.risk_level == "Low (Medium)": - self.w_risk_level = 20 - if self.risk_level == "Low (High)": - self.w_risk_level = 50 - if self.risk_level == "Medium (Low)": - self.w_risk_level = 20 - if self.risk_level == "Medium (Medium)": - self.w_risk_level = 50 - if self.risk_level == "Medium (High)": - self.w_risk_level = 80 - if self.risk_level == "High (Low)": - self.w_risk_level = 50 - if self.risk_level == "High (Medium)": - self.w_risk_level = 80 - if self.risk_level == "High (High)": - self.w_risk_level = 100 + def __init__(self, alert): + super().__init__() + self.parse_report(alert) + + @staticmethod + def _pretty(text): + return re.sub('(</?p>)+', '\n', text).strip() + + def parse_report(self, alert): + self.short_desc = self._pretty(alert['alert']['$']) + self.desc = self._pretty(alert['desc']['$']) + self.reference = self._pretty(alert['reference']['$']) + self.risk_level = self._pretty(alert['riskdesc']['$']) + self.solution = self._pretty(alert['solution']['$']) + if 'wascid' in alert: + self.wascid = alert['wascid']['$'] + self.source_pentest="OWASP ZAP" + self.set_wiser_risk_level() + + def set_wiser_risk_level(self): + if self.risk_level == "Low (Low)": + self.w_risk_level = 10 + if self.risk_level == "Low (Medium)": + self.w_risk_level = 20 + if self.risk_level == "Low (High)": + self.w_risk_level = 50 + if self.risk_level == "Medium (Low)": + self.w_risk_level = 20 + if self.risk_level == "Medium (Medium)": + self.w_risk_level = 50 + if self.risk_level == "Medium (High)": + self.w_risk_level = 80 + if self.risk_level == "High (Low)": + self.w_risk_level = 50 + if self.risk_level == "High (Medium)": + self.w_risk_level = 80 + if self.risk_level == "High (High)": + self.w_risk_level = 100 class WiserW3afVulnerability(WiserVulnerability): - def __init__(self, alert): - self.parse_report(alert) - - def parse_report(self, alert): - self.short_desc = alert['@name'] - self.desc = alert['description']['#text'] - if 'references' in alert: - if 'reference' in alert['references']: - if alert['references']['reference'] is dict: - self.reference = alert['references']['reference']['@url'] - if alert['references']['reference'] is list: - self.reference = alert['references']['reference'][0]['@url'] - self.risk_level = alert['@severity'] - if 'long-description' in alert: - self.solution = alert['long-description']['#text'] - if '@id' in alert: - if 'references' in alert: - if 'reference' in alert['references']: - if '@title' in alert['references']['reference']: - if alert['references']['reference']['@title'] == 'WASC': - #self.wascid = alert['@id'] - self.wascid = re.sub('[\[\]]', '', alert['@id']) - self.source_pentest="W3af" - self.set_wiser_risk_level() - - def set_wiser_risk_level(self): - if self.risk_level == "Information": - self.w_risk_level = 25 - if self.risk_level == "Low": - self.w_risk_level = 50 - if self.risk_level == "Medium": - self.w_risk_level = 75 - if self.risk_level == "High": - self.w_risk_level = 100 + def __init__(self, alert): + super().__init__() + self.parse_report(alert) + + def parse_report(self, alert): + self.short_desc = alert['@name'] + self.desc = alert['description']['$'] + if 'references' in alert: + if 'reference' in alert['references']: + if isinstance(alert['references']['reference'], OrderedDict): + self.reference = alert['references']['reference']['@url'] + if alert['references']['reference'] is list: + self.reference = alert['references']['reference'][0]['@url'] + self.risk_level = alert['@severity'] + if 'long-description' in alert: + self.solution = alert['long-description']['$'] + if '@id' in alert: + if 'references' in alert: + if 'reference' in alert['references']: + if '@title' in alert['references']['reference']: + if alert['references']['reference']['@title'] == 'WASC': + self.wascid = re.sub('[\[\]]', '', alert['@id']) + self.source_pentest="W3af" + self.set_wiser_risk_level() + + def set_wiser_risk_level(self): + if self.risk_level == "Information": + self.w_risk_level = 25 + if self.risk_level == "Low": + self.w_risk_level = 50 + if self.risk_level == "Medium": + self.w_risk_level = 75 + if self.risk_level == "High": + self.w_risk_level = 100 class WiserZapReport(WiserReport): - def __init__(self, report): - self.parse_report(report) - - def parse_report(self, report_dict): - """ - Parses OWASP ZAP report - :param report: - :return: - """ - self.report = list() - print report_dict - if 'site' in report_dict: - if 'alerts' in report_dict['site'] and report_dict['site']['alerts'] is not None: - if 'alertitem' in report_dict['site']['alerts']: - if type(report_dict['site']['alerts']['alertitem'])==list: - for i in range(0, len(report_dict['site']['alerts']['alertitem'])): - alert = report_dict['site']['alerts']['alertitem'][i] - vulnerability = WiserZapVulnerability(alert) - self.report.append(vulnerability) - else: - alert = report_dict['site']['alerts']['alertitem'] - vulnerability = WiserZapVulnerability(alert) - self.report.append(vulnerability) + def __init__(self, report): + super().__init__() + self.parse_report(report) + + def parse_report(self, report_dict): + """ + Parses OWASP ZAP report + :param report: + :return: + """ + self.report = list() + if 'site' in report_dict: + if 'alerts' in report_dict['site'] and report_dict['site']['alerts'] is not None: + if 'alertitem' in report_dict['site']['alerts']: + if type(report_dict['site']['alerts']['alertitem'])==list: + for i in range(0, len(report_dict['site']['alerts']['alertitem'])): + alert = report_dict['site']['alerts']['alertitem'][i] + vulnerability = WiserZapVulnerability(alert) + self.report.append(vulnerability) + else: + alert = report_dict['site']['alerts']['alertitem'] + vulnerability = WiserZapVulnerability(alert) + self.report.append(vulnerability) class WiserW3afReport(WiserReport): - def __init__(self, report): - self.parse_report(report) - - def parse_report(self, report_dict): - """ - Parses W3af report - :param report: - :return: - """ - self.report = list() - if 'vulnerability' in report_dict: - if type(report_dict['vulnerability'])==list: - for alert in report_dict['vulnerability']: - vulnerability = WiserW3afVulnerability(alert) - self.report.append(vulnerability) - else: - alert = report_dict['vulnerability'] - vulnerability = WiserW3afVulnerability(alert) - self.report.append(vulnerability) + def __init__(self, report): + super().__init__() + self.parse_report(report) + + def parse_report(self, report_dict): + """ + Parses W3af report + :param report: + :return: + """ + self.report = list() + if 'vulnerability' in report_dict: + if type(report_dict['vulnerability'])==list: + for alert in report_dict['vulnerability']: + vulnerability = WiserW3afVulnerability(alert) + self.report.append(vulnerability) + else: + alert = report_dict['vulnerability'] + vulnerability = WiserW3afVulnerability(alert) + self.report.append(vulnerability) def parse_config_file(filename): - """ - Parse the config file. + """ + Parse the config file. - :param filename: the config file - :return: - """ - config = ConfigParser.ConfigParser() - config.read(filename) - return config + :param filename: the config file + :return: + """ + config = configparser.ConfigParser() + config.read(filename) + return config def reports_json(dir): - """ - Iterate through directory. - :param dir: - :return: - """ - options = Options - setattr(options, 'pretty', False) - strip_ns = 0 - strip = 0 - onlyfiles = [f for f in listdir(dir) if isfile(join(dir,f))] - reports = dict() - for f in onlyfiles: - inputstream = open(join(dir,f)) - input = inputstream.read() - out = xml2json(input, options, strip_ns, strip) - reports[f] = out - return reports + """ + Iterate through directory. + :param dir: + :return: + """ + onlyfiles = [f for f in listdir(dir) if isfile(join(dir,f))] + reports = dict() + for f in onlyfiles: + inputstream = open(join(dir,f)) + input = inputstream.read() + out = badgerfish.data(fromstring(input)) + reports[f] = out + return reports def list_vulnerabilities(reports): - """ - List all vulnerabilities based on the reports given. - :return: - """ - vulnerabilities = list() - for report in reports.values(): - report_dict = json.loads(report) - if "OWASPZAPReport" in report_dict: - vulnerabilities.extend(WiserZapReport(report_dict['OWASPZAPReport']).get_report()) - if "w3af-run" in report_dict: - vulnerabilities.extend(WiserW3afReport(report_dict['w3af-run']).get_report()) - return vulnerabilities + """ + List all vulnerabilities based on the reports given. + :return: + """ + vulnerabilities = list() + for report in reports.values(): + report_dict = report + if "OWASPZAPReport" in report_dict: + vulnerabilities.extend(WiserZapReport(report_dict['OWASPZAPReport']).get_report()) + if "w3af-run" in report_dict: + vulnerabilities.extend(WiserW3afReport(report_dict['w3af-run']).get_report()) + return vulnerabilities if __name__ == "__main__": - config = parse_config_file('wiser-wcs.cfg') - reports = reports_json(config._sections['cscan_config']['cscan_output']) - print "printing vulnerabilities: " - vulnerabilities = list_vulnerabilities(reports) - vulnerabilities_list = list() - for vulnerability in vulnerabilities: - print vulnerability - vulnerabilities_list.append(vulnerability.__dict__) - - vulnerabilities_json = json.dumps({ "reports": vulnerabilities_list}) - print "printing vulnerabilities JSON: " - print vulnerabilities_json + config = parse_config_file('wiser-wcs.cfg') + reports = reports_json(config['cscan_config']['cscan_output']) + print("printing vulnerabilities: ") + vulnerabilities = list_vulnerabilities(reports) + vulnerabilities_list = list() + for vulnerability in vulnerabilities: + print(vulnerability) + vulnerabilities_list.append(vulnerability.__dict__) + + vulnerabilities_json = json.dumps({ "reports": vulnerabilities_list}) + print("printing vulnerabilities JSON: ") + print(vulnerabilities_json)