Mercurial > farol > farolluz
comparison farolluz/parsers/cve.py @ 43:b87f2a6e613a
Add CVE parsing (from OpenVAS GSA)
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Mon, 29 Dec 2014 16:33:34 +0100 |
parents | |
children | b7e64d0a3a7c |
comparison
equal
deleted
inserted
replaced
42:9ed24f48df01 | 43:b87f2a6e613a |
---|---|
1 # -*- coding: utf-8 -*- | |
2 # Description: | |
3 # Methods for parsing CVE XML documents | |
4 # | |
5 # Authors: | |
6 # BenoƮt Allard <benoit.allard@greenbone.net> | |
7 # | |
8 # Copyright: | |
9 # Copyright (C) 2014 Greenbone Networks GmbH | |
10 # | |
11 # This program is free software; you can redistribute it and/or | |
12 # modify it under the terms of the GNU General Public License | |
13 # as published by the Free Software Foundation; either version 2 | |
14 # of the License, or (at your option) any later version. | |
15 # | |
16 # This program is distributed in the hope that it will be useful, | |
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 # GNU General Public License for more details. | |
20 # | |
21 # You should have received a copy of the GNU General Public License | |
22 # along with this program; if not, write to the Free Software | |
23 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
24 | |
25 """\ | |
26 Methods for parsing of CVE XML Documents | |
27 | |
28 Ref: http://scap.nist.gov/schema/vulnerability/0.4 | |
29 """ | |
30 | |
31 from __future__ import absolute_import | |
32 | |
33 import xml.etree.ElementTree as ET | |
34 | |
35 from .xml import parseDate | |
36 | |
37 from ..common import CVRFNote, CVRFReference | |
38 from ..document import CVRF, CVRFPublisher, CVRFTracking, CVRFTrackingID, CVRFRevision | |
39 from ..producttree import CVRFFullProductName | |
40 from ..utils import utcnow | |
41 from ..vulnerability import CVRFVulnerability, CVRFCVSSSet, CVRFCWE, CVRFProductStatus | |
42 | |
43 NAMESPACES = { | |
44 'cve': "http://scap.nist.gov/schema/feed/vulnerability/2.0", | |
45 'vuln': "http://scap.nist.gov/schema/vulnerability/0.4", | |
46 'cvss': "http://scap.nist.gov/schema/cvss-v2/0.2", | |
47 'xml': "http://www.w3.org/XML/1998/namespace", | |
48 } | |
49 | |
50 | |
51 def UN(ns, name): | |
52 """ returns a Universal Name """ | |
53 return "{%s}%s" % (NAMESPACES[ns], name) | |
54 | |
55 def parseCVSS(xmlElem): | |
56 """ Make a vector out of a list of elements """ | |
57 def get(name): | |
58 return xmlElem.findtext('/'.join([UN('cvss', 'base_metrics'), UN('cvss', name)])) | |
59 | |
60 cvss_set = CVRFCVSSSet(float(get('score'))) | |
61 vector = [ | |
62 'AV:%s' % {'LOCAL': 'L', | |
63 'ADJACENT_NETWORK': 'A', | |
64 'NETWORK': 'N'}[get('access-vector')], | |
65 'AC:%s' % {'HIGH': 'H', | |
66 'MEDIUM': 'M', | |
67 'LOW': 'L'}[get('access-complexity')], | |
68 'Au:%s' % {'MULTIPLE': 'M', | |
69 'SINGLE': 'S', | |
70 'NONE': 'N'}[get('authentication')], | |
71 'C:%s' % {'NONE': 'N', | |
72 'PARTIAL': 'P', | |
73 'COMPLETE': 'C'}[get('confidentiality-impact')], | |
74 'I:%s' % {'NONE': 'N', | |
75 'PARTIAL': 'P', | |
76 'COMPLETE': 'C'}[get('integrity-impact')], | |
77 'A:%s' % {'NONE': 'N', | |
78 'PARTIAL': 'P', | |
79 'COMPLETE': 'C'}[get('availability-impact')], | |
80 ] | |
81 cvss_set.setVector('/'.join(vector)) | |
82 return cvss_set | |
83 | |
84 def parseXML(data): | |
85 """ returns am ET.Element from the input stuff. | |
86 input can be: | |
87 - a string | |
88 - a file handle | |
89 - an ET.Element instance | |
90 """ | |
91 if isinstance(data, ET.Element): | |
92 return data | |
93 # To allow passing file handles | |
94 if hasattr(data, 'read'): | |
95 data = data.read() | |
96 # Parse it. | |
97 return ET.fromstring(data) | |
98 | |
99 def parse_CVE_from_GSA(data): | |
100 xml = parseXML(data) | |
101 return parse(xml.find('/'.join(['get_info', 'get_info_response', 'info', 'cve', 'raw_data', UN('cve', 'entry')]))) | |
102 | |
103 def parse(xml): | |
104 xml = parseXML(xml) | |
105 | |
106 # Create an extra-minimal document | |
107 doc = CVRF(xml.findtext(UN('vuln', 'cve-id')), | |
108 'Vulnerability Description') | |
109 pub = CVRFPublisher("Other") | |
110 doc.setPublisher(pub) | |
111 now = utcnow() | |
112 tracking = CVRFTracking( | |
113 CVRFTrackingID('000000'), | |
114 "Draft", | |
115 (0,), | |
116 now, now | |
117 ) | |
118 doc.setTracking(tracking) | |
119 tracking.addRevision(CVRFRevision((0,), now, 'Document created')) | |
120 | |
121 # Add the CVE to that document | |
122 return addToDoc(doc, xml) | |
123 | |
124 def addToDoc(doc, xml): | |
125 """ Adds the CVE as vulnerability in the document """ | |
126 xml = parseXML(xml) | |
127 | |
128 vulnid = xml.attrib['id'] | |
129 | |
130 # Get a new ordinal for our new Vulnerability | |
131 if len(doc._vulnerabilities) == 0: | |
132 ordinal = 1 | |
133 else: | |
134 ordinal = doc._vulnerabilities[-1]._ordinal + 1 | |
135 | |
136 # Create a Vulnerability | |
137 vuln = CVRFVulnerability(ordinal) | |
138 doc.addVulnerability(vuln) | |
139 | |
140 vulnerable_products = [] | |
141 # Set the vulnerable products in productTree | |
142 for i, cpe in enumerate(xml.findall( | |
143 '/'.join([UN('vuln', 'vulnerable-software-list'), | |
144 UN('vuln', 'product')]))): | |
145 if doc._producttree is None: | |
146 doc.createProductTree() | |
147 try: | |
148 prod = doc._producttree.getProductForCPE(cpe.text) | |
149 except KeyError: | |
150 prod = CVRFFullProductName('%s-P%d' % (vulnid, i), cpe.text, doc._producttree, cpe.text) | |
151 doc._producttree.addProduct(prod) | |
152 vulnerable_products.append(prod) | |
153 | |
154 if vulnerable_products: | |
155 status = CVRFProductStatus('Known Affected') | |
156 for product in vulnerable_products: | |
157 status.addProductID(product._productid) | |
158 vuln.addProductStatus(status) | |
159 | |
160 # Add the CVE-id | |
161 vuln.setCVE(xml.findtext(UN('vuln', 'cve-id'))) | |
162 | |
163 # The release date | |
164 vuln.setReleaseDate(parseDate(xml.findtext(UN('vuln', 'published-datetime')))) | |
165 | |
166 # Add the CVSS | |
167 xmlcvss = xml.find(UN('vuln', 'cvss')) | |
168 if xmlcvss is not None: | |
169 vuln.addCVSSSet(parseCVSS(xmlcvss)) | |
170 | |
171 # Add the CWE id | |
172 xmlcwe = xml.find(UN('vuln', 'cwe')) | |
173 if xmlcwe is not None: | |
174 # XXX: Get a Description for the CWE ! | |
175 vuln.addCWE(CVRFCWE(xmlcwe.attrib['id'], xmlcwe.attrib['id'])) | |
176 | |
177 # Add references | |
178 for xmlref in xml.findall(UN('vuln', 'references')): | |
179 vuln.addReference(CVRFReference(xmlref.find(UN('vuln','reference')).attrib['href'], | |
180 xmlref.findtext(UN('vuln', 'reference')))) | |
181 | |
182 xmlsummary = xml.findtext(UN('vuln', 'summary')) | |
183 if xmlsummary is not None: | |
184 vuln.addNote(CVRFNote( | |
185 'Summary', | |
186 1, | |
187 xmlsummary | |
188 )) | |
189 | |
190 return doc |