Need some help to understand how CPE versioning works in the NVD CVE API response

, ,

Take this request…

curl --location 'https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2015-8470' \
--header 'apiKey: REDACTED'

Which returns…

{
    "resultsPerPage": 1,
    "startIndex": 0,
    "totalResults": 1,
    "format": "NVD_CVE",
    "version": "2.0",
    "timestamp": "2024-03-12T11:19:49.360",
    "vulnerabilities": [
        {
            "cve": {
                "id": "CVE-2015-8470",
                "sourceIdentifier": "cve@mitre.org",
                "published": "2017-12-11T17:29:00.270",
                "lastModified": "2022-01-24T16:46:02.897",
                "vulnStatus": "Analyzed",
                "descriptions": [
                    {
                        "lang": "en",
                        "value": "The console in Puppet Enterprise 3.7.x, 3.8.x, and 2015.2.x does not set the secure flag for the JSESSIONID cookie in an HTTPS session, which makes it easier for remote attackers to capture this cookie by intercepting its transmission within an HTTP session."
                    },
                    {
                        "lang": "es",
                        "value": "La consola en Puppet Enterprise 3.7.x, 3.8.x y 2015.2.x no establece la marca secure para la cookie JSESSIONID en una sesión HTTPS. Esto facilita que atacantes remotos capturen esta cookie interceptando su transmisión en una sesión HTTP."
                    }
                ],
                "metrics": {
                    "cvssMetricV30": [
                        {
                            "source": "nvd@nist.gov",
                            "type": "Primary",
                            "cvssData": {
                                "version": "3.0",
                                "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
                                "attackVector": "NETWORK",
                                "attackComplexity": "LOW",
                                "privilegesRequired": "NONE",
                                "userInteraction": "REQUIRED",
                                "scope": "UNCHANGED",
                                "confidentialityImpact": "HIGH",
                                "integrityImpact": "NONE",
                                "availabilityImpact": "NONE",
                                "baseScore": 6.5,
                                "baseSeverity": "MEDIUM"
                            },
                            "exploitabilityScore": 2.8,
                            "impactScore": 3.6
                        }
                    ],
                    "cvssMetricV2": [
                        {
                            "source": "nvd@nist.gov",
                            "type": "Primary",
                            "cvssData": {
                                "version": "2.0",
                                "vectorString": "AV:N/AC:M/Au:N/C:P/I:N/A:N",
                                "accessVector": "NETWORK",
                                "accessComplexity": "MEDIUM",
                                "authentication": "NONE",
                                "confidentialityImpact": "PARTIAL",
                                "integrityImpact": "NONE",
                                "availabilityImpact": "NONE",
                                "baseScore": 4.3
                            },
                            "baseSeverity": "MEDIUM",
                            "exploitabilityScore": 8.6,
                            "impactScore": 2.9,
                            "acInsufInfo": false,
                            "obtainAllPrivilege": false,
                            "obtainUserPrivilege": false,
                            "obtainOtherPrivilege": false,
                            "userInteractionRequired": true
                        }
                    ]
                },
                "weaknesses": [
                    {
                        "source": "nvd@nist.gov",
                        "type": "Primary",
                        "description": [
                            {
                                "lang": "en",
                                "value": "CWE-200"
                            }
                        ]
                    }
                ],
                "configurations": [
                    {
                        "nodes": [
                            {
                                "operator": "OR",
                                "negate": false,
                                "cpeMatch": [
                                    {
                                        "vulnerable": true,
                                        "criteria": "cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*",
                                        "versionStartIncluding": "3.7.0",
                                        "versionEndIncluding": "3.7.2",
                                        "matchCriteriaId": "E3C0546D-3FF4-461A-B6C4-3C1586DFA79E"
                                    },
                                    {
                                        "vulnerable": true,
                                        "criteria": "cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*",
                                        "versionStartIncluding": "3.8.0",
                                        "versionEndIncluding": "3.8.6",
                                        "matchCriteriaId": "6F08C767-D814-4026-9895-36EF1E4B2F78"
                                    },
                                    {
                                        "vulnerable": true,
                                        "criteria": "cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*",
                                        "versionStartIncluding": "2015.2.0",
                                        "versionEndIncluding": "2015.2.3",
                                        "matchCriteriaId": "4E6676D2-5545-456E-A10D-7AE7B75B6A63"
                                    }
                                ]
                            }
                        ]
                    }
                ],
                "references": [
                    {
                        "url": "https://puppet.com/security/cve/CVE-2015-8470",
                        "source": "cve@mitre.org",
                        "tags": [
                            "Vendor Advisory"
                        ]
                    }
                ]
            }
        }
    ]
}

