view farolluz/parsers/cve.py @ 48:3826f2701ff2

CPE: Add the possibility to add ourself integrally to the product tree
author Benoît Allard <benoit.allard@greenbone.net>
date Tue, 30 Dec 2014 12:30:19 +0100
parents 075519975933
children
line wrap: on
line source
# -*- coding: utf-8 -*-
# Description:
# Methods for parsing CVE XML documents
#
# Authors:
# BenoƮt Allard <benoit.allard@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 .cpe import parse as parseCPE
from .xml import parseDate

from .. import __version__
from ..common import CVRFNote, CVRFReference
from ..document import CVRF, CVRFPublisher, CVRFTracking, CVRFTrackingID, CVRFRevision, CVRFGenerator
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)
    content = xml.find('/'.join(['get_info', 'get_info_response', 'info', 'cve', 'raw_data', UN('cve', 'entry')]))
    if content is None:
        return None
    return parse(content)

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)
    generator = CVRFGenerator()
    generator.setEngine('FarolLuz ' + __version__)
    generator.setDate(now)
    tracking.setGenerator(generator)
    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')]))):
        prod = parseCPE(cpe.text).addToDoc(doc)
        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
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)