Mercurial > farol > farolluz
annotate farolluz/vulnerability.py @ 28:e317097af486
Vulnerability: remove unused functionnality
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Mon, 27 Oct 2014 11:23:33 +0100 |
parents | 809db989cac5 |
children | 2e36289616db |
rev | line source |
---|---|
0 | 1 # -*- coding: utf-8 -*- |
2 # | |
3 # Authors: | |
4 # BenoƮt Allard <benoit.allard@greenbone.net> | |
5 # | |
6 # Copyright: | |
7 # Copyright (C) 2014 Greenbone Networks GmbH | |
8 # | |
9 # This program is free software; you can redistribute it and/or | |
10 # modify it under the terms of the GNU General Public License | |
11 # as published by the Free Software Foundation; either version 2 | |
12 # of the License, or (at your option) any later version. | |
13 # | |
14 # This program is distributed in the hope that it will be useful, | |
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 # GNU General Public License for more details. | |
18 # | |
19 # You should have received a copy of the GNU General Public License | |
20 # along with this program; if not, write to the Free Software | |
21 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
22 | |
23 """\ | |
26
809db989cac5
Reorganize the code in smaller mpodules
Benoît Allard <benoit.allard@greenbone.net>
parents:
22
diff
changeset
|
24 Vulnerability Objects related to CVRF Documents |
0 | 25 """ |
26 | |
26
809db989cac5
Reorganize the code in smaller mpodules
Benoît Allard <benoit.allard@greenbone.net>
parents:
22
diff
changeset
|
27 from .common import ValidationError |
809db989cac5
Reorganize the code in smaller mpodules
Benoît Allard <benoit.allard@greenbone.net>
parents:
22
diff
changeset
|
28 from .document import CVRFPublisher |
0 | 29 |
30 | |
31 class CVRFVulnerabilityID(object): | |
32 def __init__(self, systemname, value): | |
33 self._systemname = systemname | |
34 self._value = value | |
35 | |
36 def validate(self): | |
37 if not self._systemname: | |
38 raise ValidationError('A Vulnerability ID must have a System Name') | |
39 if not self._value: | |
40 raise ValidationError('A Vulnerability ID must have a value') | |
41 | |
42 | |
43 class CVRFVulnerability(object): | |
44 def __init__(self, ordinal): | |
45 self._ordinal = ordinal | |
46 self._title = None | |
47 self._id = None | |
48 self._notes = [] | |
49 self._discoverydate = None | |
50 self._releasedate = None | |
51 self._involvements = [] | |
52 self._cve = None | |
53 self._cwes = [] | |
54 self._productstatuses = [] | |
55 self._threats = [] | |
56 self._cvsss = [] | |
57 self._remediations = [] | |
58 self._references = [] | |
59 self._acknowledgments = [] | |
60 | |
61 def setTitle(self, title): | |
62 self._title = title | |
63 | |
64 def setID(self, _id): | |
65 self._id = _id | |
66 | |
67 def addNote(self, note): | |
68 self._notes.append(note) | |
69 | |
70 def setDiscoveryDate(self, date): | |
71 self._discoverydate = date | |
72 | |
73 def setReleaseDate(self, date): | |
74 self._releasedate = date | |
75 | |
76 def addInvolvement(self, involvement): | |
77 self._involvements.append(involvement) | |
78 | |
79 def setCVE(self, cve): | |
80 self._cve = cve | |
81 | |
82 def addCWE(self, cwe): | |
83 self._cwes.append(cwe) | |
84 | |
85 def addProductStatus(self, productstatus): | |
86 self._productstatuses.append(productstatus) | |
87 | |
88 def addThreat(self, threat): | |
89 self._threats.append(threat) | |
90 | |
91 def addCVSSSet(self, cvss_set): | |
92 self._cvsss.append(cvss_set) | |
93 | |
94 def addRemediation(self, remediation): | |
95 self._remediations.append(remediation) | |
96 | |
97 def addReference(self, ref): | |
98 self._references.append(ref) | |
99 | |
100 def addAcknowledgment(self, ack): | |
101 self._acknowledgments.append(ack) | |
102 | |
103 def getTitle(self): | |
104 """ return something that can be used as a title """ | |
105 if self._title: | |
106 if self._id: | |
107 return "%s (%s)" % (self._title, self._id._value) | |
108 return self._title | |
109 if self._id: | |
110 return self._id._value | |
111 return "#%d" % self._ordinal | |
112 | |
7
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
113 def getNote(self, ordinal): |
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
114 for note in self._notes: |
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
115 if note._ordinal == ordinal: |
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
116 return note |
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
117 return None |
c924c15bd110
Add a method to get a Vulnerability Note per ordinal
Benoît Allard <benoit.allard@greenbone.net>
parents:
6
diff
changeset
|
118 |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
119 def mentionsProdId(self, productid): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
120 """ Returns in which sub element, self is mentioning the productid """ |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
121 for category in (self._productstatuses, self._threats, self._cvsss, self._remediations): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
122 for subelem in category: |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
123 if productid in subelem._productids: |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
124 yield subelem |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
125 |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
126 def isMentioningProdId(self, productid): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
127 """ Returns if self is mentioning the productid """ |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
128 for e in self.mentionsProdId(productid): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
129 # We only need to know if the generator yield at least one elem. |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
130 return True |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
131 return False |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
132 |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
133 def mentionsGroupId(self, groupid): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
134 for category in (self._threats, self._remediations): |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
135 for subelem in category: |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
136 if groupid in subelem._groupids: |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
137 yield subelem |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
138 |
28
e317097af486
Vulnerability: remove unused functionnality
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
139 def isMentioningGroupId(self, groupid): |
e317097af486
Vulnerability: remove unused functionnality
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
140 for _ in self.mentionsGroupId(groupid): |
e317097af486
Vulnerability: remove unused functionnality
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
141 # We only need to know if the generator yield at least one elem. |
e317097af486
Vulnerability: remove unused functionnality
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
142 return True |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
143 return False |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
144 |
0 | 145 def validate(self, productids, groupids): |
146 if not self._ordinal: | |
147 raise ValidationError('A Vulnerability must have an ordinal') | |
148 if self._id is not None: | |
149 self._id.validate() | |
150 ordinals = set() | |
151 for note in self._notes: | |
152 note.validate() | |
153 if note._ordinal in ordinals: | |
154 raise ValidationError('Vulnerability Note Ordinal %d duplicated' % note._ordinal) | |
155 ordinals.add(note._ordinal) | |
156 for involvement in self._involvements: | |
157 involvement.validate() | |
158 for cwe in self._cwes: | |
159 cwe.validate() | |
160 for status in self._productstatuses: | |
161 status.validate(productids) | |
13
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
162 pids = set() |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
163 for status in self._productstatuses: |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
164 for pid in status._productids: |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
165 if pid in pids: |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
166 raise ValidationError('ProductID %s mentionned in two different ProductStatuses for Vulnerability %d' % (pid, self._ordinal)) |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
167 pids.add(pid) |
0 | 168 for threat in self._threats: |
169 threat.validate(productids, groupids) | |
170 for cvss in self._cvsss: | |
171 cvss.validate(productids) | |
14
640b88744523
Fix issue in validation of CVSS Score Sets
Benoît Allard <benoit.allard@greenbone.net>
parents:
13
diff
changeset
|
172 pids = set() |
13
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
173 for cvss in self._cvsss: |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
174 for pid in (cvss._productids or productids): |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
175 if pid in pids: |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
176 raise ValidationError('ProductID %s mentionned in two different CVSS Score Sets for Vulnerability %d' % (pid, self._ordinal)) |
db2a02fff101
Improve validation
Benoît Allard <benoit.allard@greenbone.net>
parents:
8
diff
changeset
|
177 pids.add(pid) |
0 | 178 for remediation in self._remediations: |
179 remediation.validate(productids, groupids) | |
180 for reference in self._references: | |
181 reference.validate() | |
182 for acknowledgment in self._acknowledgments: | |
183 acknowledgment.validate() | |
184 | |
185 | |
186 class CVRFInvolvement(object): | |
187 PARTIES = CVRFPublisher.TYPES | |
188 STATUSES = ('Open', 'Disputed', 'In Progress', 'Completed', | |
189 'Contact Attempted', 'Not Contacted') | |
190 def __init__(self, party, status): | |
191 self._party = party | |
192 self._status = status | |
193 self._description = None | |
194 | |
195 def setDescription(self, description): | |
196 self._description = description | |
197 | |
198 def getTitle(self): | |
199 return "From %s: %s" % (self._party, self._status) | |
200 | |
201 def validate(self): | |
202 if not self._party: | |
203 raise ValidationError('An Involvement must have a Party') | |
204 if self._party not in self.PARTIES: | |
205 raise ValidationError("An Involvement's Party must be one of %s" % ', '.join(self.PARTIES)) | |
206 if not self._status: | |
207 raise ValidationError('An Involvement must have a Status') | |
208 if self._status not in self.STATUSES: | |
209 raise ValidationError("An Involvement's Status must be one of %s" % ', '.join(self.STATUSES)) | |
210 | |
211 | |
212 class CVRFCWE(object): | |
213 def __init__(self, _id, value): | |
214 self._id = _id | |
215 self._value = value | |
216 | |
217 def validate(self): | |
218 if not self._id: | |
219 raise ValidationError('A CWE must have an ID') | |
220 if not self._value: | |
221 raise ValidationError('A CWE must have a description') | |
222 | |
223 | |
224 class CVRFProductStatus(object): | |
225 TYPES = ('First Affected', 'Known Affected', 'Known Not Affected', | |
226 'First Fixed', 'Fixed', 'Recommended', 'Last Affected') | |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
227 NAME = "Product Status" |
0 | 228 def __init__(self, _type): |
229 self._type = _type | |
230 self._productids = [] | |
231 | |
232 def addProductID(self, productid): | |
233 self._productids.append(productid) | |
234 | |
235 def getTitle(self): | |
236 return "%s: %d products" % (self._type, len(self._productids)) | |
237 | |
238 def validate(self, productids): | |
239 if not self._type: | |
240 raise ValidationError('A Product Status must have a Type') | |
241 if self._type not in self.TYPES: | |
242 raise ValidationError("A Product Status' Type must be one of %s" % ', '.join(self.TYPES)) | |
243 if len(self._productids) < 1: | |
244 raise ValidationError('A Product Status must mention at least one Product') | |
245 for productid in self._productids: | |
246 if productid not in productids: | |
247 raise ValidationError('Unknown ProductID: %s' % productid) | |
248 | |
249 | |
250 class CVRFThreat(object): | |
251 TYPES = ('Impact', 'Exploit Status', 'Target Set') | |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
252 NAME = "Threat" |
0 | 253 def __init__(self, _type, description): |
254 self._type = _type | |
255 self._description = description | |
256 self._date = None | |
257 self._productids = [] | |
258 self._groupids = [] | |
259 | |
260 def setDate(self, date): | |
261 self._date = date | |
262 | |
263 def addProductID(self, productid): | |
264 self._productids.append(productid) | |
265 | |
266 def addGroupID(self, groupid): | |
267 self._groupids.append(groupid) | |
268 | |
269 def getTitle(self): | |
270 return self._type | |
271 | |
272 def validate(self, productids, groupids): | |
273 if not self._type: | |
274 raise ValidationError('A Threat must have a Type') | |
275 if self._type not in self.TYPES: | |
276 raise ValidationError("A Threat's Type must be one of %s" % ', '.join(self.TYPES)) | |
277 if not self._description: | |
278 raise ValidationError('A Threat must have a Description') | |
279 for productid in self._productids: | |
280 if productid not in productids: | |
281 raise ValidationError('Unknown ProductID: %s' % productid) | |
282 for groupid in self._groupids: | |
283 if groupid not in groupids: | |
284 raise ValidationError('Unknown GroupID: %s' % groupid) | |
285 | |
286 | |
287 class CVRFCVSSSet(object): | |
288 # To determine the base Score | |
289 VALUES = {'AV': {'L':0.395, 'A':0.646, 'N':1.0}, | |
290 'AC': {'H':0.35, 'M':0.61 ,'L':0.71}, | |
291 'Au': {'M':0.45, 'S':0.56, 'N':0.704}, | |
292 'C': {'N':0.0, 'P':0.275, 'C':0.66}, | |
293 'I': {'N':0.0, 'P':0.275, 'C':0.66}, | |
294 'A': {'N':0.0, 'P':0.275, 'C':0.66}} | |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
295 NAME = "CVSS Score Set" |
0 | 296 def __init__(self, basescore): |
297 self._basescore = basescore | |
298 self._temporalscore = None | |
299 self._environmentalscore = None | |
300 self._vector = None | |
301 self.vector = None | |
302 self._productids = [] | |
303 | |
304 def setTemporalScore(self, tempscore): | |
305 self._temporalscore = tempscore | |
306 | |
307 def setEnvironmentalScore(self, envscore): | |
308 self._environmentalscore = envscore | |
309 | |
310 def setVector(self, vector): | |
311 self._vector = vector | |
312 if vector is None: | |
313 self.vector = vector | |
314 return | |
315 try: | |
316 self.vector = {} | |
317 for component in vector[:26].split('/'): | |
318 name, value = component.split(':') | |
319 self.vector[name] = self.VALUES[name][value] | |
320 except (KeyError, ValueError): | |
321 self.vector = None | |
322 | |
323 def addProductID(self, productid): | |
324 self._productids.append(productid) | |
325 | |
326 def baseScore(self): | |
327 v = self.vector # make an alias for shorter lines | |
328 exploitability = 20 * v['AV'] * v['AC'] * v['Au'] | |
329 impact = 10.41 * (1 - (1 - v['C']) * (1 - v['I']) * (1 - v['A'])) | |
330 def f(i): return 0 if i == 0 else 1.176 | |
331 return ((0.6 * impact) + (0.4 * exploitability) - 1.5) * f(impact) | |
332 | |
333 def validate(self, productids): | |
334 if not self._basescore: | |
335 raise ValidationError('A CVSS Score Set must have a Base Score') | |
336 if self._vector and not self.vector: | |
337 raise ValidationError('Syntax Error in CVSS Vector') | |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
338 if self.vector and (abs(self._basescore - self.baseScore()) >= 0.05): |
0 | 339 raise ValidationError('Inconsistency in CVSS Score Set between Vector (%f) and Base Score (%f)' % (self.baseScore(), self._basescore)) |
340 for productid in self._productids: | |
341 if productid not in productids: | |
342 raise ValidationError('Unknown ProductID: %s' % productid) | |
343 | |
344 | |
345 class CVRFRemediation(object): | |
346 TYPES = ('Workaround', 'Mitigation', 'Vendor Fix', 'None Available', | |
347 'Will Not Fix') | |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
348 NAME = "Remediation" |
0 | 349 def __init__(self, _type, description): |
350 self._type = _type | |
351 self._description = description | |
352 self._date = None | |
353 self._entitlement = None | |
354 self._url = None | |
355 self._productids = [] | |
356 self._groupids = [] | |
357 | |
358 def setDate(self, date): | |
359 self._date = date | |
360 | |
361 def setEntitlement(self, entitlement): | |
362 self._entitlement = entitlement | |
363 | |
364 def setURL(self, url): | |
365 self._url = url | |
366 | |
367 def addProductID(self, productid): | |
368 self._productids.append(productid) | |
369 | |
370 def addGroupID(self, groupid): | |
371 self._groupids.append(groupid) | |
372 | |
373 def getTitle(self): | |
374 return self._type | |
375 | |
376 def validate(self, productids, groupids): | |
377 if not self._type: | |
378 raise ValidationError('A Remediation must have a Type') | |
379 if self._type not in self.TYPES: | |
380 raise ValidationError("A Remediation's Type must be one of %s" % ', '.join(self.TYPES)) | |
381 if not self._description: | |
382 raise ValidationError('A Remediation must have a Description') | |
383 for productid in self._productids: | |
384 if productid not in productids: | |
385 raise ValidationError('Unknown ProductID: %s' % productid) | |
386 for groupid in self._groupids: | |
387 if groupid not in groupids: | |
388 raise ValidationError('Unknown GroupID: %s' % groupid) | |
389 |