anchore / grype

A vulnerability scanner for container images and filesystems
Apache License 2.0
8.48k stars 549 forks source link

False positives caused by mishandling CPE configuration logical operators #1349

Open luhring opened 1 year ago

luhring commented 1 year ago

What happened:

Grype doesn't appear to be procesing CPE configurations correctly in the case where logical operators are used in NVD's CPE data. Specifically, when a CPE configuration has "AND"-ed nodes, Grype isn't respecting the "AND" requirement.

For example, we're seeing Grype match a private tomcat package to CVE-2016-5425, which looks like a false positive.

Here are the CPE match details from Grype's JSON output:

"matchDetails": [
  {
    "type": "cpe-match",
    "matcher": "java-matcher",
    "searchedBy": {
      "namespace": "nvd:cpe",
      "cpes": [
        "cpe:2.3:a:apache:tomcat:8.5.87:*:*:*:*:*:*:*"
      ]
    },
    "found": {
      "vulnerabilityID": "CVE-2016-5425",
      "versionConstraint": "none (unknown)",
      "cpes": [
        "cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"
      ]
    }
  }
],

Grype cites NVD as its data source for this match. But here's what the NVD data actually says:

"configurations": [
  {
    "operator": "AND",
    "nodes": [
      {
        // ...
            "criteria": "cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*",
        // ...
      },
      {
        "operator": "OR",
        "negate": false,
        "cpeMatch": [
          {
            "vulnerable": false,
            "criteria": "cpe:2.3:a:oracle:instantis_enterprisetrack:17.1:*:*:*:*:*:*:*",
            "matchCriteriaId": "82EA4BA7-C38B-4AF3-8914-9E3D089EBDD4"
          },
          {
            "vulnerable": false,
            "criteria": "cpe:2.3:a:oracle:instantis_enterprisetrack:17.2:*:*:*:*:*:*:*",
            "matchCriteriaId": "B9C9BC66-FA5F-4774-9BDA-7AB88E2839C4"

(You can see the full data record at https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2016-5425.)

In other words, NVD isn't saying this vulnerability applies to any package with a CPE that matches cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:* — it's saying to match to this CPE only if one of these other CPEs applies to the scan target as well. In this case, all of these other CPEs refer to Red Hat or Oracle software, neither of which apply to the Wolfi/Chainguard distros.

What you expected to happen:

Grype shouldn't be reporting these kinds of matches, since they are provably false postives.

Environment:

Application:          grype
Version:              0.62.3
Syft Version:         v0.83.0
BuildDate:            2023-06-05T21:34:29Z
GitCommit:            3865f4cc1dfcdcefbb7009400df153f24b18c772
GitDescription:       v0.62.3
Platform:             darwin/arm64
GoVersion:            go1.19.9
Compiler:             gc
Supported DB Schema:  5
luhring commented 1 year ago

@westonsteimel curious if you have any thoughts here 😃

westonsteimel commented 1 year ago

@luhring, we just recently added the platform-cpe package qualifer to help deselect these in specific simple cases though this one seems to fall outside that case. I think it's probably additional os that need handling in the conditions, but also changes to parsing necessary in the build of grype-db https://github.com/anchore/grype-db/blob/main/pkg/process/v5/transformers/nvd/unique_pkg.go#L66

I left it to a very narrow well-understood set of cases for the initial implementation

westonsteimel commented 1 year ago

So for instance with CVE-2022-26488, we should now properly exclude this on anything that isn't windows. Here is the extract from the sqlite vulnerability table:

                     pk = 207153
                     id = CVE-2022-26488
           package_name = python
              namespace = nvd:cpe
     package_qualifiers = [{"kind":"platform-cpe","cpe":"cpe:2.3:o:microsoft:windows:-:*:*:*:*:*:*:*"}]
     version_constraint = <= 3.7.12 || >= 3.8.0, <= 3.8.12 || >= 3.9.0, <= 3.9.10 || >= 3.10.0, <= 3.10.2 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0
         version_format = unknown
                   cpes = ["cpe:2.3:a:python:python:*:*:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha1:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha2:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha3:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha4:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha5:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha6:*:*:*:*:*:*"]
related_vulnerabilities =
      fixed_in_versions =
              fix_state = unknown
             advisories =
westonsteimel commented 1 year ago

So for CVE-2016-5425 we'd need to split it into multiple vulnerability rows each with a different platform-cpe qualifier from the list on the entry, so that should be a change somewhere in https://github.com/anchore/grype-db/blob/main/pkg/process/v5/transformers/nvd/unique_pkg.go#L66

westonsteimel commented 1 year ago

Hopefully that helps some. Here are the PR's for the original feature:

luhring commented 1 year ago

That's cool! I hadn't seen the qualifier stuff.

And what you're saying makes sense, this needs to be accounted for in the Grype DB build.

willmurphyscode commented 4 months ago

We took at step in the direction @westonsteimel mentioned above with https://github.com/anchore/grype-db/pull/203, but I don't think it would fix this particular issue.

@luhring can you able to post a Dockerfile or SBOM or something that exhibits this particular false positive?

luhring commented 4 months ago

tomcat.syft.json

This was generated with wolfictl which uses Syft. Piping this into grype with GRYPE_MATCH_JAVA_USING_CPES=true set seems to still exhibit this kind of false positive.

$ grype version
Application:         grype
Version:             0.77.0
BuildDate:           2024-04-18T19:14:37Z
GitCommit:           b7ffbeee53105478e699290aeac238a0ead28962
GitDescription:      v0.77.0
Platform:            darwin/arm64
GoVersion:           go1.21.9
Compiler:            gc
Syft Version:        v1.2.0
Supported DB Schema: 5
wagoodman commented 1 month ago

A snippet from the DB for someone trying to grok this:

sqlite3 -header -column /Users/wagoodman/Library/Caches/grype/db/5/vulnerability.db 'select package_qualifiers,cpes from vulnerability where id == "CVE-2016-5425" and namespace LIKE "%cpe%";'
package_qualifiers                                                                                 cpes
-------------------------------------------------------------------------------------------------  -------------------------------------------
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.1:*:*:*:*:*:*:*"}]    ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.2:*:*:*:*:*:*:*"}]    ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.3:*:*:*:*:*:*:*"}]    ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:oracle:linux:7:-:*:*:*:*:*:*"}]                           ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_desktop:7.0:*:*:*:*:*:*:*"}]      ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server:7.0:*:*:*:*:*:*:*"}]       ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.2:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.3:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.4:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.6:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.7:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.2:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.3:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.4:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.5:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.6:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.7:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.2:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.3:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.6:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.7:*:*:*:*:*:*:*"}]   ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_workstation:7.0:*:*:*:*:*:*:*"}]  ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]

Agreed there are a couple things wrong: