Beispiel #1
0
def get_image_vulnerabilities(user_id, image_id, force_refresh=False):
    """
    Return the vulnerability listing for the specified image and load from catalog if not found and specifically asked
    to do so.


    Example json output:
    {
       "multi" : {
          "url_column_index" : 7,
          "result" : {
             "rows" : [],
             "rowcount" : 0,
             "colcount" : 8,
             "header" : [
                "CVE_ID",
                "Severity",
                "*Total_Affected",
                "Vulnerable_Package",
                "Fix_Available",
                "Fix_Images",
                "Rebuild_Images",
                "URL"
             ]
          },
          "querycommand" : "/usr/lib/python2.7/site-packages/anchore/anchore-modules/multi-queries/cve-scan.py /ebs_data/anchore/querytmp/queryimages.7026386 /ebs_data/anchore/data /ebs_data/anchore/querytmp/query.59057288 all",
          "queryparams" : "all",
          "warns" : [
             "0005b136f0fb (prom/prometheus:master) cannot perform CVE scan: no CVE data is currently available for the detected base distro type (busybox:unknown_version,busybox:v1.26.2)"
          ]
       }
    }

    :param user_id: user id of image to evaluate
    :param image_id: image id to evaluate
    :param force_refresh: if true, flush and recompute vulnerabilities rather than returning current values
    :return:
    """

    # Has image?
    db = get_session()
    try:
        img = db.query(Image).get((image_id, user_id))
        vulns = []
        if not img:
            abort(404)
        else:
            if force_refresh:
                log.info('Forcing refresh of vulnerabiltiies for {}/{}'.format(user_id, image_id))
                try:
                    current_vulns = img.vulnerabilities()
                    log.info('Removing {} current vulnerabilities for {}/{} to rescan'.format(len(current_vulns), user_id, image_id))
                    for v in current_vulns:
                        db.delete(v)

                    db.flush()
                    vulns = vulnerabilities_for_image(img)
                    log.info('Adding {} vulnerabilities from rescan to {}/{}'.format(len(vulns), user_id, image_id))
                    for v in vulns:
                        db.add(v)
                    db.commit()
                except Exception as e:
                    log.exception('Error refreshing cve matches for image {}/{}'.format(user_id, image_id))
                    db.rollback()
                    abort(Response('Error refreshing vulnerability listing for image.', 500))

                db = get_session()
                db.refresh(img)
            else:
                vulns = img.vulnerabilities()

        # Has vulnerabilities?
        warns = []
        if not vulns:
            vulns = []
            ns = DistroNamespace.for_obj(img)
            if not have_vulnerabilities_for(ns):
                warns = ['No vulnerability data available for image distro: {}'.format(ns.namespace_name)]


        rows = []
        for vuln in vulns:
            # if vuln.vulnerability.fixed_in:
            #     fixes_in = filter(lambda x: x.name == vuln.pkg_name or x.name == vuln.package.normalized_src_pkg,
            #            vuln.vulnerability.fixed_in)
            #     fix_available_in = fixes_in[0].version if fixes_in else 'None'
            # else:
            #     fix_available_in = 'None'

            rows.append([
                vuln.vulnerability_id,
                vuln.vulnerability.severity,
                1,
                vuln.pkg_name + '-' + vuln.package.fullversion,
                str(vuln.fixed_in()),
                vuln.pkg_image_id,
                'None', # Always empty this for now
                vuln.vulnerability.link
                ]
            )

        vuln_listing = {
            'multi': {
                'url_column_index': 7,
                'result': {
                    'header': TABLE_STYLE_HEADER_LIST,
                    'rowcount': len(rows),
                    'colcount': len(TABLE_STYLE_HEADER_LIST),
                    'rows': rows
                },
                'warns': warns
            }
        }

        report = LegacyVulnerabilityReport.from_dict(vuln_listing)
        resp = ImageVulnerabilityListing(user_id=user_id, image_id=image_id, legacy_report=report)
        return resp.to_dict()
    except HTTPException:
        db.rollback()
        raise
    except Exception as e:
        log.exception('Error checking image {}, {} for vulnerabiltiies. Rolling back'.format(user_id, image_id))
        db.rollback()
        abort(500)
    finally:
        db.close()
