Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map products to CPE criteria, not only CPEs themselves #468

Open
J08nY opened this issue Jan 27, 2025 · 2 comments
Open

Map products to CPE criteria, not only CPEs themselves #468

J08nY opened this issue Jan 27, 2025 · 2 comments
Labels
cc Related to CC certification cpe Related to CPEs cve Related to CVEs fips Related to FIPS 140 certification

Comments

@J08nY
Copy link
Member

J08nY commented Jan 27, 2025

Currently, when we are doing the CPE mapping, we are only mapping products to CPEs from the CPE dataset. However, when NIST issues CVEs, they sometimes specify the vulnerable configurations using criteria which specify configurations that do not match any actual CPEs in the CPE database, yet they contain basically almost all of the information that CPE contains.

Example

Take CVE-2024-45678 as an example. Here on the NIST page you can see the specified affected configurations. When you click on the "Show Matching CPEs" dropdown you will see that only 2 of the configurations actually have CPEs issued under them. However, for our purposes, the configurations specified themselves have a lot of information we could use to bind the CVE to an affected product: They have the vendor, the product, and some version range.

I do not have any numbers on the actual prevalence of this. We could run some numbers.

Implementation

Few things would need to be done to implement this:

  • Do not filter the CPEMatch dataset:
    if "matches" in m["matchString"]:
    dataset_to_fill["match_strings"][m["matchString"]["matchCriteriaId"]] = {
    "criteria": m["matchString"]["criteria"],
    "matches": m["matchString"]["matches"],
    }
    for version_key in self._VERSION_KEYS:
    if version_key in m["matchString"]:
    dataset_to_fill["match_strings"][m["matchString"]["matchCriteriaId"]][version_key] = m[
    "matchString"
    ][version_key]
  • ✅ Make some sort of "CPECriteria" dataclass that holds the information that we have. Note that the criteria may not have all of the metadata that a CPE must have, so some will be useless.
  • Generalize the CPE classifier to also support this criteria thing.
  • Hold the criteria in the CPE dataset or a separate dataset.

Wdyt, @adamjanovsky?

@J08nY J08nY added cc Related to CC certification cpe Related to CPEs cve Related to CVEs enhancement New feature or request fips Related to FIPS 140 certification and removed enhancement New feature or request labels Jan 27, 2025
@adamjanovsky
Copy link
Collaborator

Yes, we would certainly benefit from that. However, beware that this increases the complexity of the whole matching thing.

Just to note, the CPEMatchCriteria class is already implemented for proper CVE matching (so are classes for criteria configurations):

class CPEMatchCriteria(ComplexSerializableType):
vulnerable: bool
criteria: str
criteria_id: str
version_start: tuple[str, str] | None
version_end: tuple[str, str] | None
__slots__ = ["vulnerable", "criteria", "criteria_id", "version_start", "version_end"]
# We cannot use frozen=True. It does not work with __slots__ prior to Python 3.10 dataclasses
# Hence we manually provide __hash__ and __eq__ despite not guaranteeing immutability
def __hash__(self) -> int:
return hash(self.criteria_id)
def __eq__(self, other: object) -> bool:
return isinstance(other, CPEMatchCriteria) and self.criteria_id == other.criteria_id
def __lt__(self, other: CPEMatchCriteria) -> bool:
return self.criteria_id < other.criteria_id
@classmethod
def from_nist_dict(cls, dct: dict[str, Any]) -> CPEMatchCriteria:
if dct.get("versionStartIncluding"):
version_start = ("including", dct["versionStartIncluding"])
elif dct.get("versionStartExcluding"):
version_start = ("excluding", dct["versionStartExcluding"])
else:
version_start = None
if dct.get("versionEndIncluding"):
version_end = ("including", dct["versionEndIncluding"])
elif dct.get("versionEndExcluding"):
version_end = ("excluding", dct["versionEndExcluding"])
else:
version_end = None
return cls(dct["vulnerable"], dct["criteria"], dct["matchCriteriaId"], version_start, version_end)

@J08nY
Copy link
Member Author

J08nY commented Jan 28, 2025

I made an improvement on the site in this regard:
https://sec-certs.org/vuln/cve/CVE-2024-45678
The CVE page now lists also the CPE match criteria that do not have CPEs matched. It now aligns a bit more with the NIST page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cc Related to CC certification cpe Related to CPEs cve Related to CVEs fips Related to FIPS 140 certification
Projects
None yet
Development

No branches or pull requests

2 participants