Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to API calls for CSAF output #19

Merged
merged 2 commits into from
Sep 7, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 95 additions & 24 deletions api_examples/get_vince.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/usr/bin/python3

import requests,json,sys,getpass,argparse
import requests
import json
import sys
import getpass
import argparse
import uuid

###################################################################################
###################### Python Script to collect VINCE API ########################
Expand All @@ -9,7 +14,7 @@
### Usage ###

# To run this script you must have the following:
# Python 2.7 or Python 3 (Preferred)
# use Python 3
# Python modules requests,json,sys,getpass,argparse

# Simply run following command in terminal to validate json file against schema:
Expand All @@ -24,6 +29,17 @@
###################################################################################
###################################################################################

def deepcheck(obj,dir):
x = obj
for s in dir.split("."):
if isinstance(x,dict) and s in x:
x = x[s]
elif isinstance(x,list) and int(s) < len(x):
x = x[int(s)]
else:
return None
return x


def error_exit(reason):
print(json.dumps({"error":reason}))
Expand All @@ -33,7 +49,7 @@ def fatal_exit(ex_cls, ex, tb):
#Send all locals into a error array back to exit
#errors = map(str,locals())
errors = {"ex_cls":str(ex_cls),"ex":str(ex),"tb":str(tb)}
print(json.dumps({"errors":"Program error","info":errors}))
print(json.dumps({"error":"Program error","info":errors}))
sys.exit(2)


Expand All @@ -51,11 +67,12 @@ def create_response(key,turl):
result[key] = json.loads(str(r.text))

def vince_to_cvrf(vince):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def vince_to_cvrf(vince):
def vince_to_csaf(vince):

case_id = vince["get_case"]["vuid"]
cvrf = { "document": {
"acknowledgments": [
{
"urls": [
"https://kb.cert.org/vuls/id/"+vince["get_case"]["vuid"]
"https://kb.cert.org/vuls/id/"+case_id

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should include at least the anchor to acknowledgments section (as extracting the single values is not supported yet). The anchor must be supported by the website as well.

Suggested change
"https://kb.cert.org/vuls/id/"+case_id
"https://kb.cert.org/vuls/id/"+case_id+"#Acknowledgements"

]
}
],
Expand All @@ -67,11 +84,6 @@ def vince_to_cvrf(vince):
"text": vince["get_case"]["summary"],
"title": "Summary"
},
{
"category": "faq",
"text": "Please visit https://vuls.cert.org/confluence/display/Wiki/Vulnerability+Disclosure+Policy for full disclosure policy document",
"title": "Vulnerability Policy"
},
{
"category": "legal_disclaimer",
"text": "THIS DOCUMENT IS PROVIDED ON AN \"AS IS\" BASIS AND DOES NOT IMPLY ANY KIND OF GUARANTEE OR WARRANTY, INCLUDING THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. YOUR USE OF THE INFORMATION ON THE DOCUMENT OR MATERIALS LINKED FROM THE DOCUMENT IS AT YOUR OWN RISK.",
Expand All @@ -86,9 +98,15 @@ def vince_to_cvrf(vince):
"namespace": "https://kb.cert.org/"
},
"references": [
{
"url": "https://vuls.cert.org/confluence/display/Wiki/Vulnerability+Disclosure+Policy",
"summary": "CERT/CC vulnerability disclosure policy"
},

{
"summary": "CERT/CC document released",
"url": "https://kb.cert.org/vuls/id/"+vince["get_case"]["vuid"]
"category": "self",
"url": "https://kb.cert.org/vuls/id/"+case_id
}
],
"title": vince["get_case"]["title"],
Expand All @@ -100,8 +118,8 @@ def vince_to_cvrf(vince):
"version": "1.30.0"
}
},
"id": vince["get_case"]["vuid"],
"initial_release_date": vince["get_case"]["created"],
"id": "VU#"+case_id,
"initial_release_date": vince["get_case"]["due_date"],
"revision_history": [
{
"date": vince["get_case"]["due_date"],
Expand All @@ -114,21 +132,74 @@ def vince_to_cvrf(vince):
}
}}
cvrf["vulnerabilities"] = []
#map vulnerabilities to cvrf
#map vulnerabilities to csaf
#for now assume a singe product vendor id
product_csafid = "CSAFPID-"+str(uuid.uuid1())
for k in vince["get_vuls"]:
cve = k["name"].upper()
#We dont have a CVE title in VINCE, so get the first sentence
#to mimic a title per vulnerability.
# @tschmidtb51 also suggested something similar.
#https://github.com/CERTCC/VINCE/issues/17
short_title = k["description"].split(".")[0]+"."
cvrf["vulnerabilities"].append({
"title":k["description"],
"cve":k["name"]})
"title":short_title,
"notes":[{
"category": "summary",
"text": k["description"]
}],
"cve": cve,
"product_status": {
"known_affected": [
product_csafid
]
}
})
if cve.find("CVE-") > -1:
try:
cve_url = "https://olbat.github.io/nvdcve/"+cve+".json"
resp = requests.get(url=cve_url)
data = resp.json()
cvss_v3_data = deepcheck(data,"impact.baseMetricV3.cvssV3")
cvss_v2_data = deepcheck(data,"impact.baseMetricV2.cvssV2")
cve_title = deepcheck(data,"cve.description.description_data.0.value")
if cve_title:
#replace the title with CVE information
cvrf["vulnerabilities"][-1]["title"] = cve_title
#Add cvss_v3 or cvss_v2 data is available
if cvss_v3_data:
cvrf["vulnerabilities"][-1]["scores"] = [{"cvss_v3": cvss_v3_data,
"products": [product_csafid]}]
elif cvss_v2_data:
cvrf["vulnerabilities"][-1]["scores"] = [{"cvss_v2": cvss_v2_data,
"products": [product_csafid]}]
except:
pass
vendor_name = "Unknown"
if vince["get_original_report"]["vendor_name"]:
vendor_name = vince["get_original_report"]["vendor_name"]
product_name = "Unknown"
if vince["get_original_report"]["product_name"]:
product_name = vince["get_original_report"]["product_name"]
product_version = "1.0.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the product version is not present, it should not be specified.

if vince["get_original_report"]["product_version"]:
product_version = vince["get_original_report"]["product_version"]
product_fullname = vendor_name + " " + product_name + " " + product_version
cvrf["product_tree"] = {"branches": [{
"category": "product_version",
"name": vince["get_original_report"]["product_name"]
if vince["get_original_report"]["product_name"] else "Unspecified",
"product": {
"name": vince["get_original_report"]["product_name"]
if vince["get_original_report"]["product_name"] else "Unspecified",
"product_id": vince["get_original_report"]["product_version"]
if vince["get_original_report"]["product_version"] else "Unknown"
}
"category": "vendor",
"name": vendor_name,
"branches": [{
"category": "product_name",
"name": product_name,
"branches": [{
"category": "product_version",
"name": product_version,
"product": {
"product_id": product_csafid,
"name": product_fullname
}
}]
}]
}]}
return cvrf

Expand Down