def test_vuln_report():
    r = ImageVulnerabilityListing()
    r.image_id = 'image'
    r.user_id = 'user'
    r.cpe_report = [CpeVulnerability()]
    v = r.cpe_report[0]
    v.name = 'lib1'
    v.cpe = 'cpe:*:*'
    v.cpe23 = 'cpe2:*:*'
    v.version = '1.1'
    v.feed_name = 'nvdv2'
    v.feed_namespace = 'nvdv2:cpes'
    v.severity = 'High'
    v.vulnerability_id = 'CVE'
    v.vendor_data = [CvssCombined()]
    v.vendor_data[0].id = 'CVE-VENDOR'
    v.vendor_data[0].cvss_v2 = CvssScore()
    v.vendor_data[0].cvss_v2.base_score = 1.0
    v.vendor_data[0].cvss_v2.exploitability_score = 2.0
    v.vendor_data[0].cvss_v2.impact_score = 3.0
    v.vendor_data[0].cvss_v3 = CvssScore()
    v.vendor_data[0].cvss_v3.base_score = 1.0
    v.vendor_data[0].cvss_v3.exploitability_score = 2.0
    v.vendor_data[0].cvss_v3.impact_score = 3.0
    v.nvd_data = [CvssCombined()]
    v.nvd_data[0].id = 'CVE-NVD'
    v.nvd_data[0].cvss_v2 = CvssScore()
    v.nvd_data[0].cvss_v2.base_score = 1.1
    v.nvd_data[0].cvss_v2.exploitability_score = 2.2
    v.nvd_data[0].cvss_v2.impact_score = 3.3
    v.nvd_data[0].cvss_v3 = CvssScore()
    v.nvd_data[0].cvss_v3.base_score = 1.1
    v.nvd_data[0].cvss_v3.exploitability_score = 2.2
    v.nvd_data[0].cvss_v3.impact_score = 3.3
    r.legacy_report = LegacyVulnerabilityReport()
    r.legacy_report.multi = LegacyMultiReport()
    r.legacy_report.multi.result = LegacyTableReport()
    r.legacy_report.multi.result.colcount = 4
    r.legacy_report.multi.result.rowcount = 1
    r.legacy_report.multi.result.header = ['id', 'name', 'version', 'url']
    r.legacy_report.multi.result.rows = [[
        'CVE-NVD', 'lib1', '1.1', 'http://someurl'
    ]]
    r.legacy_report.multi.url_column_index = 3
    r.legacy_report.multi.warns = []

    assert r.to_json() == {
        'user_id':
        'user',
        'image_id':
        'image',
        'cpe_report': [{
            'cpe':
            'cpe:*:*',
            'cpe23':
            'cpe2:*:*',
            'pkg_path':
            None,
            'pkg_type':
            None,
            'feed_name':
            'nvdv2',
            'feed_namespace':
            'nvdv2:cpes',
            'version':
            '1.1',
            'name':
            'lib1',
            'link':
            None,
            'nvd_data': [{
                'id': 'CVE-NVD',
                'cvss_v2': {
                    'base_score': 1.1,
                    'exploitability_score': 2.2,
                    'impact_score': 3.3,
                },
                'cvss_v3': {
                    'base_score': 1.1,
                    'exploitability_score': 2.2,
                    'impact_score': 3.3
                }
            }],
            'vendor_data': [{
                'id': 'CVE-VENDOR',
                'cvss_v2': {
                    'base_score': 1.0,
                    'exploitability_score': 2.0,
                    'impact_score': 3.0,
                },
                'cvss_v3': {
                    'base_score': 1.0,
                    'exploitability_score': 2.0,
                    'impact_score': 3.0
                }
            }],
            'severity':
            'High',
            'vulnerability_id':
            'CVE',
        }],
        'legacy_report': {
            'multi': {
                'result': {
                    'colcount': 4,
                    'header': ['id', 'name', 'version', 'url'],
                    'rowcount': 1,
                    'rows': [['CVE-NVD', 'lib1', '1.1', 'http://someurl']]
                },
                'url_column_index': 3,
                'warns': []
            }
        }
    }
