Skip to content

Commit 2178de6

Browse files
committed
Added Vendor + Product details
1 parent 9b31273 commit 2178de6

File tree

3 files changed

+57
-16
lines changed

3 files changed

+57
-16
lines changed

cve_prioritizer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__author__ = "Mario Rojas"
44
__license__ = "BSD 3-clause"
5-
__version__ = "1.3.0"
5+
__version__ = "1.4.0"
66
__maintainer__ = "Mario Rojas"
77
__status__ = "Production"
88

@@ -101,7 +101,7 @@
101101

102102
if args.output:
103103
with open(args.output, 'w') as output_file:
104-
output_file.write("cve_id,priority,epss,cvss,cvss_version,cvss_severity,cisa_kev"+"\n")
104+
output_file.write("cve_id,priority,epss,cvss,cvss_version,cvss_severity,cisa_kev,cpe,vendor,product"+"\n")
105105

106106
for cve in cve_list:
107107
throttle = 1

scripts/constants.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
__author__ = "Mario Rojas"
44
__license__ = "BSD 3-clause"
5-
__version__ = "1.3.0"
5+
__version__ = "1.4.0"
66
__maintainer__ = "Mario Rojas"
77
__status__ = "Production"
88

99
SIMPLE_HEADER = f"{'CVE-ID':<18}Priority"+"\n"+("-"*30)
10-
VERBOSE_HEADER = f"{'CVE-ID':<18}{'PRIORITY':<13}{'EPSS':<9}{'CVSS':<6}{'VERSION':<10}{'SEVERITY':<10}CISA_KEV"+"\n"+("-"*75)
10+
VERBOSE_HEADER = (f"{'CVE-ID':<18}{'PRIORITY':<13}{'EPSS':<9}{'CVSS':<6}{'VERSION':<10}{'SEVERITY':<10}{'CISA_KEV':<10}"
11+
f"{'VENDOR':<18}PRODUCT")+"\n"+("-"*115)
1112
EPSS_URL = "https://api.first.org/data/v1/epss"
1213
NIST_BASE_URL = "https://services.nvd.nist.gov/rest/json/cves/2.0"
1314
LOGO = """

scripts/helpers.py

+52-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
__author__ = "Mario Rojas"
1414
__license__ = "BSD 3-clause"
15-
__version__ = "1.3.0"
15+
__version__ = "1.4.0"
1616
__maintainer__ = "Mario Rojas"
1717
__status__ = "Production"
1818

@@ -67,32 +67,41 @@ def nist_check(cve_id):
6767
if unique_cve.get("cve").get("cisaExploitAdd"):
6868
cisa_kev = True
6969

70+
try:
71+
cpe = unique_cve.get("cve").get("configurations")[0].get("nodes")[0].get("cpeMatch")[0].get("criteria")
72+
except TypeError:
73+
cpe = 'cpe:2.3:::::::::::'
74+
7075
# Collect CVSS Data
7176
if unique_cve.get("cve").get("metrics").get("cvssMetricV31"):
7277
for metric in unique_cve.get("cve").get("metrics").get("cvssMetricV31"):
7378
results = {"cvss_version": "CVSS 3.1",
7479
"cvss_baseScore": float(metric.get("cvssData").get("baseScore")),
7580
"cvss_severity": metric.get("cvssData").get("baseSeverity"),
76-
"cisa_kev": cisa_kev}
81+
"cisa_kev": cisa_kev,
82+
"cpe": cpe}
7783
return results
7884
elif unique_cve.get("cve").get("metrics").get("cvssMetricV30"):
7985
for metric in unique_cve.get("cve").get("metrics").get("cvssMetricV30"):
8086
results = {"cvss_version": "CVSS 3.0",
8187
"cvss_baseScore": float(metric.get("cvssData").get("baseScore")),
8288
"cvss_severity": metric.get("cvssData").get("baseSeverity"),
83-
"cisa_kev": cisa_kev}
89+
"cisa_kev": cisa_kev,
90+
"cpe": cpe}
8491
return results
8592
elif unique_cve.get("cve").get("metrics").get("cvssMetricV2"):
8693
for metric in unique_cve.get("cve").get("metrics").get("cvssMetricV2"):
8794
results = {"cvss_version": "CVSS 2.0",
8895
"cvss_baseScore": float(metric.get("cvssData").get("baseScore")),
8996
"cvss_severity": metric.get("baseSeverity"),
90-
"cisa_kev": cisa_kev}
97+
"cisa_kev": cisa_kev,
98+
"cpe": cpe}
9199
return results
92100
elif unique_cve.get("cve").get("vulnStatus") == "Awaiting Analysis":
93101
print(f"{cve_id:<18}NIST Status: {unique_cve.get('cve').get('vulnStatus')}")
94102
else:
95103
print(f"{cve_id:<18}Not Found in NIST NVD.")
104+
exit()
96105
else:
97106
print(f"{cve_id:<18}Error code {nvd_status_code}")
98107
except requests.exceptions.ConnectionError:
@@ -113,17 +122,48 @@ def colored_print(priority):
113122
return colored(priority, 'green')
114123

115124

125+
# Extract CVE product details
126+
def parse_cpe(cpe_str):
127+
"""
128+
Parses a CPE URI string and extracts the vendor, product, and version.
129+
Assumes the CPE string is in the format: cpe:/a:vendor:product:version:update:edition:language
130+
"""
131+
# Splitting the CPE string into components
132+
parts = cpe_str.split(':')
133+
134+
# Extracting vendor, product, and version
135+
vendor = parts[3] if len(parts) > 2 else None
136+
product = parts[4] if len(parts) > 3 else None
137+
138+
return vendor, product
139+
140+
141+
# Truncate for printing
142+
def truncate_string(input_string, max_length):
143+
"""
144+
Truncates a string to a maximum length, appending an ellipsis if the string is too long.
145+
"""
146+
if len(input_string) > max_length:
147+
return input_string[:max_length - 3] + "..."
148+
else:
149+
return input_string
150+
151+
116152
# Function manages the outputs
117-
def print_and_write(working_file, cve_id, priority, epss, cvss_base_score, cvss_version, cvss_severity, cisa_kev, verbose):
153+
def print_and_write(working_file, cve_id, priority, epss, cvss_base_score, cvss_version, cvss_severity, cisa_kev,
154+
verbose, cpe):
118155

119156
color_priority = colored_print(priority)
157+
vendor, product = parse_cpe(cpe)
120158

121159
if verbose:
122-
print(f"{cve_id:<18}{color_priority:<22}{epss:<9}{cvss_base_score:<6}{cvss_version:<10}{cvss_severity:<10}{cisa_kev}")
160+
print(f"{cve_id:<18}{color_priority:<22}{epss:<9}{cvss_base_score:<6}{cvss_version:<10}{cvss_severity:<10}"
161+
f"{cisa_kev:<10}{truncate_string(vendor,15):<18}{truncate_string(product, 20)}")
123162
else:
124163
print(f"{cve_id:<18}{color_priority:<22}")
125164
if working_file:
126-
working_file.write(f"{cve_id},{priority},{epss},{cvss_base_score},{cvss_version},{cvss_severity},{cisa_kev}\n")
165+
working_file.write(f"{cve_id},{priority},{epss},{cvss_base_score},{cvss_version},{cvss_severity},"
166+
f"{cisa_kev},{cpe},{vendor},{product}\n")
127167

128168

129169
# Main function
@@ -139,25 +179,25 @@ def worker(cve_id, cvss_score, epss_score, verbose_print, sem, save_output=None)
139179
if nist_result.get("cisa_kev"):
140180
print_and_write(working_file, cve_id, 'Priority 1+', epss_result.get('epss'),
141181
nist_result.get('cvss_baseScore'), nist_result.get('cvss_version'),
142-
nist_result.get('cvss_severity'), 'TRUE', verbose_print)
182+
nist_result.get('cvss_severity'), 'TRUE', verbose_print, nist_result.get('cpe'))
143183
elif nist_result.get("cvss_baseScore") >= cvss_score:
144184
if epss_result.get("epss") >= epss_score:
145185
print_and_write(working_file, cve_id, 'Priority 1', epss_result.get('epss'),
146186
nist_result.get('cvss_baseScore'), nist_result.get('cvss_version'),
147-
nist_result.get('cvss_severity'), 'FALSE', verbose_print)
187+
nist_result.get('cvss_severity'), 'FALSE', verbose_print, nist_result.get('cpe'))
148188
else:
149189
print_and_write(working_file, cve_id, 'Priority 2', epss_result.get('epss'),
150190
nist_result.get('cvss_baseScore'), nist_result.get('cvss_version'),
151-
nist_result.get('cvss_severity'), 'FALSE', verbose_print)
191+
nist_result.get('cvss_severity'), 'FALSE', verbose_print, nist_result.get('cpe'))
152192
else:
153193
if epss_result.get("epss") >= epss_score:
154194
print_and_write(working_file, cve_id, 'Priority 3', epss_result.get('epss'),
155195
nist_result.get('cvss_baseScore'), nist_result.get('cvss_version'),
156-
nist_result.get('cvss_severity'), 'FALSE', verbose_print)
196+
nist_result.get('cvss_severity'), 'FALSE', verbose_print, nist_result.get('cpe'))
157197
else:
158198
print_and_write(working_file, cve_id, 'Priority 4', epss_result.get('epss'),
159199
nist_result.get('cvss_baseScore'), nist_result.get('cvss_version'),
160-
nist_result.get('cvss_severity'), 'FALSE', verbose_print)
200+
nist_result.get('cvss_severity'), 'FALSE', verbose_print, nist_result.get('cpe'))
161201
except (TypeError, AttributeError):
162202
pass
163203

0 commit comments

Comments
 (0)