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()
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": [], } }, }