def get_image_vulnerabilities(user_id,
                              image_id,
                              force_refresh=False,
                              vendor_only=True):
    """
    Return the vulnerability listing for the specified image and load from catalog if not found and specifically asked
    to do so.


    Example json output:
    {
       "multi" : {
          "url_column_index" : 7,
          "result" : {
             "rows" : [],
             "rowcount" : 0,
             "colcount" : 8,
             "header" : [
                "CVE_ID",
                "Severity",
                "*Total_Affected",
                "Vulnerable_Package",
                "Fix_Available",
                "Fix_Images",
                "Rebuild_Images",
                "URL"
             ]
          },
          "querycommand" : "/usr/lib/python2.7/site-packages/anchore/anchore-modules/multi-queries/cve-scan.py /ebs_data/anchore/querytmp/queryimages.7026386 /ebs_data/anchore/data /ebs_data/anchore/querytmp/query.59057288 all",
          "queryparams" : "all",
          "warns" : [
             "0005b136f0fb (prom/prometheus:master) cannot perform CVE scan: no CVE data is currently available for the detected base distro type (busybox:unknown_version,busybox:v1.26.2)"
          ]
       }
    }

    :param user_id: user id of image to evaluate
    :param image_id: image id to evaluate
    :param force_refresh: if true, flush and recompute vulnerabilities rather than returning current values
    :param vendor_only: if true, filter out the vulnerabilities that vendors will explicitly not address
    :return:
    """

    # Has image?
    db = get_session()
    try:
        img = db.query(Image).get((image_id, user_id))
        vulns = []
        if not img:
            abort(404)
        else:
            if force_refresh:
                log.info('Forcing refresh of vulnerabiltiies for {}/{}'.format(
                    user_id, image_id))
                try:
                    vulns = rescan_image(img, db_session=db)
                    db.commit()
                except Exception as e:
                    log.exception(
                        'Error refreshing cve matches for image {}/{}'.format(
                            user_id, image_id))
                    db.rollback()
                    abort(
                        Response(
                            'Error refreshing vulnerability listing for image.',
                            500))

                db = get_session()
                db.refresh(img)

            vulns = img.vulnerabilities()

        # Has vulnerabilities?
        warns = []
        if not vulns:
            vulns = []
            ns = DistroNamespace.for_obj(img)
            if not have_vulnerabilities_for(ns):
                warns = [
                    'No vulnerability data available for image distro: {}'.
                    format(ns.namespace_name)
                ]

        rows = []
        for vuln in vulns:
            # if vuln.vulnerability.fixed_in:
            #     fixes_in = filter(lambda x: x.name == vuln.pkg_name or x.name == vuln.package.normalized_src_pkg,
            #            vuln.vulnerability.fixed_in)
            #     fix_available_in = fixes_in[0].version if fixes_in else 'None'
            # else:
            #     fix_available_in = 'None'

            # Skip the vulnerability if the vendor_only flag is set to True and the issue won't be addressed by the vendor
            if vendor_only and vuln.fix_has_no_advisory():
                continue

            rows.append([
                vuln.vulnerability_id,
                vuln.vulnerability.severity,
                1,
                vuln.pkg_name + '-' + vuln.package.fullversion,
                str(vuln.fixed_in()),
                vuln.pkg_image_id,
                'None',  # Always empty this for now
                vuln.vulnerability.link,
                vuln.pkg_type,
                'vulnerabilities',
                vuln.vulnerability.namespace_name,
                vuln.pkg_name,
                vuln.package.fullversion,
            ])

        vuln_listing = {
            'multi': {
                'url_column_index': 7,
                'result': {
                    'header': TABLE_STYLE_HEADER_LIST,
                    'rowcount': len(rows),
                    'colcount': len(TABLE_STYLE_HEADER_LIST),
                    'rows': rows
                },
                'warns': warns
            }
        }

        cpe_vuln_listing = []
        try:
            all_cpe_matches = db.query(
                ImageCpe,
                CpeVulnerability).filter(ImageCpe.image_id == image_id).filter(
                    ImageCpe.name == CpeVulnerability.name).filter(
                        ImageCpe.version == CpeVulnerability.version)
            if not all_cpe_matches:
                all_cpe_matches = []

            cpe_hashes = {}
            for image_cpe, vulnerability_cpe in all_cpe_matches:
                cpe_vuln_el = {
                    'vulnerability_id': vulnerability_cpe.vulnerability_id,
                    'severity': vulnerability_cpe.severity,
                    'link': vulnerability_cpe.link,
                    'pkg_type': image_cpe.pkg_type,
                    'pkg_path': image_cpe.pkg_path,
                    'name': image_cpe.name,
                    'version': image_cpe.version,
                    'cpe': image_cpe.get_cpestring(),
                    'feed_name': vulnerability_cpe.feed_name,
                    'feed_namespace': vulnerability_cpe.namespace_name,
                }
                cpe_hash = hashlib.sha256(
                    utils.ensure_bytes(json.dumps(cpe_vuln_el))).hexdigest()
                if not cpe_hashes.get(cpe_hash, False):
                    cpe_vuln_listing.append(cpe_vuln_el)
                    cpe_hashes[cpe_hash] = True
        except Exception as err:
            log.warn("could not fetch CPE matches - exception: " + str(err))

        report = LegacyVulnerabilityReport.from_dict(vuln_listing)
        resp = ImageVulnerabilityListing(user_id=user_id,
                                         image_id=image_id,
                                         legacy_report=report,
                                         cpe_report=cpe_vuln_listing)
        return resp.to_dict()
    except HTTPException:
        db.rollback()
        raise
    except Exception as e:
        log.exception(
            'Error checking image {}, {} for vulnerabiltiies. Rolling back'.
            format(user_id, image_id))
        db.rollback()
        abort(500)
    finally:
        db.close()