I understand the nodes define what software is vulnerable.

So I interpret the above as:

cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:* OR cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:* OR cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*

Are vulnerable.

But all the CPEs listed here are the same.

Looking at the response closer, I see versionStartIncluding and versionEndIncluding for each cpeMatch

 "versionStartIncluding": "3.8.0",
 "versionEndIncluding": "3.8.6",

So why doesn’t the response just print the CPEs with the version numbers included?

For context, I ask because I am trying to deduce all versions of a product are vulnerable to a CVE.

The reason all CPE URIs are not printed in the CVE response is because it is not uncommon for their to be hundreds of results.

This is where the matchCriteriaId property comes in;

                                    {
                                        "vulnerable": true,
                                        "criteria": "cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*",
                                        "versionStartIncluding": "3.7.0",
                                        "versionEndIncluding": "3.7.2",
                                        "matchCriteriaId": "E3C0546D-3FF4-461A-B6C4-3C1586DFA79E"
                                    },

The NVD Product APIs (Product APIs) have a cpematch endpoint.

You can pass a matchCriteriaId to this endpoint.

Here’s an example, using the response from the CVE API above…

curl --location 'https://services.nvd.nist.gov/rest/json/cpematch/2.0?matchCriteriaId=E3C0546D-3FF4-461A-B6C4-3C1586DFA79E \
--header 'apiKey: XXX'

Returns…

{
    "resultsPerPage": 1,
    "startIndex": 0,
    "totalResults": 1,
    "format": "NVD_CPEMatchString",
    "version": "2.0",
    "timestamp": "2024-03-12T11:31:58.800",
    "matchStrings": [
        {
            "matchString": {
                "matchCriteriaId": "E3C0546D-3FF4-461A-B6C4-3C1586DFA79E",
                "criteria": "cpe:2.3:a:puppet:puppet_enterprise:*:*:*:*:*:*:*:*",
                "versionStartIncluding": "3.7.0",
                "versionEndIncluding": "3.7.2",
                "lastModified": "2022-01-24T16:44:41.490",
                "cpeLastModified": "2022-01-24T16:46:02.407",
                "created": "2022-01-24T16:44:41.490",
                "status": "Active",
                "matches": [
                    {
                        "cpeName": "cpe:2.3:a:puppet:puppet_enterprise:3.7.0:*:*:*:*:*:*:*",
                        "cpeNameId": "4E472B67-1448-441D-A087-98B2D483FA6E"
                    },
                    {
                        "cpeName": "cpe:2.3:a:puppet:puppet_enterprise:3.7.1:*:*:*:*:*:*:*",
                        "cpeNameId": "8269ACF0-16F6-4DD3-89CC-EAD75F0BE9DB"
                    },
                    {
                        "cpeName": "cpe:2.3:a:puppet:puppet_enterprise:3.7.2:*:*:*:*:*:*:*",
                        "cpeNameId": "AB3321EF-2518-4148-A88F-8A8EAFC490CF"
                    }
                ]
            }
        }
    ]
}

The matches property lists all the CPEs match the version range.

In this case those are:

  • cpe:2.3:a:puppet:puppet_enterprise:3.7.0:*:*:*:*:*:*:*
  • cpe:2.3:a:puppet:puppet_enterprise:3.7.1:*:*:*:*:*:*:*
  • cpe:2.3:a:puppet:puppet_enterprise:3.7.2:*:*:*:*:*:*:*

You can do the same thing for the other two matchCriteriaIds in the NVE CVE response you’ve printed (6F08C767-D814-4026-9895-36EF1E4B2F78 and 4E6676D2-5545-456E-A10D-7AE7B75B6A63) to get the list of CPEs you need.