This repository was archived by the owner on Nov 7, 2024. It is now read-only.
forked from ptdropper/CVE-Scanner-for-your-SW-BOM
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcve_lookup.py
More file actions
148 lines (127 loc) · 4.26 KB
/
cve_lookup.py
File metadata and controls
148 lines (127 loc) · 4.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from __future__ import print_function
import sys
import re
from collections import defaultdict
# preload XML
import xml.etree.cElementTree as ET
import defusedxml.cElementTree as DET
import re
import glob
xmlstring = []
def parse_dbs(folder):
"""
parse the XML dbs and build an in-memory lookup
:param folder: the folder full of *.xml files
:return:
"""
root = None
for filename in glob.glob(folder+'/*.xml'):
with open(filename) as f:
db_string = f.read() # remove the annoying namespace
db_string = re.sub(' xmlns="[^"]+"', '', db_string, count=1)
# xmlstring.append(db_string)
data = ET.fromstring(db_string)
if root is None:
root = data
else:
root.extend(data)
return root
#root = ET.fromstring("\n".join(xmlstring))
# namespace ="http://nvd.nist.gov/feeds/cve/1.2"
def etree_to_dict(t):
"""
Change the xml tree to an easy to use python dict
:param t: the xml tree
:return: a dict representation
"""
d = {t.tag: {} if t.attrib else None}
children = list(t)
if children:
dd = defaultdict(list)
for dc in map(etree_to_dict, children):
for k, v in dc.iteritems():
dd[k].append(v)
d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in dd.iteritems()}}
if t.attrib:
d[t.tag].update(('@' + k, v) for k, v in t.attrib.iteritems())
if t.text:
text = t.text.strip()
if children or t.attrib:
if text:
d[t.tag]['#text'] = text
else:
d[t.tag] = text
return d
def get_packages_swid(package_list):
"""
Get the packages from a swid string
:param package_strs:
:return:
"""
package_xml = None
packages = defaultdict(set)
errors = []
for xml_doc in package_list.split("\n"):
try:
#print('Hello 81 xml_doc="{0}"',format(xml_doc))
# remove the <? ?> if any
xml_doc = re.sub('<\?[^>]+\?>', '', xml_doc)
# use DET since this is untrusted data
data = DET.fromstring(xml_doc)
""""""
name, version = data.attrib['name'], data.attrib['version']
#print('87 name="{0}" version="{1}"'.format(data.attrib['name'], data.attrib['version']))
version = version.split("-")[0]
packages[name].add(version)
except Exception as e:
errors.append(str(e))
return errors, packages
def get_packages_rpm(package_list):
"""
Get the packages from an rpm string
:param package_strs:
:return:
"""
package_strs = package_list.split("\n")
packages = defaultdict(set)
errors = []
for x in package_strs:
m = re.search(r'(.*)-(.*)-(.*)', x)
if m:
(vendor, name, version) = m.groups()
#path = path or ''
verrel = version
packages[name].add(version)
#print ('118',format([vendor, name, version ]))
else:
errors.append('ERROR: Invalid name: %s\n' % x)
return errors, packages
def get_package_dict(package_list):
"""
Get the packages from the string
:param package_strs:
:return:
"""
if package_list.startswith("<?xml"):
return get_packages_swid(package_list)
else:
return get_packages_rpm(package_list)
def get_vulns(packages, root):
"""
Get the vulns from a list of packages returned by get_package_dict()
:param packages:
:return:
"""
result = defaultdict(list)
for entry in root:
for vuln_soft in entry.findall("vuln_soft"):
for prod in vuln_soft.findall("prod"):
if prod.attrib['name'] in packages:
vers = set([x.attrib['num'] for x in prod.findall("vers")])
#print('149 prod="{0}" vers="{1}"'.format(prod.attrib['name'], vers))
intersection = set(vers).intersection(packages[prod.attrib['name']])
#print('intersection="{0}"'.format(intersection))
if len(intersection) > 0:
si = ' - ' + ','.join(intersection)
result[prod.attrib['name'] + si].append(etree_to_dict(entry)["entry"])
return result