Beispiel #4
0
def test_vuln_report():
    r = ImageVulnerabilityListing()
    r.image_id = "image"
    r.user_id = "user"
    r.cpe_report = [CpeVulnerability()]
    v = r.cpe_report[0]
    v.name = "lib1"
    v.cpe = "cpe:*:*"
    v.cpe23 = "cpe2:*:*"
    v.version = "1.1"
    v.feed_name = "nvdv2"
    v.feed_namespace = "nvdv2:cpes"
    v.severity = "High"
    v.vulnerability_id = "CVE"
    v.vendor_data = [CvssCombined()]
    v.vendor_data[0].id = "CVE-VENDOR"
    v.vendor_data[0].cvss_v2 = CvssScore()
    v.vendor_data[0].cvss_v2.base_score = 1.0
    v.vendor_data[0].cvss_v2.exploitability_score = 2.0
    v.vendor_data[0].cvss_v2.impact_score = 3.0
    v.vendor_data[0].cvss_v3 = CvssScore()
    v.vendor_data[0].cvss_v3.base_score = 1.0
    v.vendor_data[0].cvss_v3.exploitability_score = 2.0
    v.vendor_data[0].cvss_v3.impact_score = 3.0
    v.nvd_data = [CvssCombined()]
    v.nvd_data[0].id = "CVE-NVD"
    v.nvd_data[0].cvss_v2 = CvssScore()
    v.nvd_data[0].cvss_v2.base_score = 1.1
    v.nvd_data[0].cvss_v2.exploitability_score = 2.2
    v.nvd_data[0].cvss_v2.impact_score = 3.3
    v.nvd_data[0].cvss_v3 = CvssScore()
    v.nvd_data[0].cvss_v3.base_score = 1.1
    v.nvd_data[0].cvss_v3.exploitability_score = 2.2
    v.nvd_data[0].cvss_v3.impact_score = 3.3
    r.legacy_report = LegacyVulnerabilityReport()
    r.legacy_report.multi = LegacyMultiReport()
    r.legacy_report.multi.result = LegacyTableReport()
    r.legacy_report.multi.result.colcount = 4
    r.legacy_report.multi.result.rowcount = 1
    r.legacy_report.multi.result.header = ["id", "name", "version", "url"]
    r.legacy_report.multi.result.rows = [[
        "CVE-NVD", "lib1", "1.1", "http://someurl"
    ]]
    r.legacy_report.multi.url_column_index = 3
    r.legacy_report.multi.warns = []

    assert r.to_json() == {
        "user_id":
        "user",
        "image_id":
        "image",
        "cpe_report": [{
            "cpe":
            "cpe:*:*",
            "cpe23":
            "cpe2:*:*",
            "pkg_path":
            None,
            "pkg_type":
            None,
            "feed_name":
            "nvdv2",
            "feed_namespace":
            "nvdv2:cpes",
            "version":
            "1.1",
            "name":
            "lib1",
            "link":
            None,
            "nvd_data": [{
                "id": "CVE-NVD",
                "cvss_v2": {
                    "base_score": 1.1,
                    "exploitability_score": 2.2,
                    "impact_score": 3.3,
                },
                "cvss_v3": {
                    "base_score": 1.1,
                    "exploitability_score": 2.2,
                    "impact_score": 3.3,
                },
            }],
            "vendor_data": [{
                "id": "CVE-VENDOR",
                "cvss_v2": {
                    "base_score": 1.0,
                    "exploitability_score": 2.0,
                    "impact_score": 3.0,
                },
                "cvss_v3": {
                    "base_score": 1.0,
                    "exploitability_score": 2.0,
                    "impact_score": 3.0,
                },
            }],
            "severity":
            "High",
            "vulnerability_id":
            "CVE",
        }],
        "legacy_report": {
            "multi": {
                "result": {
                    "colcount": 4,
                    "header": ["id", "name", "version", "url"],
                    "rowcount": 1,
                    "rows": [["CVE-NVD", "lib1", "1.1", "http://someurl"]],
                },
                "url_column_index": 3,
                "warns": [],
            }
        },
    }