Skip to content

Commit 223ce32

Browse files
author
Agh42
committed
Added support for field vulnerable_product
Parser now ingests the field "vulerable_product" from the NVD XML-feed. New option "--vulnerable-product-only" uses this field: With this option, "-p" will only return vulnerabilities directly assigned to the product. I.e. it will not consider "windows_7" if it is only mentioned as affected OS in a "foxit_reader" vulnerability.
1 parent 550af3d commit 223ce32

File tree

4 files changed

+21
-6
lines changed

4 files changed

+21
-6
lines changed

bin/search.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
# parse command-line arguments
4646
argParser = argparse.ArgumentParser(description='Search for vulnerabilities in the National Vulnerability DB. Data from http://nvd.nist.org.')
4747
argParser.add_argument('-p', type=str, help='S = search product, e.g. o:microsoft:windows_7 or o:cisco:ios:12.1')
48+
argParser.add_argument('--only-if-vulnerable', dest='vulnProdSearch', default=False, action='store_true', help='With this option, "-p" will only return vulnerabilities directly assigned to the product. I.e. it will not consider "windows_7" if it is only mentioned as affected OS in an adobe:reader vulnerability. ')
4849
argParser.add_argument('--lax', default=False, action='store_true', help='Strict search for software version is disabled. Note that this option only support product description with numerical values only (of the form cisco:ios:1.2.3) ')
4950
argParser.add_argument('-f', type=str, help='F = free text search in vulnerability summary')
5051
argParser.add_argument('-c', action='append', help='search one or more CVE-ID')
@@ -61,6 +62,7 @@
6162

6263
vSearch = args.p
6364
relaxSearch = args.lax
65+
vulnerableProductSearch = args.vulnProdSearch
6466
cveSearch = [x.upper() for x in args.c] if args.c else None
6567
vOutput = args.o
6668
vFreeSearch = args.f
@@ -303,7 +305,7 @@ def search_in_summary(item):
303305
# Search Product (best to use CPE notation, e.g. cisco:ios:12.2
304306
if vSearch:
305307

306-
for item in db.cvesForCPE(vSearch, lax=relaxSearch):
308+
for item in db.cvesForCPE(vSearch, lax=relaxSearch, vulnProdSearch=vulnerableProductSearch):
307309
if not last_ndays:
308310
if csvOutput:
309311
printCVE_csv(item)

lib/DatabaseLayer.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,11 @@ def target_version_is_included(target_version, cpe_version):
106106

107107

108108
# API Functions
109-
def cvesForCPE(cpe, lax=False):
109+
def cvesForCPE(cpe, lax=False, vulnProdSearch=False):
110110
if not cpe: return []
111111
cpe_regex = cpe
112112
final_cves = []
113+
cpe_searchField = "vulnerable_product" if vulnProdSearch else "vulnerable_configuration"
113114
if lax:
114115
# get target version from product description provided by the user
115116
target_version = cpe.split(":")[-1]
@@ -127,12 +128,13 @@ def cvesForCPE(cpe, lax=False):
127128

128129
# over-approximate versions
129130
final_cves = []
130-
cpe_regex = product
131-
cves = colCVE.find({"vulnerable_configuration": {"$regex": cpe_regex}}).sort("Modified", -1)
131+
cpe_regex = product
132+
cves = colCVE.find({cpe_searchField: {"$regex": cpe_regex}}).sort("Modified", -1)
132133
i = 0
133134
for cve in cves:
134135
vuln_confs = cve["vulnerable_configuration"]
135136
vuln_confs += cve["vulnerable_configuration_cpe_2_2"]
137+
vuln_confs += cve["vulnerable_product"]
136138
i += 1
137139
for vc in vuln_confs:
138140
if not cpe_regex in vc:
@@ -157,7 +159,7 @@ def cvesForCPE(cpe, lax=False):
157159

158160
else:
159161
# default strict search
160-
cves = colCVE.find({"vulnerable_configuration": {"$regex": cpe_regex}}).sort("Modified", -1)
162+
cves = colCVE.find({cpe_searchField: {"$regex": cpe_regex}}).sort("Modified", -1)
161163
final_cves = cves
162164

163165
return sanitize(final_cves)

sbin/db_mgmt.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(self):
6363
self.inCVSSElem = 0
6464
self.inSUMMElem = 0
6565
self.inDTElem = 0
66+
self.inVPElem = 0
6667
self.inPUBElem = 0
6768
self.inAccessvElem = 0
6869
self.inAccesscElem = 0
@@ -74,11 +75,15 @@ def __init__(self):
7475

7576
def startElement(self, name, attrs):
7677
if name == 'entry':
77-
self.cves.append({'id': attrs.get('id'), 'references': [], 'vulnerable_configuration': [], 'vulnerable_configuration_cpe_2_2':[]})
78+
self.cves.append({'id': attrs.get('id'), 'references': [], 'vulnerable_configuration': [],
79+
'vulnerable_configuration_cpe_2_2':[], 'vulnerable_product':[] })
7880
self.ref = attrs.get('id')
7981
elif name == 'cpe-lang:fact-ref':
8082
self.cves[-1]['vulnerable_configuration'].append(toStringFormattedCPE(attrs.get('name')))
8183
self.cves[-1]['vulnerable_configuration_cpe_2_2'].append(attrs.get('name'))
84+
elif name=='vuln:product':
85+
self.inVPElem = 1
86+
self.VP = ""
8287
elif name == 'cvss:score':
8388
self.inCVSSElem = 1
8489
self.CVSS = ""
@@ -120,6 +125,8 @@ def startElement(self, name, attrs):
120125
def characters(self, ch):
121126
if self.inCVSSElem:
122127
self.CVSS += ch
128+
if self.inVPElem:
129+
self.VP += ch
123130
if self.inSUMMElem:
124131
self.SUMM += ch
125132
if self.inDTElem:
@@ -145,6 +152,9 @@ def endElement(self, name):
145152
if name == 'cvss:score':
146153
self.inCVSSElem = 0
147154
self.cves[-1]['cvss'] = self.CVSS
155+
if name == 'vuln:product':
156+
self.inVPElem = 0
157+
self.cves[-1]['vulnerable_product'].append(self.VP)
148158
if name == 'cvss:access-vector':
149159
self.inAccessvElem = 0
150160
if 'access' not in self.cves[-1]:

sbin/db_mgmt_create_index.py

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def setIndex(col, field, printSuccess = True):
3030
setIndex('cpeother', 'id')
3131
setIndex('cves', 'id')
3232
setIndex('cves', 'vulnerable_configuration')
33+
setIndex('cves', 'vulnerable_product')
3334
setIndex('cves', 'Modified')
3435
setIndex('cves', [("summary",TEXT)])
3536
setIndex('via4', 'id')

0 commit comments

Comments
 (0)