[PATCH 44 of 54] Add CVE parsing (from OpenVAS GSA)
Wald Commits
scm-commit at wald.intevation.org
Wed Jan 7 10:57:01 CET 2015
# HG changeset patch
# User Benoît Allard <benoit.allard at greenbone.net>
# Date 1419867214 -3600
# Node ID b87f2a6e613a0399b3ca2431583fe59d9d193036
# Parent 9ed24f48df016a415524db9b192b679df9a5dea3
Add CVE parsing (from OpenVAS GSA)
diff -r 9ed24f48df01 -r b87f2a6e613a CHANGES
--- a/CHANGES Mon Dec 29 15:00:59 2014 +0100
+++ b/CHANGES Mon Dec 29 16:33:34 2014 +0100
@@ -4,6 +4,7 @@
Main changes since FarolLuz 1.0:
--------------------------------
* Add parsing for CPE.
+* Add parsing for CVEs format from the OpenVAS Greenbone Security Manager.
FarolLuz 1.0 (2014-11-05)
diff -r 9ed24f48df01 -r b87f2a6e613a farolluz/document.py
--- a/farolluz/document.py Mon Dec 29 15:00:59 2014 +0100
+++ b/farolluz/document.py Mon Dec 29 16:33:34 2014 +0100
@@ -82,6 +82,7 @@
class CVRFTracking(object):
STATUSES = ('Draft', 'Interim', 'Final')
def __init__(self, _id, status, version, initial, current):
+ """ version must be a tuple of (max four) ints """
self._identification = _id
self._status = status
self._version = version
@@ -148,6 +149,7 @@
class CVRFRevision(object):
def __init__(self, number, date, description):
+ """ number is a tuple of (max four) ints """
self._number = number
self._date = date
self._description = description
diff -r 9ed24f48df01 -r b87f2a6e613a farolluz/parsers/cve.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/parsers/cve.py Mon Dec 29 16:33:34 2014 +0100
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+# Description:
+# Methods for parsing CVE XML documents
+#
+# Authors:
+# Benoît Allard <benoit.allard at greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""\
+Methods for parsing of CVE XML Documents
+
+Ref: http://scap.nist.gov/schema/vulnerability/0.4
+"""
+
+from __future__ import absolute_import
+
+import xml.etree.ElementTree as ET
+
+from .xml import parseDate
+
+from ..common import CVRFNote, CVRFReference
+from ..document import CVRF, CVRFPublisher, CVRFTracking, CVRFTrackingID, CVRFRevision
+from ..producttree import CVRFFullProductName
+from ..utils import utcnow
+from ..vulnerability import CVRFVulnerability, CVRFCVSSSet, CVRFCWE, CVRFProductStatus
+
+NAMESPACES = {
+ 'cve': "http://scap.nist.gov/schema/feed/vulnerability/2.0",
+ 'vuln': "http://scap.nist.gov/schema/vulnerability/0.4",
+ 'cvss': "http://scap.nist.gov/schema/cvss-v2/0.2",
+ 'xml': "http://www.w3.org/XML/1998/namespace",
+}
+
+
+def UN(ns, name):
+ """ returns a Universal Name """
+ return "{%s}%s" % (NAMESPACES[ns], name)
+
+def parseCVSS(xmlElem):
+ """ Make a vector out of a list of elements """
+ def get(name):
+ return xmlElem.findtext('/'.join([UN('cvss', 'base_metrics'), UN('cvss', name)]))
+
+ cvss_set = CVRFCVSSSet(float(get('score')))
+ vector = [
+ 'AV:%s' % {'LOCAL': 'L',
+ 'ADJACENT_NETWORK': 'A',
+ 'NETWORK': 'N'}[get('access-vector')],
+ 'AC:%s' % {'HIGH': 'H',
+ 'MEDIUM': 'M',
+ 'LOW': 'L'}[get('access-complexity')],
+ 'Au:%s' % {'MULTIPLE': 'M',
+ 'SINGLE': 'S',
+ 'NONE': 'N'}[get('authentication')],
+ 'C:%s' % {'NONE': 'N',
+ 'PARTIAL': 'P',
+ 'COMPLETE': 'C'}[get('confidentiality-impact')],
+ 'I:%s' % {'NONE': 'N',
+ 'PARTIAL': 'P',
+ 'COMPLETE': 'C'}[get('integrity-impact')],
+ 'A:%s' % {'NONE': 'N',
+ 'PARTIAL': 'P',
+ 'COMPLETE': 'C'}[get('availability-impact')],
+ ]
+ cvss_set.setVector('/'.join(vector))
+ return cvss_set
+
+def parseXML(data):
+ """ returns am ET.Element from the input stuff.
+ input can be:
+ - a string
+ - a file handle
+ - an ET.Element instance
+ """
+ if isinstance(data, ET.Element):
+ return data
+ # To allow passing file handles
+ if hasattr(data, 'read'):
+ data = data.read()
+ # Parse it.
+ return ET.fromstring(data)
+
+def parse_CVE_from_GSA(data):
+ xml = parseXML(data)
+ return parse(xml.find('/'.join(['get_info', 'get_info_response', 'info', 'cve', 'raw_data', UN('cve', 'entry')])))
+
+def parse(xml):
+ xml = parseXML(xml)
+
+ # Create an extra-minimal document
+ doc = CVRF(xml.findtext(UN('vuln', 'cve-id')),
+ 'Vulnerability Description')
+ pub = CVRFPublisher("Other")
+ doc.setPublisher(pub)
+ now = utcnow()
+ tracking = CVRFTracking(
+ CVRFTrackingID('000000'),
+ "Draft",
+ (0,),
+ now, now
+ )
+ doc.setTracking(tracking)
+ tracking.addRevision(CVRFRevision((0,), now, 'Document created'))
+
+ # Add the CVE to that document
+ return addToDoc(doc, xml)
+
+def addToDoc(doc, xml):
+ """ Adds the CVE as vulnerability in the document """
+ xml = parseXML(xml)
+
+ vulnid = xml.attrib['id']
+
+ # Get a new ordinal for our new Vulnerability
+ if len(doc._vulnerabilities) == 0:
+ ordinal = 1
+ else:
+ ordinal = doc._vulnerabilities[-1]._ordinal + 1
+
+ # Create a Vulnerability
+ vuln = CVRFVulnerability(ordinal)
+ doc.addVulnerability(vuln)
+
+ vulnerable_products = []
+ # Set the vulnerable products in productTree
+ for i, cpe in enumerate(xml.findall(
+ '/'.join([UN('vuln', 'vulnerable-software-list'),
+ UN('vuln', 'product')]))):
+ if doc._producttree is None:
+ doc.createProductTree()
+ try:
+ prod = doc._producttree.getProductForCPE(cpe.text)
+ except KeyError:
+ prod = CVRFFullProductName('%s-P%d' % (vulnid, i), cpe.text, doc._producttree, cpe.text)
+ doc._producttree.addProduct(prod)
+ vulnerable_products.append(prod)
+
+ if vulnerable_products:
+ status = CVRFProductStatus('Known Affected')
+ for product in vulnerable_products:
+ status.addProductID(product._productid)
+ vuln.addProductStatus(status)
+
+ # Add the CVE-id
+ vuln.setCVE(xml.findtext(UN('vuln', 'cve-id')))
+
+ # The release date
+ vuln.setReleaseDate(parseDate(xml.findtext(UN('vuln', 'published-datetime'))))
+
+ # Add the CVSS
+ xmlcvss = xml.find(UN('vuln', 'cvss'))
+ if xmlcvss is not None:
+ vuln.addCVSSSet(parseCVSS(xmlcvss))
+
+ # Add the CWE id
+ xmlcwe = xml.find(UN('vuln', 'cwe'))
+ if xmlcwe is not None:
+ # XXX: Get a Description for the CWE !
+ vuln.addCWE(CVRFCWE(xmlcwe.attrib['id'], xmlcwe.attrib['id']))
+
+ # Add references
+ for xmlref in xml.findall(UN('vuln', 'references')):
+ vuln.addReference(CVRFReference(xmlref.find(UN('vuln','reference')).attrib['href'],
+ xmlref.findtext(UN('vuln', 'reference'))))
+
+ xmlsummary = xml.findtext(UN('vuln', 'summary'))
+ if xmlsummary is not None:
+ vuln.addNote(CVRFNote(
+ 'Summary',
+ 1,
+ xmlsummary
+ ))
+
+ return doc
diff -r 9ed24f48df01 -r b87f2a6e613a farolluz/producttree.py
--- a/farolluz/producttree.py Mon Dec 29 15:00:59 2014 +0100
+++ b/farolluz/producttree.py Mon Dec 29 16:33:34 2014 +0100
@@ -51,6 +51,12 @@
return product
raise KeyError(productid)
+ def getProductForCPE(self, cpe):
+ for product in self._products:
+ if product._cpe == cpe:
+ return product
+ raise KeyError(cpe)
+
def getGroupForID(self, groupid):
for group in self._groups:
if group._groupid == groupid:
diff -r 9ed24f48df01 -r b87f2a6e613a tests/testParseCVE.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testParseCVE.py Mon Dec 29 16:33:34 2014 +0100
@@ -0,0 +1,81 @@
+import utils
+
+from farolluz.parsers.cve import parse
+
+FULL_CVE = """\
+<entry xmlns:scap-core="http://scap.nist.gov/schema/scap-core/0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:patch="http://scap.nist.gov/schema/patch/0.1" xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4" xmlns:cvss="http://scap.nist.gov/schema/cvss-v2/0.2" xmlns:cpe-lang="http://cpe.mitre.org/language/2.0" xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0" id="CVE-2014-7088">
+<vuln:vulnerable-configuration id="http://nvd.nist.gov/">
+<cpe-lang:logical-test operator="OR" negate="false">
+<cpe-lang:fact-ref name="cpe:/a:jdm_lifestyle_project:jdm_lifestyle:6.4::~~~android~~"/>
+</cpe-lang:logical-test>
+</vuln:vulnerable-configuration>
+<vuln:vulnerable-software-list>
+<vuln:product>
+cpe:/a:jdm_lifestyle_project:jdm_lifestyle:6.4::~~~android~~
+</vuln:product>
+</vuln:vulnerable-software-list>
+<vuln:cve-id>CVE-2014-7088</vuln:cve-id>
+<vuln:published-datetime>2014-10-18T21:55:17.027-04:00</vuln:published-datetime>
+<vuln:last-modified-datetime>2014-11-14T09:07:51.650-05:00</vuln:last-modified-datetime>
+<vuln:cvss>
+<cvss:base_metrics>
+<cvss:score>5.4</cvss:score>
+<cvss:access-vector>ADJACENT_NETWORK</cvss:access-vector>
+<cvss:access-complexity>MEDIUM</cvss:access-complexity>
+<cvss:authentication>NONE</cvss:authentication>
+<cvss:confidentiality-impact>PARTIAL</cvss:confidentiality-impact>
+<cvss:integrity-impact>PARTIAL</cvss:integrity-impact>
+<cvss:availability-impact>PARTIAL</cvss:availability-impact>
+<cvss:source>http://nvd.nist.gov</cvss:source>
+<cvss:generated-on-datetime>2014-11-14T09:07:51.290-05:00</cvss:generated-on-datetime>
+</cvss:base_metrics>
+</vuln:cvss>
+<vuln:cwe id="CWE-310"/>
+<vuln:references reference_type="UNKNOWN" xml:lang="en">
+<vuln:source>CERT-VN</vuln:source>
+<vuln:reference href="http://www.kb.cert.org/vuls/id/582497" xml:lang="en">VU#582497</vuln:reference>
+</vuln:references>
+<vuln:references reference_type="UNKNOWN" xml:lang="en">
+<vuln:source>MISC</vuln:source>
+<vuln:reference href="https://docs.google.com/spreadsheets/d/1t5GXwjw82SyunALVJb2w0zi3FoLRIkfGPc7AMjRF0r4/edit?usp=sharing" xml:lang="en">
+https://docs.google.com/spreadsheets/d/1t5GXwjw82SyunALVJb2w0zi3FoLRIkfGPc7AMjRF0r4/edit?usp=sharing
+</vuln:reference>
+</vuln:references>
+<vuln:summary>
+The JDM Lifestyle (aka com.hondatech) application 6.4 for Android does not verify X.509 certificates from SSL servers, which allows man-in-the-middle attackers to spoof servers and obtain sensitive information via a crafted certificate.
+</vuln:summary>
+</entry>"""
+
+CVE_NO_CVSS = """\
+<entry xmlns:scap-core="http://scap.nist.gov/schema/scap-core/0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:patch="http://scap.nist.gov/schema/patch/0.1" xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4" xmlns:cvss="http://scap.nist.gov/schema/cvss-v2/0.2" xmlns:cpe-lang="http://cpe.mitre.org/language/2.0" xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0" id="CVE-2014-9388">
+<vuln:cve-id>CVE-2014-9388</vuln:cve-id>
+<vuln:published-datetime>2014-12-17T14:59:08.587-05:00</vuln:published-datetime>
+<vuln:last-modified-datetime>2014-12-17T14:59:09.620-05:00</vuln:last-modified-datetime>
+<vuln:references reference_type="UNKNOWN" xml:lang="en">
+<vuln:source>CONFIRM</vuln:source>
+<vuln:reference href="https://www.mantisbt.org/bugs/view.php?id=17878" xml:lang="en">https://www.mantisbt.org/bugs/view.php?id=17878</vuln:reference>
+</vuln:references>
+<vuln:references reference_type="UNKNOWN" xml:lang="en">
+<vuln:source>CONFIRM</vuln:source>
+<vuln:reference href="https://www.mantisbt.org/bugs/changelog_page.php?version_id=191" xml:lang="en">
+https://www.mantisbt.org/bugs/changelog_page.php?version_id=191
+</vuln:reference>
+</vuln:references>
+<vuln:references reference_type="UNKNOWN" xml:lang="en">
+<vuln:source>MLIST</vuln:source>
+<vuln:reference href="http://seclists.org/oss-sec/2014/q4/955" xml:lang="en">[oss-security] 20141207 MantisBT 1.2.18 Released</vuln:reference>
+</vuln:references>
+<vuln:summary>
+bug_report.php in MantisBT before 1.2.18 allows remote attackers to assign arbitrary issues via the handler_id parameter.
+</vuln:summary>
+</entry>"""
+
+class testCVEParsing(utils.TestCase):
+
+ def test_Full(self):
+ self.doc = parse(FULL_CVE)
+ self._validate()
+
+ def test_no_CVSS(self):
+ self.doc = parse(CVE_NO_CVSS)
+ self._validate()
More information about the Farol-commits
mailing list