diff --git a/cve_support/cve_policy_filter.py b/cve_support/cve_policy_filter.py index dff356d2..1fc246f0 100644 --- a/cve_support/cve_policy_filter.py +++ b/cve_support/cve_policy_filter.py @@ -14,6 +14,16 @@ import sys import os from lp import find_lp_assigned +cves_valid = [] +cves_to_fix = [] +cves_to_fix_lp = [] +cves_to_track = [] +cves_w_errors = [] +cves_wont_fix = [] +cves_to_omit = [] +cves_report = {} + + def print_html_report(cves_report, title): """ Print the html report @@ -22,9 +32,14 @@ def print_html_report(cves_report, title): template_loader = jinja2.FileSystemLoader(searchpath="./") template_env = jinja2.Environment(loader=template_loader) - template_file = "template.txt" + if CVSS_VER == "cvssv3": + template_file = "template_v3.txt" + heads = ["cve_id", "status", "cvss3Score", "av", "ac", "ui","a"] + else: + template_file = "template.txt" + heads = ["cve_id", "status", "cvss2Score", "av", "ac", "au", "ai"] + template = template_env.get_template(template_file) - heads = ["cve_id", "status", "cvss2Score", "av", "ac", "au", "ai"] output_text = template.render(cves_to_fix=cves_report["cves_to_fix"],\ cves_to_fix_lp=cves_report["cves_to_fix_lp"],\ cves_to_track=cves_report["cves_to_track"],\ @@ -49,10 +64,16 @@ def print_report(cves_report, title): print("\n") print(cve["id"]) print("status : " + cve["status"]) - print("cvss2Score : " + str(cve["cvss2Score"])) + if CVSS_VER == "cvssv3": + print("cvss3Score : " + str(cve["cvss3Score"])) + else: + print("cvss2Score : " + str(cve["cvss2Score"])) print("Attack Vector: " + cve["av"]) print("Access Complexity : " + cve["ac"]) - print("Authentication: " + cve["au"]) + if CVSS_VER == "cvssv3": + print("User Interaction: " + cve["ui"]) + else: + print("Authentication: " + cve["au"]) print("Availability Impact :" + cve["ai"]) print("Affected packages:") print(cve["affectedpackages"]) @@ -88,8 +109,12 @@ def print_report(cves_report, title): print(cve_line) - print("\nERROR: CVEs that have no cvss2Score or cvss2Vector: %d \n" \ - % (len(cves_report["cves_w_errors"]))) + if CVSS_VER == "cvssv3": + print("\nERROR: CVEs that have no cvss3Score or cvss3Vector: %d \n" \ + % (len(cves_report["cves_w_errors"]))) + else: + print("\nERROR: CVEs that have no cvss2Score or cvss2Vector: %d \n" \ + % (len(cves_report["cves_w_errors"]))) for cve in cves_report["cves_w_errors"]: print(cve) @@ -130,49 +155,112 @@ def get_affectedpackages(data, cve_id): allfixed = "unfixed" return affectedpackages_list, allfixed -def main(): +def update_report(): + cves_report["cves_to_fix"] = cves_to_fix + cves_report["cves_to_fix_lp"] = cves_to_fix_lp + cves_report["cves_to_track"] = cves_to_track + cves_report["cves_w_errors"] = cves_w_errors + cves_report["cves_wont_fix"] = cves_wont_fix + cves_report["cves_to_omit"] = cves_to_omit + +def cvssv3_pb_alg(): """ - main function - Rules to consider a CVE valid for STX from: - https://wiki.openstack.org/wiki/StarlingX/Security/CVE_Support_Policy + Patchback algo for CVSSV3 report """ - data = {} - cves = [] - cves_valid = [] - cves_to_fix = [] - cves_to_fix_lp = [] - cves_to_track = [] - cves_w_errors = [] - cves_wont_fix = [] - cves_to_omit = [] - cves_report = {} + for cve in cves_valid: + if (cve["cvss3Score"] >= 7.8 + and cve["av"] == "N" + and cve["ac"] == "L" + and cve["ui"] == "R" + and cve["ai"] != "N"): + if cve["status"] == "fixed": + bug = find_lp_assigned(cve["id"]) + if (bug): + print(bug["status"]) + if (bug["status"] == "Invalid" or bug["status"] == "Won't Fix"): + cves_wont_fix.append(cve) + else: + cves_to_fix_lp.append(cve) + else: + cves_to_fix.append(cve) + else: + cves_to_track.append(cve) + else: + cves_to_omit.append(cve) - if len(sys.argv) < 3: - print("\nERROR : Missing arguments, the expected arguments are:") - print("\n %s \n" % (sys.argv[0])) - print("\n result.json = json file generated from: vuls report -format-json") - print("\n") - sys.exit(0) + update_report() - if os.path.isfile(sys.argv[1]): - results_json = sys.argv[1] - else: - print("%s is not a file" % sys.argv[1]) - sys.exit(0) - title = sys.argv[2] +def cvssv2_pb_alg(): + """ + Patchback algo for CVSSV2 report + """ + for cve in cves_valid: + if (cve["cvss2Score"] >= 7.0 + and cve["av"] == "N" + and cve["ac"] == "L" + and ("N" in cve["au"] or "S" in cve["au"]) + and ("P" in cve["ai"] or "C" in cve["ai"])): + if cve["status"] == "fixed": + bug = find_lp_assigned(cve["id"]) + if (bug): + print(bug["status"]) + if (bug["status"] == "Invalid" or bug["status"] == "Won't Fix"): + cves_wont_fix.append(cve) + else: + cves_to_fix_lp.append(cve) + else: + cves_to_fix.append(cve) + else: + cves_to_track.append(cve) + else: + cves_to_omit.append(cve) - try: - with open(results_json) as json_file: - data = json.load(json_file) - except ValueError as error: - print(error) + update_report() - for element in data["scannedCves"]: - cve = {} - cve["id"] = str(element.strip()) - cves.append(cve) +def cvssv3_parse_n_report(cves,title,data): + """ + Parse and generate report for CVSSV3 + """ + for cve in cves: + cve_id = cve["id"] + affectedpackages_list = [] + allfixed = "fixed" + try: + nvd2_score = data["scannedCves"][cve_id]["cveContents"]["nvd"]["cvss3Score"] + cvss3vector = data["scannedCves"][cve_id]["cveContents"]["nvd"]["cvss3Vector"] + except KeyError: + cves_w_errors.append(cve) + else: + cve["cvss3Score"] = nvd2_score + for element in cvss3vector.split("/"): + if "AV:" in element: + _av = element.split(":")[1] + if "AC:" in element: + _ac = element.split(":")[1] + if "A:" in element: + _ai = element.split(":")[1] + if "UI:" in element: + _ui = element.split(":")[1] + print(cve) + cve["av"] = str(_av) + cve["ac"] = str(_ac) + cve["ai"] = str(_ai) + cve["ui"] = str(_ui) + cve["summary"] = get_summary(data, cve_id) + cve["sourcelink"] = get_source_link(data, cve_id) + affectedpackages_list, allfixed = get_affectedpackages(data, cve_id) + cve["affectedpackages"] = affectedpackages_list + cve["status"] = allfixed + cves_valid.append(cve) + cvssv3_pb_alg() + print_report(cves_report, title) + print_html_report(cves_report, title) +def cvssv2_parse_n_report(cves,title,data): + """ + Parse and generate report for CVSSV2 + """ for cve in cves: cve_id = cve["id"] affectedpackages_list = [] @@ -203,37 +291,55 @@ def main(): cve["affectedpackages"] = affectedpackages_list cve["status"] = allfixed cves_valid.append(cve) - - for cve in cves_valid: - if (cve["cvss2Score"] >= 7.0 - and cve["av"] == "N" - and cve["ac"] == "L" - and ("N" in cve["au"] or "S" in cve["au"]) - and ("P" in cve["ai"] or "C" in cve["ai"])): - if cve["status"] == "fixed": - bug = find_lp_assigned(cve["id"]) - if (bug): - print(bug["status"]) - if (bug["status"] == "Invalid" or bug["status"] == "Won't Fix"): - cves_wont_fix.append(cve) - else: - cves_to_fix_lp.append(cve) - else: - cves_to_fix.append(cve) - else: - cves_to_track.append(cve) - else: - cves_to_omit.append(cve) - - cves_report["cves_to_fix"] = cves_to_fix - cves_report["cves_to_fix_lp"] = cves_to_fix_lp - cves_report["cves_to_track"] = cves_to_track - cves_report["cves_w_errors"] = cves_w_errors - cves_report["cves_wont_fix"] = cves_wont_fix - cves_report["cves_to_omit"] = cves_to_omit - + cvssv2_pb_alg() print_report(cves_report, title) print_html_report(cves_report, title) +def main(): + """ + main function + Rules to consider a CVE valid for STX from: + https://wiki.openstack.org/wiki/StarlingX/Security/CVE_Support_Policy + """ + data = {} + cves = [] + + + if len(sys.argv) < 4: + print("\nERROR : Missing arguments, the expected arguments are:") + print("\n %s <result.json> <title> [cvssv3|cvssv2]\n" % (sys.argv[0])) + print("\n result.json = json file generated from: vuls report -format-json") + print("\n") + sys.exit(0) + + if os.path.isfile(sys.argv[1]): + results_json = sys.argv[1] + else: + print("%s is not a file" % sys.argv[1]) + sys.exit(0) + + title = sys.argv[2] + + try: + with open(results_json) as json_file: + data = json.load(json_file) + except ValueError as error: + print(error) + + for element in data["scannedCves"]: + cve = {} + cve["id"] = str(element.strip()) + cves.append(cve) + global CVSS_VER + CVSS_VER=sys.argv[3].lower() + if CVSS_VER =="cvssv3": + cvssv3_parse_n_report(cves,title,data) + elif CVSS_VER == "cvssv2": + cvssv2_parse_n_report(cves,title,data) + else: + print("\n argument not matching \n enter [cvssv3|cvssv2] ") + sys.exit(0) + + if __name__ == "__main__": main() diff --git a/cve_support/template_v3.txt b/cve_support/template_v3.txt new file mode 100644 index 00000000..a666c9ba --- /dev/null +++ b/cve_support/template_v3.txt @@ -0,0 +1,127 @@ +<head></head> +<body> + <h1>Security report from vuls scan from {{title}}</h1> + <h2>CVEs to fix w/o a launchpad assigned: {{cves_to_fix | length}}</h2> + <table> + {% if cves_to_fix|length >= 1 %} + <tr> + {% for head in heads %} + <th>{{head}}</th> + {% endfor %} + </tr> + + {% for cve in cves_to_fix %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + <td>{{cve["cvss3Score"]}}</td> + <td>{{cve["av"]}}</td> + <td>{{cve["ac"]}}</td> + <td>{{cve["ui"]}}</td> + <td>{{cve["ai"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> + <h2>CVEs to fix w/ a launchpad assigend: {{cves_to_fix_lp | length}}</h2> + <table> + {% if cves_to_fix_lp|length >= 1 %} + <tr> + {% for head in heads %} + <th>{{head}}</th> + {% endfor %} + </tr> + + {% for cve in cves_to_fix_lp %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + <td>{{cve["cvss3Score"]}}</td> + <td>{{cve["av"]}}</td> + <td>{{cve["ac"]}}</td> + <td>{{cve["ui"]}}</td> + <td>{{cve["ai"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> + <h2> CVEs to track for incoming fix: {{cves_to_track | length}}</h2> + <table> + {% if cves_to_track|length >= 1 %} + <tr> + {% for head in heads %} + <th>{{head}}</th> + {% endfor %} + </tr> + + {% for cve in cves_to_track %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + <td>{{cve["cvss3Score"]}}</td> + <td>{{cve["av"]}}</td> + <td>{{cve["ac"]}}</td> + <td>{{cve["ui"]}}</td> + <td>{{cve["ai"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> + <h2> CVEs that are Invalid or Won't Fix: {{cves_wont_fix | length}}</h2> + <table> + {% if cves_wont_fix|length >= 1 %} + <tr> + {% for head in heads %} + <th>{{head}}</th> + {% endfor %} + </tr> + + {% for cve in cves_wont_fix %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + <td>{{cve["cvss3Score"]}}</td> + <td>{{cve["av"]}}</td> + <td>{{cve["ac"]}}</td> + <td>{{cve["ui"]}}</td> + <td>{{cve["ai"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> + + <h2> CVEs to omit: {{cves_to_omit | length}}</h2> + <table> + {% if cves_to_omit|length >= 1 %} + <tr> + {% for head in heads %} + <th>{{head}}</th> + {% endfor %} + </tr> + + {% for cve in cves_to_omit %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + <td>{{cve["cvss3Score"]}}</td> + <td>{{cve["av"]}}</td> + <td>{{cve["ac"]}}</td> + <td>{{cve["ui"]}}</td> + <td>{{cve["ai"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> + + <h2>ERROR: CVEs that have no cvss3Score or cvss2Vector:{{cves_w_errors | length}}</h2> + <table> + {% if cves_w_errors|length >= 1 %} + {% for cve in cves_w_errors %} + <tr> + <td>{{cve["id"]}}</td> + <td>{{cve["status"]}}</td> + </tr> + {% endfor %} + {% endif %} + </table> +</body>