diff --git a/vulnerabilities/importers/__init__.py b/vulnerabilities/importers/__init__.py index 82ee4525a..11d393c8f 100644 --- a/vulnerabilities/importers/__init__.py +++ b/vulnerabilities/importers/__init__.py @@ -44,6 +44,7 @@ from vulnerabilities.pipelines.v2_importers import apache_httpd_importer as apache_httpd_v2 from vulnerabilities.pipelines.v2_importers import archlinux_importer as archlinux_importer_v2 from vulnerabilities.pipelines.v2_importers import curl_importer as curl_importer_v2 +from vulnerabilities.pipelines.v2_importers import cvelistv5_importer as cvelistv5_importer_v2 from vulnerabilities.pipelines.v2_importers import ( elixir_security_importer as elixir_security_importer_v2, ) @@ -69,6 +70,7 @@ elixir_security_importer_v2.ElixirSecurityImporterPipeline, npm_importer_v2.NpmImporterPipeline, vulnrichment_importer_v2.VulnrichImporterPipeline, + cvelistv5_importer_v2.CVEListV5ImporterPipeline, apache_httpd_v2.ApacheHTTPDImporterPipeline, pypa_importer_v2.PyPaImporterPipeline, gitlab_importer_v2.GitLabImporterPipeline, diff --git a/vulnerabilities/importers/cve_schema.py b/vulnerabilities/importers/cve_schema.py new file mode 100644 index 000000000..6c17d304d --- /dev/null +++ b/vulnerabilities/importers/cve_schema.py @@ -0,0 +1,162 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import json +import re + +import dateparser + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import ReferenceV2 +from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.models import VulnerabilityReference +from vulnerabilities.severity_systems import SCORING_SYSTEMS +from vulnerabilities.utils import get_cwe_id +from vulnerabilities.utils import get_reference_id +from vulnerabilities.utils import ssvc_calculator + + +def parse_cve_v5_advisory(raw_data, advisory_url): + cve_metadata = raw_data.get("cveMetadata", {}) + cve_id = cve_metadata.get("cveId") + + date_published = cve_metadata.get("datePublished") + if date_published: + date_published = dateparser.parse( + date_published, + settings={ + "TIMEZONE": "UTC", + "RETURN_AS_TIMEZONE_AWARE": True, + "TO_TIMEZONE": "UTC", + }, + ) + + # Extract containers + containers = raw_data.get("containers", {}) + cna_data = containers.get("cna", {}) + adp_data = containers.get("adp", {}) + + # Extract descriptions + summary = "" + description_list = cna_data.get("descriptions", []) + for description_dict in description_list: + if not description_dict.get("lang") in ["en", "en-US"]: + continue + summary = description_dict.get("value") + + # Extract metrics + severities = [] + metrics = cna_data.get("metrics", []) + [ + adp_metrics for data in adp_data for adp_metrics in data.get("metrics", []) + ] + + cve_scoring_system = { + "cvssV4_0": SCORING_SYSTEMS["cvssv4"], + "cvssV3_1": SCORING_SYSTEMS["cvssv3.1"], + "cvssV3_0": SCORING_SYSTEMS["cvssv3"], + "cvssV2_0": SCORING_SYSTEMS["cvssv2"], + "other": { + "ssvc": SCORING_SYSTEMS["ssvc"], + }, # ignore kev + } + + for metric in metrics: + for metric_type, metric_value in metric.items(): + if metric_type not in cve_scoring_system: + continue + + if metric_type == "other": + other_types = metric_value.get("type") + if other_types == "ssvc": + content = metric_value.get("content", {}) + vector_string, decision = ssvc_calculator(content) + scoring_system = cve_scoring_system[metric_type][other_types] + severity = VulnerabilitySeverity( + system=scoring_system, value=decision, scoring_elements=vector_string + ) + severities.append(severity) + # ignore kev + else: + vector_string = metric_value.get("vectorString") + base_score = metric_value.get("baseScore") + scoring_system = cve_scoring_system[metric_type] + severity = VulnerabilitySeverity( + system=scoring_system, value=base_score, scoring_elements=vector_string + ) + severities.append(severity) + + # Extract references cpes and ignore affected products + cpes = set() + for affected_product in cna_data.get("affected", []): + if type(affected_product) != dict: + continue + cpes.update(affected_product.get("cpes") or []) + + references = [] + for ref in cna_data.get("references", []): + # https://github.com/CVEProject/cve-schema/blob/main/schema/tags/reference-tags.json + # We removed all unwanted reference types and set the default reference type to 'OTHER'. + ref_type = VulnerabilityReference.OTHER + vul_ref_types = { + "exploit": VulnerabilityReference.EXPLOIT, + "issue-tracking": VulnerabilityReference.BUG, + "mailing-list": VulnerabilityReference.MAILING_LIST, + "third-party-advisory": VulnerabilityReference.ADVISORY, + "vendor-advisory": VulnerabilityReference.ADVISORY, + "vdb-entry": VulnerabilityReference.ADVISORY, + } + + for tag_type in ref.get("tags", []): + if tag_type in vul_ref_types: + ref_type = vul_ref_types.get(tag_type) + + url = ref.get("url") + reference = ReferenceV2( + reference_id=get_reference_id(url), + url=url, + reference_type=ref_type, + ) + + references.append(reference) + + cpes_ref = [ + ReferenceV2( + reference_id=cpe, + reference_type=VulnerabilityReference.OTHER, + url=f"https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query={cpe}", + ) + for cpe in sorted(list(cpes)) + ] + references.extend(cpes_ref) + + weaknesses = set() + for problem_type in cna_data.get("problemTypes", []): + descriptions = problem_type.get("descriptions", []) + for description in descriptions: + cwe_id = description.get("cweId") + if cwe_id: + weaknesses.add(get_cwe_id(cwe_id)) + + description_text = description.get("description") + if description_text: + pattern = r"CWE-(\d+)" + match = re.search(pattern, description_text) + if match: + weaknesses.add(int(match.group(1))) + + return AdvisoryData( + advisory_id=cve_id, + aliases=[], + summary=summary, + references_v2=references, + date_published=date_published, + weaknesses=sorted(weaknesses), + url=advisory_url, + severities=severities, + original_advisory_text=json.dumps(raw_data, indent=2, ensure_ascii=False), + ) diff --git a/vulnerabilities/importers/vulnrichment.py b/vulnerabilities/importers/vulnrichment.py index 9eb4d3bcb..708b04213 100644 --- a/vulnerabilities/importers/vulnrichment.py +++ b/vulnerabilities/importers/vulnrichment.py @@ -15,6 +15,7 @@ from vulnerabilities.utils import get_advisory_url from vulnerabilities.utils import get_cwe_id from vulnerabilities.utils import get_reference_id +from vulnerabilities.utils import ssvc_calculator logger = logging.getLogger(__name__) @@ -184,117 +185,3 @@ def parse_cve_advisory(raw_data, advisory_url): weaknesses=sorted(weaknesses), url=advisory_url, ) - - -def ssvc_calculator(ssvc_data): - """ - Return the ssvc vector and the decision value - """ - options = ssvc_data.get("options", []) - timestamp = ssvc_data.get("timestamp") - - # Extract the options into a dictionary - options_dict = {k: v.lower() for option in options for k, v in option.items()} - - # We copied the table value from this link. - # https://www.cisa.gov/sites/default/files/publications/cisa-ssvc-guide%20508c.pdf - - # Determining Mission and Well-Being Impact Value - mission_well_being_table = { - # (Mission Prevalence, Public Well-being Impact) : "Mission & Well-being" - ("minimal", "minimal"): "low", - ("minimal", "material"): "medium", - ("minimal", "irreversible"): "high", - ("support", "minimal"): "medium", - ("support", "material"): "medium", - ("support", "irreversible"): "high", - ("essential", "minimal"): "high", - ("essential", "material"): "high", - ("essential", "irreversible"): "high", - } - - if "Mission Prevalence" not in options_dict: - options_dict["Mission Prevalence"] = "minimal" - - if "Public Well-being Impact" not in options_dict: - options_dict["Public Well-being Impact"] = "material" - - options_dict["Mission & Well-being"] = mission_well_being_table[ - (options_dict["Mission Prevalence"], options_dict["Public Well-being Impact"]) - ] - - decision_key = ( - options_dict.get("Exploitation"), - options_dict.get("Automatable"), - options_dict.get("Technical Impact"), - options_dict.get("Mission & Well-being"), - ) - - decision_points = { - "Exploitation": {"E": {"none": "N", "poc": "P", "active": "A"}}, - "Automatable": {"A": {"no": "N", "yes": "Y"}}, - "Technical Impact": {"T": {"partial": "P", "total": "T"}}, - "Public Well-being Impact": {"B": {"minimal": "M", "material": "A", "irreversible": "I"}}, - "Mission Prevalence": {"P": {"minimal": "M", "support": "S", "essential": "E"}}, - "Mission & Well-being": {"M": {"low": "L", "medium": "M", "high": "H"}}, - } - - # Create the SSVC vector - ssvc_vector = "SSVCv2/" - for key, value_map in options_dict.items(): - options_key = decision_points.get(key) - for lhs, rhs_map in options_key.items(): - ssvc_vector += f"{lhs}:{rhs_map.get(value_map)}/" - - # "Decision": {"D": {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"}}, - decision_values = {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"} - - decision_lookup = { - ("none", "no", "partial", "low"): "Track", - ("none", "no", "partial", "medium"): "Track", - ("none", "no", "partial", "high"): "Track", - ("none", "no", "total", "low"): "Track", - ("none", "no", "total", "medium"): "Track", - ("none", "no", "total", "high"): "Track*", - ("none", "yes", "partial", "low"): "Track", - ("none", "yes", "partial", "medium"): "Track", - ("none", "yes", "partial", "high"): "Attend", - ("none", "yes", "total", "low"): "Track", - ("none", "yes", "total", "medium"): "Track", - ("none", "yes", "total", "high"): "Attend", - ("poc", "no", "partial", "low"): "Track", - ("poc", "no", "partial", "medium"): "Track", - ("poc", "no", "partial", "high"): "Track*", - ("poc", "no", "total", "low"): "Track", - ("poc", "no", "total", "medium"): "Track*", - ("poc", "no", "total", "high"): "Attend", - ("poc", "yes", "partial", "low"): "Track", - ("poc", "yes", "partial", "medium"): "Track", - ("poc", "yes", "partial", "high"): "Attend", - ("poc", "yes", "total", "low"): "Track", - ("poc", "yes", "total", "medium"): "Track*", - ("poc", "yes", "total", "high"): "Attend", - ("active", "no", "partial", "low"): "Track", - ("active", "no", "partial", "medium"): "Track", - ("active", "no", "partial", "high"): "Attend", - ("active", "no", "total", "low"): "Track", - ("active", "no", "total", "medium"): "Attend", - ("active", "no", "total", "high"): "Act", - ("active", "yes", "partial", "low"): "Attend", - ("active", "yes", "partial", "medium"): "Attend", - ("active", "yes", "partial", "high"): "Act", - ("active", "yes", "total", "low"): "Attend", - ("active", "yes", "total", "medium"): "Act", - ("active", "yes", "total", "high"): "Act", - } - - decision = decision_lookup.get(decision_key, "") - - if decision: - ssvc_vector += f"D:{decision_values.get(decision)}/" - - if timestamp: - timestamp_formatted = dateparser.parse(timestamp).strftime("%Y-%m-%dT%H:%M:%SZ") - - ssvc_vector += f"{timestamp_formatted}/" - return ssvc_vector, decision diff --git a/vulnerabilities/pipelines/v2_importers/cvelistv5_importer.py b/vulnerabilities/pipelines/v2_importers/cvelistv5_importer.py new file mode 100644 index 000000000..2d5123f9b --- /dev/null +++ b/vulnerabilities/pipelines/v2_importers/cvelistv5_importer.py @@ -0,0 +1,71 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import json +import logging +from pathlib import Path +from typing import Iterable + +from fetchcode.vcs import fetch_via_vcs + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.cve_schema import parse_cve_v5_advisory +from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 +from vulnerabilities.utils import get_advisory_url + +logger = logging.getLogger(__name__) + + +class CVEListV5ImporterPipeline(VulnerableCodeBaseImporterPipelineV2): + pipeline_id = "cvelistv5_importer_v2" + # license PR: https://github.com/CVEProject/cvelistV5/pull/65 + spdx_license_expression = "CC0-1.0" + license_url = "https://github.com/CVEProject/cvelistV5/blob/main/LICENSE" + repo_url = "git+https://github.com/CVEProject/cvelistV5" + + @classmethod + def steps(cls): + return ( + cls.clone, + cls.collect_and_store_advisories, + cls.clean_downloads, + ) + + def clone(self): + self.log(f"Cloning `{self.repo_url}`") + self.vcs_response = fetch_via_vcs(self.repo_url) + + def advisories_count(self): + vuln_directory = Path(self.vcs_response.dest_dir) / "cves" + return sum(1 for _ in vuln_directory.glob("*.json")) + + def collect_advisories(self) -> Iterable[AdvisoryData]: + base_directory = Path(self.vcs_response.dest_dir) + vulns_directory = base_directory / "cves" + + for file in vulns_directory.rglob("*.json"): + if not file.name.startswith("CVE-"): + continue + + advisory_url = get_advisory_url( + file=file, + base_path=base_directory, + url="https://github.com/CVEProject/cvelistV5/blob/main/", + ) + + with open(file) as f: + raw_data = json.load(f) + yield parse_cve_v5_advisory(raw_data, advisory_url) + + def clean_downloads(self): + if self.vcs_response: + self.log(f"Removing cloned repository") + self.vcs_response.delete() + + def on_failure(self): + self.clean_downloads() diff --git a/vulnerabilities/pipelines/v2_importers/vulnrichment_importer.py b/vulnerabilities/pipelines/v2_importers/vulnrichment_importer.py index a596d8d65..43a0dd4ba 100644 --- a/vulnerabilities/pipelines/v2_importers/vulnrichment_importer.py +++ b/vulnerabilities/pipelines/v2_importers/vulnrichment_importer.py @@ -1,21 +1,14 @@ import json import logging -import re from pathlib import Path from typing import Iterable -import dateparser from fetchcode.vcs import fetch_via_vcs from vulnerabilities.importer import AdvisoryData -from vulnerabilities.importer import ReferenceV2 -from vulnerabilities.importer import VulnerabilitySeverity -from vulnerabilities.models import VulnerabilityReference +from vulnerabilities.importers.cve_schema import parse_cve_v5_advisory from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 -from vulnerabilities.severity_systems import SCORING_SYSTEMS from vulnerabilities.utils import get_advisory_url -from vulnerabilities.utils import get_cwe_id -from vulnerabilities.utils import get_reference_id logger = logging.getLogger(__name__) @@ -60,148 +53,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]: base_path=base_path, url="https://github.com/cisagov/vulnrichment/blob/develop/", ) - yield self.parse_cve_advisory(raw_data, advisory_url) - - def parse_cve_advisory(self, raw_data, advisory_url): - cve_metadata = raw_data.get("cveMetadata", {}) - cve_id = cve_metadata.get("cveId") - state = cve_metadata.get("state") - - date_published = cve_metadata.get("datePublished") - if date_published: - date_published = dateparser.parse( - date_published, - settings={ - "TIMEZONE": "UTC", - "RETURN_AS_TIMEZONE_AWARE": True, - "TO_TIMEZONE": "UTC", - }, - ) - - # Extract containers - containers = raw_data.get("containers", {}) - cna_data = containers.get("cna", {}) - adp_data = containers.get("adp", {}) - - # Extract descriptions - summary = "" - description_list = cna_data.get("descriptions", []) - for description_dict in description_list: - if not description_dict.get("lang") in ["en", "en-US"]: - continue - summary = description_dict.get("value") - - # Extract metrics - severities = [] - metrics = cna_data.get("metrics", []) + [ - adp_metrics for data in adp_data for adp_metrics in data.get("metrics", []) - ] - - vulnrichment_scoring_system = { - "cvssV4_0": SCORING_SYSTEMS["cvssv4"], - "cvssV3_1": SCORING_SYSTEMS["cvssv3.1"], - "cvssV3_0": SCORING_SYSTEMS["cvssv3"], - "cvssV2_0": SCORING_SYSTEMS["cvssv2"], - "other": { - "ssvc": SCORING_SYSTEMS["ssvc"], - }, # ignore kev - } - - for metric in metrics: - for metric_type, metric_value in metric.items(): - if metric_type not in vulnrichment_scoring_system: - continue - - if metric_type == "other": - other_types = metric_value.get("type") - if other_types == "ssvc": - content = metric_value.get("content", {}) - vector_string, decision = ssvc_calculator(content) - scoring_system = vulnrichment_scoring_system[metric_type][other_types] - severity = VulnerabilitySeverity( - system=scoring_system, value=decision, scoring_elements=vector_string - ) - severities.append(severity) - # ignore kev - else: - vector_string = metric_value.get("vectorString") - base_score = metric_value.get("baseScore") - scoring_system = vulnrichment_scoring_system[metric_type] - severity = VulnerabilitySeverity( - system=scoring_system, value=base_score, scoring_elements=vector_string - ) - severities.append(severity) - - # Extract references cpes and ignore affected products - cpes = set() - for affected_product in cna_data.get("affected", []): - if type(affected_product) != dict: - continue - cpes.update(affected_product.get("cpes") or []) - - references = [] - for ref in cna_data.get("references", []): - # https://github.com/CVEProject/cve-schema/blob/main/schema/tags/reference-tags.json - # We removed all unwanted reference types and set the default reference type to 'OTHER'. - ref_type = VulnerabilityReference.OTHER - vul_ref_types = { - "exploit": VulnerabilityReference.EXPLOIT, - "issue-tracking": VulnerabilityReference.BUG, - "mailing-list": VulnerabilityReference.MAILING_LIST, - "third-party-advisory": VulnerabilityReference.ADVISORY, - "vendor-advisory": VulnerabilityReference.ADVISORY, - "vdb-entry": VulnerabilityReference.ADVISORY, - } - - for tag_type in ref.get("tags", []): - if tag_type in vul_ref_types: - ref_type = vul_ref_types.get(tag_type) - - url = ref.get("url") - reference = ReferenceV2( - reference_id=get_reference_id(url), - url=url, - reference_type=ref_type, - ) - - references.append(reference) - - cpes_ref = [ - ReferenceV2( - reference_id=cpe, - reference_type=VulnerabilityReference.OTHER, - url=f"https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query={cpe}", - ) - for cpe in sorted(list(cpes)) - ] - references.extend(cpes_ref) - - weaknesses = set() - for problem_type in cna_data.get("problemTypes", []): - descriptions = problem_type.get("descriptions", []) - for description in descriptions: - cwe_id = description.get("cweId") - if cwe_id: - weaknesses.add(get_cwe_id(cwe_id)) - - description_text = description.get("description") - if description_text: - pattern = r"CWE-(\d+)" - match = re.search(pattern, description_text) - if match: - weaknesses.add(int(match.group(1))) - - return AdvisoryData( - advisory_id=cve_id, - aliases=[], - summary=summary, - references_v2=references, - date_published=date_published, - weaknesses=sorted(weaknesses), - url=advisory_url, - severities=severities, - original_advisory_text=json.dumps(raw_data, indent=2, ensure_ascii=False), - ) + yield parse_cve_v5_advisory(raw_data, advisory_url) def clean_downloads(self): if self.vcs_response: @@ -210,117 +62,3 @@ def clean_downloads(self): def on_failure(self): self.clean_downloads() - - -def ssvc_calculator(ssvc_data): - """ - Return the ssvc vector and the decision value - """ - options = ssvc_data.get("options", []) - timestamp = ssvc_data.get("timestamp") - - # Extract the options into a dictionary - options_dict = {k: v.lower() for option in options for k, v in option.items()} - - # We copied the table value from this link. - # https://www.cisa.gov/sites/default/files/publications/cisa-ssvc-guide%20508c.pdf - - # Determining Mission and Well-Being Impact Value - mission_well_being_table = { - # (Mission Prevalence, Public Well-being Impact) : "Mission & Well-being" - ("minimal", "minimal"): "low", - ("minimal", "material"): "medium", - ("minimal", "irreversible"): "high", - ("support", "minimal"): "medium", - ("support", "material"): "medium", - ("support", "irreversible"): "high", - ("essential", "minimal"): "high", - ("essential", "material"): "high", - ("essential", "irreversible"): "high", - } - - if "Mission Prevalence" not in options_dict: - options_dict["Mission Prevalence"] = "minimal" - - if "Public Well-being Impact" not in options_dict: - options_dict["Public Well-being Impact"] = "material" - - options_dict["Mission & Well-being"] = mission_well_being_table[ - (options_dict["Mission Prevalence"], options_dict["Public Well-being Impact"]) - ] - - decision_key = ( - options_dict.get("Exploitation"), - options_dict.get("Automatable"), - options_dict.get("Technical Impact"), - options_dict.get("Mission & Well-being"), - ) - - decision_points = { - "Exploitation": {"E": {"none": "N", "poc": "P", "active": "A"}}, - "Automatable": {"A": {"no": "N", "yes": "Y"}}, - "Technical Impact": {"T": {"partial": "P", "total": "T"}}, - "Public Well-being Impact": {"B": {"minimal": "M", "material": "A", "irreversible": "I"}}, - "Mission Prevalence": {"P": {"minimal": "M", "support": "S", "essential": "E"}}, - "Mission & Well-being": {"M": {"low": "L", "medium": "M", "high": "H"}}, - } - - # Create the SSVC vector - ssvc_vector = "SSVCv2/" - for key, value_map in options_dict.items(): - options_key = decision_points.get(key) - for lhs, rhs_map in options_key.items(): - ssvc_vector += f"{lhs}:{rhs_map.get(value_map)}/" - - # "Decision": {"D": {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"}}, - decision_values = {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"} - - decision_lookup = { - ("none", "no", "partial", "low"): "Track", - ("none", "no", "partial", "medium"): "Track", - ("none", "no", "partial", "high"): "Track", - ("none", "no", "total", "low"): "Track", - ("none", "no", "total", "medium"): "Track", - ("none", "no", "total", "high"): "Track*", - ("none", "yes", "partial", "low"): "Track", - ("none", "yes", "partial", "medium"): "Track", - ("none", "yes", "partial", "high"): "Attend", - ("none", "yes", "total", "low"): "Track", - ("none", "yes", "total", "medium"): "Track", - ("none", "yes", "total", "high"): "Attend", - ("poc", "no", "partial", "low"): "Track", - ("poc", "no", "partial", "medium"): "Track", - ("poc", "no", "partial", "high"): "Track*", - ("poc", "no", "total", "low"): "Track", - ("poc", "no", "total", "medium"): "Track*", - ("poc", "no", "total", "high"): "Attend", - ("poc", "yes", "partial", "low"): "Track", - ("poc", "yes", "partial", "medium"): "Track", - ("poc", "yes", "partial", "high"): "Attend", - ("poc", "yes", "total", "low"): "Track", - ("poc", "yes", "total", "medium"): "Track*", - ("poc", "yes", "total", "high"): "Attend", - ("active", "no", "partial", "low"): "Track", - ("active", "no", "partial", "medium"): "Track", - ("active", "no", "partial", "high"): "Attend", - ("active", "no", "total", "low"): "Track", - ("active", "no", "total", "medium"): "Attend", - ("active", "no", "total", "high"): "Act", - ("active", "yes", "partial", "low"): "Attend", - ("active", "yes", "partial", "medium"): "Attend", - ("active", "yes", "partial", "high"): "Act", - ("active", "yes", "total", "low"): "Attend", - ("active", "yes", "total", "medium"): "Act", - ("active", "yes", "total", "high"): "Act", - } - - decision = decision_lookup.get(decision_key, "") - - if decision: - ssvc_vector += f"D:{decision_values.get(decision)}/" - - if timestamp: - timestamp_formatted = dateparser.parse(timestamp).strftime("%Y-%m-%dT%H:%M:%SZ") - - ssvc_vector += f"{timestamp_formatted}/" - return ssvc_vector, decision diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_cvelistv5_importer_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_cvelistv5_importer_v2.py new file mode 100644 index 000000000..e5a3ff438 --- /dev/null +++ b/vulnerabilities/tests/pipelines/v2_importers/test_cvelistv5_importer_v2.py @@ -0,0 +1,205 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +import json +from unittest.mock import MagicMock +from unittest.mock import patch + +import pytest + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.importers.cve_schema import parse_cve_v5_advisory +from vulnerabilities.pipelines.v2_importers.cvelistv5_importer import CVEListV5ImporterPipeline + + +@pytest.fixture +def mock_vcs_response(): + # Mock the vcs_response from fetch_via_vcs + mock_response = MagicMock() + mock_response.dest_dir = "/mock/repo" + mock_response.delete = MagicMock() + return mock_response + + +@pytest.fixture +def mock_fetch_via_vcs(mock_vcs_response): + with patch("vulnerabilities.pipelines.v2_importers.cvelistv5_importer.fetch_via_vcs") as mock: + mock.return_value = mock_vcs_response + yield mock + + +@pytest.fixture +def mock_pathlib(tmp_path): + # Create a mock filesystem with a 'cves/2021/1xxx' directory and JSON files + vulns_dir = tmp_path / "cves/2021/1xxx" + vulns_dir.mkdir(parents=True, exist_ok=True) + + advisory_file = vulns_dir / "CVE-2021-1234.json" + advisory_file.write_text( + json.dumps( + { + "cveMetadata": { + "cveId": "CVE-2021-1234", + "state": "PUBLIC", + "datePublished": "2021-01-01", + }, + "containers": { + "cna": { + "descriptions": [{"lang": "en", "value": "Sample PyPI vulnerability"}], + "metrics": [ + { + "cvssV4_0": { + "baseScore": 7.5, + "vectorString": "AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + } + } + ], + "affected": [{"cpes": ["cpe:/a:example:package"]}], + "references": [{"url": "https://example.com", "tags": ["exploit"]}], + } + }, + } + ) + ) + return vulns_dir + + +def test_clone(mock_fetch_via_vcs, mock_vcs_response): + # Test the `clone` method to ensure the repository is cloned correctly + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + + mock_fetch_via_vcs.assert_called_once_with(pipeline.repo_url) + assert pipeline.vcs_response == mock_vcs_response + + +def test_advisories_count(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs): + mock_vcs_response.dest_dir = str(mock_pathlib.parent) + + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + count = pipeline.advisories_count() + + assert count == 0 + + +def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs, tmp_path): + # Mock `vcs_response.dest_dir` to point to the temporary directory + mock_vcs_response.dest_dir = str(tmp_path) + + # Mock `parse_cve_advisory` to return an AdvisoryData object + with patch( + "vulnerabilities.pipelines.v2_importers.cvelistv5_importer.CVEListV5ImporterPipeline" + ) as mock_parse: + mock_parse.return_value = AdvisoryData( + advisory_id="CVE-2021-1234", + summary="Sample PyPI vulnerability", + references_v2=[{"url": "https://example.com"}], + affected_packages=[], + weaknesses=[], + url="https://github.com/CVEProject/cvelistV5/blob/cves/2021/1xxx/CVE-2021-1234.json", + severities=[ + VulnerabilitySeverity( + system="cvssv4", + value=7.5, + scoring_elements="AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + ) + ], + ) + + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + advisories = list(pipeline.collect_advisories()) + + # Ensure that advisories are parsed correctly + assert len(advisories) == 1 + advisory = advisories[0] + assert advisory.advisory_id == "CVE-2021-1234" + assert advisory.summary == "Sample PyPI vulnerability" + assert ( + advisory.url + == "https://github.com/CVEProject/cvelistV5/blob/main/cves/2021/1xxx/CVE-2021-1234.json" + ) + + +def test_clean_downloads(mock_vcs_response, mock_fetch_via_vcs): + # Test the `clean_downloads` method to ensure the repository is deleted + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + pipeline.vcs_response = mock_vcs_response + + pipeline.clean_downloads() + + mock_vcs_response.delete.assert_called_once() + + +def test_on_failure(mock_vcs_response, mock_fetch_via_vcs): + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + pipeline.vcs_response = mock_vcs_response + + with patch.object(pipeline, "clean_downloads") as mock_clean: + pipeline.on_failure() + + mock_clean.assert_called_once() + + +def test_parse_cve_advisory(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs): + mock_vcs_response.dest_dir = str(mock_pathlib.parent) + + raw_data = { + "cveMetadata": {"cveId": "CVE-2021-1234", "state": "PUBLIC", "datePublished": "2021-01-01"}, + "containers": { + "cna": { + "descriptions": [{"lang": "en", "value": "Sample PyPI vulnerability"}], + "metrics": [ + { + "cvssV4_0": { + "baseScore": 7.5, + "vectorString": "AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + } + } + ], + "affected": [{"cpes": ["cpe:/a:example:package"]}], + "references": [{"url": "https://example.com", "tags": ["exploit"]}], + } + }, + } + advisory_url = "https://github.com/CVEProject/cvelistV5/blob/cves/2021/1xxx/CVE-2021-1234.json" + + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + advisory = parse_cve_v5_advisory(raw_data, advisory_url) + + assert advisory.advisory_id == "CVE-2021-1234" + assert advisory.summary == "Sample PyPI vulnerability" + assert advisory.url == advisory_url + assert len(advisory.severities) == 1 + assert advisory.severities[0].value == 7.5 + + +def test_collect_advisories_with_invalid_json( + mock_pathlib, mock_vcs_response, mock_fetch_via_vcs, tmp_path +): + invalid_file = mock_pathlib / "CVE-invalid.json" + invalid_file.write_text("invalid_json") + + mock_vcs_response.dest_dir = str(tmp_path) + + with patch( + "vulnerabilities.pipelines.v2_importers.cvelistv5_importer.CVEListV5ImporterPipeline" + ) as mock_parse: + mock_parse.side_effect = json.JSONDecodeError("Invalid JSON", "", 0) + + pipeline = CVEListV5ImporterPipeline() + pipeline.clone() + + with pytest.raises(json.JSONDecodeError): + list(pipeline.collect_advisories()) diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_vulnrichment_importer_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_vulnrichment_importer_v2.py index f926058c2..d948049e9 100644 --- a/vulnerabilities/tests/pipelines/v2_importers/test_vulnrichment_importer_v2.py +++ b/vulnerabilities/tests/pipelines/v2_importers/test_vulnrichment_importer_v2.py @@ -8,7 +8,6 @@ # import json -from pathlib import Path from unittest.mock import MagicMock from unittest.mock import patch @@ -16,6 +15,7 @@ from vulnerabilities.importer import AdvisoryData from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.importers.cve_schema import parse_cve_v5_advisory from vulnerabilities.pipelines.v2_importers.vulnrichment_importer import VulnrichImporterPipeline @@ -98,7 +98,7 @@ def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) # Mock `parse_cve_advisory` to return an AdvisoryData object with patch( - "vulnerabilities.pipelines.v2_importers.vulnrichment_importer.VulnrichImporterPipeline.parse_cve_advisory" + "vulnerabilities.pipelines.v2_importers.vulnrichment_importer.VulnrichImporterPipeline" ) as mock_parse: mock_parse.return_value = AdvisoryData( advisory_id="CVE-2021-1234", @@ -106,7 +106,7 @@ def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) references_v2=[{"url": "https://example.com"}], affected_packages=[], weaknesses=[], - url="https://example.com", + url="https://github.com/cisagov/vulnrichment/blob/develop/vulns/CVE-2021-1234.json", severities=[ VulnerabilitySeverity( system="cvssv4", @@ -125,7 +125,10 @@ def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) advisory = advisories[0] assert advisory.advisory_id == "CVE-2021-1234" assert advisory.summary == "Sample PyPI vulnerability" - assert advisory.url == "https://example.com" + assert ( + advisory.url + == "https://github.com/cisagov/vulnrichment/blob/develop/vulns/CVE-2021-1234.json" + ) def test_clean_downloads(mock_vcs_response, mock_fetch_via_vcs): @@ -151,9 +154,6 @@ def test_on_failure(mock_vcs_response, mock_fetch_via_vcs): def test_parse_cve_advisory(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs): - from vulnerabilities.pipelines.v2_importers.vulnrichment_importer import ( - VulnrichImporterPipeline, - ) mock_vcs_response.dest_dir = str(mock_pathlib.parent) @@ -179,7 +179,7 @@ def test_parse_cve_advisory(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) pipeline = VulnrichImporterPipeline() pipeline.clone() - advisory = pipeline.parse_cve_advisory(raw_data, advisory_url) + advisory = parse_cve_v5_advisory(raw_data, advisory_url) assert advisory.advisory_id == "CVE-2021-1234" assert advisory.summary == "Sample PyPI vulnerability" @@ -189,13 +189,13 @@ def test_parse_cve_advisory(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) def test_collect_advisories_with_invalid_json(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs): - invalid_file = mock_pathlib / "invalid_file.json" + invalid_file = mock_pathlib / "CVE-invalid.json" invalid_file.write_text("invalid_json") mock_vcs_response.dest_dir = str(mock_pathlib.parent) with patch( - "vulnerabilities.pipelines.v2_importers.vulnrichment_importer.VulnrichImporterPipeline.parse_cve_advisory" + "vulnerabilities.pipelines.v2_importers.vulnrichment_importer.VulnrichImporterPipeline" ) as mock_parse: mock_parse.side_effect = json.JSONDecodeError("Invalid JSON", "", 0) diff --git a/vulnerabilities/tests/test_cve_schema.py b/vulnerabilities/tests/test_cve_schema.py new file mode 100644 index 000000000..6f901cc60 --- /dev/null +++ b/vulnerabilities/tests/test_cve_schema.py @@ -0,0 +1,68 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +import json +import os +from unittest import TestCase + +from vulnerabilities.importers.cve_schema import parse_cve_v5_advisory +from vulnerabilities.tests import util_tests + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +TEST_DATA = os.path.join(BASE_DIR, "test_data/cve_schema") + + +class TestCVESchemaV5(TestCase): + def test_to_advisories1(self): + with open(os.path.join(TEST_DATA, "vulnrichment-data1.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "vulnrichment-data1-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisorie2(self): + with open(os.path.join(TEST_DATA, "vulnrichment-data2.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "vulnrichment-data2-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisorie3(self): + with open(os.path.join(TEST_DATA, "vulnrichment-data3.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "vulnrichment-data3-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories4(self): + with open(os.path.join(TEST_DATA, "cvelistv5-data1.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "cvelistv5-data1-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisorie5(self): + with open(os.path.join(TEST_DATA, "cvelistv5-data2.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "cvelistv5-data2-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisorie6(self): + with open(os.path.join(TEST_DATA, "cvelistv5-data3.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "cvelistv5-data3-expected.json") + imported_data = parse_cve_v5_advisory(mock_response, advisory_url="https://test.com") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data-invalid.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data-invalid.json new file mode 100644 index 000000000..3deb1542c --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data-invalid.json @@ -0,0 +1,28 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.0", + "cveMetadata": { + "state": "REJECTED", + "cveId": "CVE-2017-0999", + "assignerOrgId": "6dda929c-bb53-4a77-a76d-48e79601a1ce", + "assignerShortName": "intel", + "dateUpdated": "2023-02-22T00:00:00", + "dateRejected": "2023-02-22T00:00:00", + "dateReserved": "2016-11-30T00:00:00" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "6dda929c-bb53-4a77-a76d-48e79601a1ce", + "shortName": "intel", + "dateUpdated": "2023-02-22T00:00:00" + }, + "rejectedReasons": [ + { + "lang": "en", + "value": "DO NOT USE THIS CANDIDATE NUMBER. ConsultIDs: none. Reason: This candidate was in a CNA pool that was not assigned to any issues during 2017. Notes: none." + } + ] + } + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1-expected.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1-expected.json new file mode 100644 index 000000000..5b2e87ce2 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1-expected.json @@ -0,0 +1,61 @@ +{ + "advisory_id": "CVE-2025-0950", + "aliases": [], + "summary": "A vulnerability was found in itsourcecode Tailoring Management System 1.0 and classified as critical. This issue affects some unknown processing of the file staffview.php. The manipulation of the argument staffid leads to sql injection. The attack may be initiated remotely. The exploit has been disclosed to the public and may be used.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "?id.294305", + "reference_type": "advisory", + "url": "https://vuldb.com/?id.294305" + }, + { + "reference_id": "?ctiid.294305", + "reference_type": "other", + "url": "https://vuldb.com/?ctiid.294305" + }, + { + "reference_id": "7", + "reference_type": "bug", + "url": "https://github.com/magic2353112890/cve/issues/7" + }, + { + "reference_id": "itsourcecode.com", + "reference_type": "other", + "url": "https://itsourcecode.com/" + } + ], + "severities": [ + { + "system": "cvssv4", + "value": 5.3, + "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N" + }, + { + "system": "cvssv3.1", + "value": 6.3, + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L" + }, + { + "system": "cvssv3", + "value": 6.3, + "scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L" + }, + { + "system": "cvssv2", + "value": 6.5, + "scoring_elements": "AV:N/AC:L/Au:S/C:P/I:P/A:P" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2025-02-03T17:14:26Z/" + } + ], + "date_published": "2025-02-01T20:00:12.431000+00:00", + "weaknesses": [ + 74, + 89 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1.json new file mode 100644 index 000000000..345dfca6a --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data1.json @@ -0,0 +1,190 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.1", + "cveMetadata": { + "cveId": "CVE-2025-0950", + "assignerOrgId": "1af790b2-7ee1-4545-860a-a788eba489b5", + "state": "PUBLISHED", + "assignerShortName": "VulDB", + "dateReserved": "2025-01-31T19:27:39.391Z", + "datePublished": "2025-02-01T20:00:12.431Z", + "dateUpdated": "2025-02-03T17:14:33.848Z" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "1af790b2-7ee1-4545-860a-a788eba489b5", + "shortName": "VulDB", + "dateUpdated": "2025-02-01T20:00:12.431Z" + }, + "title": "itsourcecode Tailoring Management System staffview.php sql injection", + "problemTypes": [ + { + "descriptions": [ + { + "type": "CWE", + "cweId": "CWE-89", + "lang": "en", + "description": "SQL Injection" + } + ] + }, + { + "descriptions": [ + { + "type": "CWE", + "cweId": "CWE-74", + "lang": "en", + "description": "Injection" + } + ] + } + ], + "affected": [ + { + "vendor": "itsourcecode", + "product": "Tailoring Management System", + "versions": [ + { + "version": "1.0", + "status": "affected" + } + ] + } + ], + "descriptions": [ + { + "lang": "en", + "value": "A vulnerability was found in itsourcecode Tailoring Management System 1.0 and classified as critical. This issue affects some unknown processing of the file staffview.php. The manipulation of the argument staffid leads to sql injection. The attack may be initiated remotely. The exploit has been disclosed to the public and may be used." + }, + { + "lang": "de", + "value": "Eine kritische Schwachstelle wurde in itsourcecode Tailoring Management System 1.0 gefunden. Davon betroffen ist unbekannter Code der Datei staffview.php. Dank der Manipulation des Arguments staffid mit unbekannten Daten kann eine sql injection-Schwachstelle ausgenutzt werden. Der Angriff kann über das Netzwerk erfolgen. Der Exploit steht zur öffentlichen Verfügung." + } + ], + "metrics": [ + { + "cvssV4_0": { + "version": "4.0", + "baseScore": 5.3, + "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N", + "baseSeverity": "MEDIUM" + } + }, + { + "cvssV3_1": { + "version": "3.1", + "baseScore": 6.3, + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", + "baseSeverity": "MEDIUM" + } + }, + { + "cvssV3_0": { + "version": "3.0", + "baseScore": 6.3, + "vectorString": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", + "baseSeverity": "MEDIUM" + } + }, + { + "cvssV2_0": { + "version": "2.0", + "baseScore": 6.5, + "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P" + } + } + ], + "timeline": [ + { + "time": "2025-01-31T00:00:00.000Z", + "lang": "en", + "value": "Advisory disclosed" + }, + { + "time": "2025-01-31T01:00:00.000Z", + "lang": "en", + "value": "VulDB entry created" + }, + { + "time": "2025-01-31T20:32:54.000Z", + "lang": "en", + "value": "VulDB entry last update" + } + ], + "references": [ + { + "url": "https://vuldb.com/?id.294305", + "name": "VDB-294305 | itsourcecode Tailoring Management System staffview.php sql injection", + "tags": [ + "vdb-entry", + "technical-description" + ] + }, + { + "url": "https://vuldb.com/?ctiid.294305", + "name": "VDB-294305 | CTI Indicators (IOB, IOC, TTP, IOA)", + "tags": [ + "signature", + "permissions-required" + ] + }, + { + "url": "https://github.com/magic2353112890/cve/issues/7", + "tags": [ + "exploit", + "issue-tracking" + ] + }, + { + "url": "https://itsourcecode.com/", + "tags": [ + "product" + ] + } + ] + }, + "adp": [ + { + "references": [ + { + "url": "https://github.com/magic2353112890/cve/issues/7", + "tags": [ + "exploit" + ] + } + ], + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "timestamp": "2025-02-03T17:14:26.389861Z", + "id": "CVE-2025-0950", + "options": [ + { + "Exploitation": "poc" + }, + { + "Automatable": "no" + }, + { + "Technical Impact": "partial" + } + ], + "role": "CISA Coordinator", + "version": "2.0.3" + } + } + } + ], + "title": "CISA ADP Vulnrichment", + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2025-02-03T17:14:33.848Z" + } + } + ] + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2-expected.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2-expected.json new file mode 100644 index 000000000..a9b5ea4fc --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2-expected.json @@ -0,0 +1,35 @@ +{ + "advisory_id": "CVE-2024-0906", + "aliases": [], + "summary": "The f(x) Private Site plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.2.1 via the API. This makes it possible for unauthenticated attackers to obtain page and post contents of a site protected with this plugin.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "79c3abc6-68fa-4c51-88fa-03ab7d26cc4c?source=cve", + "reference_type": "other", + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/79c3abc6-68fa-4c51-88fa-03ab7d26cc4c?source=cve" + }, + { + "reference_id": "fx-private-site", + "reference_type": "other", + "url": "https://wordpress.org/plugins/fx-private-site/" + } + ], + "severities": [ + { + "system": "cvssv3.1", + "value": 5.3, + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:N/A:N/T:P/P:M/B:A/M:M/D:T/2024-03-12T18:42:41Z/" + } + ], + "date_published": "2024-03-12T08:34:17.481000+00:00", + "weaknesses": [ + 200 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2.json new file mode 100644 index 000000000..501431538 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data2.json @@ -0,0 +1,141 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.1", + "cveMetadata": { + "cveId": "CVE-2024-0906", + "assignerOrgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "state": "PUBLISHED", + "assignerShortName": "Wordfence", + "dateReserved": "2024-01-25T20:05:55.951Z", + "datePublished": "2024-03-12T08:34:17.481Z", + "dateUpdated": "2024-08-01T18:18:19.079Z" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "shortName": "Wordfence", + "dateUpdated": "2024-03-12T08:34:17.481Z" + }, + "affected": [ + { + "vendor": "turtlepod", + "product": "f(x) Private Site", + "versions": [ + { + "version": "*", + "status": "affected", + "lessThanOrEqual": "1.2.1", + "versionType": "semver" + } + ], + "defaultStatus": "unaffected" + } + ], + "descriptions": [ + { + "lang": "en", + "value": "The f(x) Private Site plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.2.1 via the API. This makes it possible for unauthenticated attackers to obtain page and post contents of a site protected with this plugin." + } + ], + "references": [ + { + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/79c3abc6-68fa-4c51-88fa-03ab7d26cc4c?source=cve" + }, + { + "url": "https://wordpress.org/plugins/fx-private-site/" + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "lang": "en", + "description": "CWE-200 Information Exposure" + } + ] + } + ], + "metrics": [ + { + "cvssV3_1": { + "version": "3.1", + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "baseScore": 5.3, + "baseSeverity": "MEDIUM" + } + } + ], + "credits": [ + { + "lang": "en", + "type": "finder", + "value": "Francesco Carlucci" + } + ], + "timeline": [ + { + "time": "2024-03-11T00:00:00.000+00:00", + "lang": "en", + "value": "Disclosed" + } + ] + }, + "adp": [ + { + "title": "CISA ADP Vulnrichment", + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2024-0906", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "none" + }, + { + "Automatable": "no" + }, + { + "Technical Impact": "partial" + } + ], + "version": "2.0.3", + "timestamp": "2024-03-12T18:42:41.121767Z" + } + } + } + ], + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2024-06-04T17:59:00.318Z" + } + }, + { + "providerMetadata": { + "orgId": "af854a3a-2127-422b-91ae-364da2661108", + "shortName": "CVE", + "dateUpdated": "2024-08-01T18:18:19.079Z" + }, + "title": "CVE Program Container", + "references": [ + { + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/79c3abc6-68fa-4c51-88fa-03ab7d26cc4c?source=cve", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://wordpress.org/plugins/fx-private-site/", + "tags": [ + "x_transferred" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3-expected.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3-expected.json new file mode 100644 index 000000000..c64ddd84c --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3-expected.json @@ -0,0 +1,35 @@ +{ + "advisory_id": "CVE-2023-0710", + "aliases": [], + "summary": "The Metform Elementor Contact Form Builder for WordPress is vulnerable to Cross-Site Scripting by using the 'fname' attribute of the 'mf_thankyou' shortcode to echo unescaped form submissions in versions up to, and including, 3.3.0. This allows authenticated attackers, with contributor-level permissions or above, to inject arbitrary web scripts in pages that will execute when the victim visits a a page containing the shortcode when the submission id is present in the query string. Note that getting the JavaScript to execute requires user interaction as the victim must visit a crafted link with the form entry id, but the script itself is stored in the site database. Additionally this requires successful payment, increasing the complexity.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "89a98053-33c7-4e75-87a1-0f483a990641?source=cve", + "reference_type": "other", + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/89a98053-33c7-4e75-87a1-0f483a990641?source=cve" + }, + { + "reference_id": "shortcode.php?rev=2845078", + "reference_type": "other", + "url": "https://plugins.trac.wordpress.org/browser/metform/trunk/base/shortcode.php?rev=2845078" + } + ], + "severities": [ + { + "system": "cvssv3.1", + "value": 4.9, + "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:N/A:N/T:P/P:M/B:A/M:M/D:T/2024-11-23T13:13:32Z/" + } + ], + "date_published": "2023-06-09T05:33:23.543000+00:00", + "weaknesses": [ + 79 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3.json b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3.json new file mode 100644 index 000000000..7df7e4191 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/cvelistv5-data3.json @@ -0,0 +1,146 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.1", + "cveMetadata": { + "cveId": "CVE-2023-0710", + "assignerOrgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "state": "PUBLISHED", + "assignerShortName": "Wordfence", + "dateReserved": "2023-02-07T15:19:09.384Z", + "datePublished": "2023-06-09T05:33:23.543Z", + "dateUpdated": "2024-11-23T13:18:21.937Z" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "shortName": "Wordfence", + "dateUpdated": "2023-06-09T05:33:23.543Z" + }, + "affected": [ + { + "vendor": "xpeedstudio", + "product": "Metform Elementor Contact Form Builder – Flexible and Design-Friendly Contact Form builder plugin for WordPress", + "versions": [ + { + "version": "*", + "status": "affected", + "lessThanOrEqual": "3.3.0", + "versionType": "semver" + } + ], + "defaultStatus": "unaffected" + } + ], + "descriptions": [ + { + "lang": "en", + "value": "The Metform Elementor Contact Form Builder for WordPress is vulnerable to Cross-Site Scripting by using the 'fname' attribute of the 'mf_thankyou' shortcode to echo unescaped form submissions in versions up to, and including, 3.3.0. This allows authenticated attackers, with contributor-level permissions or above, to inject arbitrary web scripts in pages that will execute when the victim visits a a page containing the shortcode when the submission id is present in the query string. Note that getting the JavaScript to execute requires user interaction as the victim must visit a crafted link with the form entry id, but the script itself is stored in the site database. Additionally this requires successful payment, increasing the complexity." + } + ], + "references": [ + { + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/89a98053-33c7-4e75-87a1-0f483a990641?source=cve" + }, + { + "url": "https://plugins.trac.wordpress.org/browser/metform/trunk/base/shortcode.php?rev=2845078" + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "lang": "en", + "description": "CWE-79 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')" + } + ] + } + ], + "metrics": [ + { + "cvssV3_1": { + "version": "3.1", + "vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N", + "baseScore": 4.9, + "baseSeverity": "MEDIUM" + } + } + ], + "credits": [ + { + "lang": "en", + "type": "finder", + "value": "Ramuel Gall" + } + ], + "timeline": [ + { + "time": "2023-02-07T00:00:00.000+00:00", + "lang": "en", + "value": "Discovered" + }, + { + "time": "2023-06-08T00:00:00.000+00:00", + "lang": "en", + "value": "Disclosed" + } + ] + }, + "adp": [ + { + "providerMetadata": { + "orgId": "af854a3a-2127-422b-91ae-364da2661108", + "shortName": "CVE", + "dateUpdated": "2024-08-02T05:17:50.396Z" + }, + "title": "CVE Program Container", + "references": [ + { + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/89a98053-33c7-4e75-87a1-0f483a990641?source=cve", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://plugins.trac.wordpress.org/browser/metform/trunk/base/shortcode.php?rev=2845078", + "tags": [ + "x_transferred" + ] + } + ] + }, + { + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2023-0710", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "none" + }, + { + "Automatable": "no" + }, + { + "Technical Impact": "partial" + } + ], + "version": "2.0.3", + "timestamp": "2024-11-23T13:13:32.842155Z" + } + } + } + ], + "title": "CISA ADP Vulnrichment", + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2024-11-23T13:18:21.937Z" + } + } + ] + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1-expected.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1-expected.json new file mode 100644 index 000000000..80ba17799 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1-expected.json @@ -0,0 +1,35 @@ +{ + "advisory_id": "CVE-2024-3018", + "aliases": [], + "summary": "The Essential Addons for Elementor plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 5.9.13 via deserialization of untrusted input from the 'error_resetpassword' attribute of the \"Login | Register Form\" widget (disabled by default). This makes it possible for authenticated attackers, with author-level access and above, to inject a PHP Object. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "342049e5-834e-4867-8174-01ca7bb0caa2?source=cve", + "reference_type": "other", + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/342049e5-834e-4867-8174-01ca7bb0caa2?source=cve" + }, + { + "reference_id": "essential-addons-for-elementor-lite", + "reference_type": "other", + "url": "https://plugins.trac.wordpress.org/changeset/3060417/essential-addons-for-elementor-lite" + } + ], + "severities": [ + { + "system": "cvssv3.1", + "value": 8.8, + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:N/A:N/T:P/P:M/B:A/M:M/D:T/2024-04-01T17:33:59Z/" + } + ], + "date_published": "2024-03-30T11:17:25.675000+00:00", + "weaknesses": [ + 502 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1.json new file mode 100644 index 000000000..6d38df1fc --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data1.json @@ -0,0 +1,124 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.1", + "cveMetadata": { + "cveId": "CVE-2024-3018", + "assignerOrgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "state": "PUBLISHED", + "assignerShortName": "Wordfence", + "dateReserved": "2024-03-27T17:18:09.609Z", + "datePublished": "2024-03-30T11:17:25.675Z", + "dateUpdated": "2024-06-04T17:32:12.178Z" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "b15e7b5b-3da4-40ae-a43c-f7aa60e62599", + "shortName": "Wordfence", + "dateUpdated": "2024-03-30T11:17:25.675Z" + }, + "affected": [ + { + "vendor": "wpdevteam", + "product": "Essential Addons for Elementor \u2013 Best Elementor Templates, Widgets, Kits & WooCommerce Builders", + "versions": [ + { + "version": "*", + "status": "affected", + "lessThanOrEqual": "5.9.13", + "versionType": "semver" + } + ], + "defaultStatus": "unaffected" + } + ], + "descriptions": [ + { + "lang": "en", + "value": "The Essential Addons for Elementor plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 5.9.13 via deserialization of untrusted input from the 'error_resetpassword' attribute of the \"Login | Register Form\" widget (disabled by default). This makes it possible for authenticated attackers, with author-level access and above, to inject a PHP Object. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code." + } + ], + "references": [ + { + "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/342049e5-834e-4867-8174-01ca7bb0caa2?source=cve" + }, + { + "url": "https://plugins.trac.wordpress.org/changeset/3060417/essential-addons-for-elementor-lite" + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "lang": "en", + "description": "CWE-502 Deserialization of Untrusted Data" + } + ] + } + ], + "metrics": [ + { + "cvssV3_1": { + "version": "3.1", + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "baseScore": 8.8, + "baseSeverity": "HIGH" + } + } + ], + "credits": [ + { + "lang": "en", + "type": "finder", + "value": "Ng\u00f4 Thi\u00ean An" + } + ], + "timeline": [ + { + "time": "2024-03-27T00:00:00.000+00:00", + "lang": "en", + "value": "Vendor Notified" + }, + { + "time": "2024-03-29T00:00:00.000+00:00", + "lang": "en", + "value": "Disclosed" + } + ] + }, + "adp": [ + { + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2024-3018", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "none" + }, + { + "Automatable": "no" + }, + { + "Technical Impact": "partial" + } + ], + "version": "2.0.3", + "timestamp": "2024-04-01T17:33:59.355004Z" + } + } + } + ], + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2024-05-23T19:01:20.623Z" + }, + "title": "CISA ADP Vulnrichment" + } + ] + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2-expected.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2-expected.json new file mode 100644 index 000000000..2e776dd77 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2-expected.json @@ -0,0 +1,198 @@ +{ + "advisory_id": "CVE-2022-26915", + "aliases": [], + "summary": "Windows Secure Channel Denial of Service Vulnerability", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "CVE-2022-26915", + "reference_type": "advisory", + "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26915" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:arm64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:arm64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1809:10.0.18363.2212:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1809:10.0.18363.2212:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:arm64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:arm64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:arm64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:arm64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19043.1645:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H2:10.0.19043.1645:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:arm64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:arm64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:arm64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:arm64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_rt_8.1:6.3.9600.20337:*:*:*:*:*:*:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_rt_8.1:6.3.9600.20337:*:*:*:*:*:*:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2008_R2:6.1.7601.25924:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2008_R2:6.1.7601.25924:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x86:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x86:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2012:6.2.9200.23679:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2012:6.2.9200.23679:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2012_R2:6.3.9600.20337:*:*:*:*:*:x64:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2012_R2:6.3.9600.20337:*:*:*:*:*:x64:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2016:10.0.14393.5066:*:*:*:*:*:*:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2016:10.0.14393.5066:*:*:*:*:*:*:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2019:10.0.17763.2803:*:*:*:*:*:*:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2019:10.0.17763.2803:*:*:*:*:*:*:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_2022:10.0.20348.643:*:*:*:*:*:*:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_2022:10.0.20348.643:*:*:*:*:*:*:*" + }, + { + "reference_id": "cpe:2.3:o:microsoft:windows_server_20H2:10.0.19042.1645:*:*:*:*:*:*:*", + "reference_type": "other", + "url": "https://nvd.nist.gov/vuln/search/results?adv_search=true&isCpeNameSearch=true&query=cpe:2.3:o:microsoft:windows_server_20H2:10.0.19042.1645:*:*:*:*:*:*:*" + } + ], + "severities": [ + { + "system": "cvssv3.1", + "value": 7.5, + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:U/RL:O/RC:C" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:N/A:Y/T:P/P:M/B:A/M:M/D:T/2024-05-30T18:43:59Z/" + } + ], + "date_published": "2022-04-15T19:05:52+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2.json new file mode 100644 index 000000000..5d7e241a5 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data2.json @@ -0,0 +1,606 @@ +{ + "containers": { + "cna": { + "title": "Windows Secure Channel Denial of Service Vulnerability", + "datePublic": "2022-04-12T08:00:00+00:00", + "affected": [ + { + "vendor": "Microsoft", + "product": "Windows 10 Version 1809", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_10_1809:10.0.17763.2803:*:*:*:*:*:arm64:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.17763.2803", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2019", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2019:10.0.17763.2803:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.17763.2803", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2019 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2019:10.0.17763.2803:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.17763.2803", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 1909", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_1909:10.0.18363.2212:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_10_1809:10.0.18363.2212:*:*:*:*:*:x64:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.18363.2212", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 21H1", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:arm64:*", + "cpe:2.3:o:microsoft:windows_10_21H1:10.0.19043.1645:*:*:*:*:*:x86:*" + ], + "platforms": [ + "x64-based Systems", + "ARM64-based Systems", + "32-bit Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.19043.1645", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2022", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2022:10.0.20348.643:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.20348.643", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 20H2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_20H2:10.0.19042.1645:*:*:*:*:*:arm64:*" + ], + "platforms": [ + "32-bit Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.19042.1645", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server version 20H2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_20H2:10.0.19042.1645:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.19042.1645", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 11 version 21H2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_11_21H2:10.0.22000.613:*:*:*:*:*:arm64:*" + ], + "platforms": [ + "x64-based Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.22000.613", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 21H2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19043.1645:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:arm64:*", + "cpe:2.3:o:microsoft:windows_10_21H2:10.0.19044.1645:*:*:*:*:*:x64:*" + ], + "platforms": [ + "32-bit Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.19043.1645", + "versionType": "custom", + "status": "affected" + }, + { + "version": "10.0.0", + "lessThan": "10.0.19044.1645", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 1507", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_1507:10.0.10240.19265:*:*:*:*:*:x64:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.10240.19265", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 10 Version 1607", + "cpes": [ + "cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_10_1607:10.0.14393.5066:*:*:*:*:*:x64:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.14393.5066", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2016", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2016:10.0.14393.5066:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.14393.5066", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2016 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2016:10.0.14393.5066:*:*:*:*:*:*:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "10.0.0", + "lessThan": "10.0.14393.5066", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 7", + "cpes": [ + "cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x86:*" + ], + "platforms": [ + "32-bit Systems" + ], + "versions": [ + { + "version": "6.1.0", + "lessThan": "6.1.7601.25924", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 7 Service Pack 1", + "cpes": [ + "cpe:2.3:o:microsoft:windows_7:6.1.7601.25924:sp1:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.1.0", + "lessThan": "6.1.7601.25924", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows 8.1", + "cpes": [ + "cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x86:*", + "cpe:2.3:o:microsoft:windows_8.1:6.3.9600.20337:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_rt_8.1:6.3.9600.20337:*:*:*:*:*:*:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems", + "ARM64-based Systems" + ], + "versions": [ + { + "version": "6.3.0", + "lessThan": "6.3.9600.20337", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2008 Service Pack 2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x64:*" + ], + "platforms": [ + "32-bit Systems" + ], + "versions": [ + { + "version": "6.0.0", + "lessThan": "6.0.6003.21446", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2008 Service Pack 2 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x64:*", + "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x86:*" + ], + "platforms": [ + "32-bit Systems", + "x64-based Systems" + ], + "versions": [ + { + "version": "6.0.0", + "lessThan": "6.0.6003.21446", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2008 Service Pack 2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2008_sp2:6.0.6003.21446:*:*:*:*:*:x86:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.0.0", + "lessThan": "6.0.6003.21446", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2008 R2 Service Pack 1", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2008_R2:6.1.7601.25924:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.1.0", + "lessThan": "6.1.7601.25924", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2008 R2 Service Pack 1 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2008_R2:6.1.7601.25924:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.0.0", + "lessThan": "6.1.7601.25924", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2012", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2012:6.2.9200.23679:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.2.0", + "lessThan": "6.2.9200.23679", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2012 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2012:6.2.9200.23679:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.2.0", + "lessThan": "6.2.9200.23679", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2012 R2", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2012_R2:6.3.9600.20337:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.3.0", + "lessThan": "6.3.9600.20337", + "versionType": "custom", + "status": "affected" + } + ] + }, + { + "vendor": "Microsoft", + "product": "Windows Server 2012 R2 (Server Core installation)", + "cpes": [ + "cpe:2.3:o:microsoft:windows_server_2012_R2:6.3.9600.20337:*:*:*:*:*:x64:*" + ], + "platforms": [ + "x64-based Systems" + ], + "versions": [ + { + "version": "6.3.0", + "lessThan": "6.3.9600.20337", + "versionType": "custom", + "status": "affected" + } + ] + } + ], + "descriptions": [ + { + "value": "Windows Secure Channel Denial of Service Vulnerability", + "lang": "en-US" + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "description": "Denial of Service", + "lang": "en-US", + "type": "Impact" + } + ] + } + ], + "providerMetadata": { + "orgId": "f38d906d-7342-40ea-92c1-6c4a2c6478c8", + "shortName": "microsoft", + "dateUpdated": "2024-05-29T14:36:41.369Z" + }, + "references": [ + { + "name": "Windows Secure Channel Denial of Service Vulnerability", + "tags": [ + "vendor-advisory" + ], + "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26915" + } + ], + "metrics": [ + { + "format": "CVSS", + "scenarios": [ + { + "lang": "en-US", + "value": "GENERAL" + } + ], + "cvssV3_1": { + "version": "3.1", + "baseSeverity": "HIGH", + "baseScore": 7.5, + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:U/RL:O/RC:C" + } + } + ] + }, + "adp": [ + { + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2022-26915", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "none" + }, + { + "Automatable": "yes" + }, + { + "Technical Impact": "partial" + } + ], + "version": "2.0.3", + "timestamp": "2024-05-30T18:43:59.085457Z" + } + } + } + ], + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2024-05-30T18:44:03.461Z" + }, + "title": "CISA ADP Vulnrichment" + } + ] + }, + "cveMetadata": { + "assignerOrgId": "f38d906d-7342-40ea-92c1-6c4a2c6478c8", + "assignerShortName": "microsoft", + "cveId": "CVE-2022-26915", + "datePublished": "2022-04-15T19:05:52", + "dateReserved": "2022-03-11T00:00:00", + "dateUpdated": "2024-06-04T17:16:14.274Z", + "state": "PUBLISHED" + }, + "dataType": "CVE_RECORD", + "dataVersion": "5.1" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3-expected.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3-expected.json new file mode 100644 index 000000000..d6a720e80 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3-expected.json @@ -0,0 +1,35 @@ +{ + "advisory_id": "CVE-2024-4901", + "aliases": [], + "summary": "An issue was discovered in GitLab CE/EE affecting all versions starting from 16.9 prior to 16.11.5, starting from 17.0 prior to 17.0.3, and starting from 17.1 prior to 17.1.1, where a stored XSS vulnerability could be imported from a project with malicious commit notes.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "461773", + "reference_type": "bug", + "url": "https://gitlab.com/gitlab-org/gitlab/-/issues/461773" + }, + { + "reference_id": "2500163", + "reference_type": "exploit", + "url": "https://hackerone.com/reports/2500163" + } + ], + "severities": [ + { + "system": "cvssv3.1", + "value": 8.7, + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N" + }, + { + "system": "ssvc", + "value": "Track", + "scoring_elements": "SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2024-06-28T03:55:15Z/" + } + ], + "date_published": "2024-06-26T23:31:05.422000+00:00", + "weaknesses": [ + 79 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3.json b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3.json new file mode 100644 index 000000000..9eaddd7c9 --- /dev/null +++ b/vulnerabilities/tests/test_data/cve_schema/vulnrichment-data3.json @@ -0,0 +1,210 @@ +{ + "dataType": "CVE_RECORD", + "containers": { + "adp": [ + { + "title": "CISA ADP Vulnrichment", + "metrics": [ + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2024-4901", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "none" + }, + { + "Automatable": "no" + }, + { + "Technical Impact": "total" + } + ], + "version": "2.0.3", + "timestamp": "2024-06-28T03:55:15.710247Z" + } + } + } + ], + "affected": [ + { + "cpes": [ + "cpe:2.3:a:gitlab:gitlab:16.9.0:*:*:*:*:*:*:*" + ], + "vendor": "gitlab", + "product": "gitlab", + "versions": [ + { + "status": "affected", + "version": "16.9.0", + "lessThan": "16.11.5", + "versionType": "custom" + } + ], + "defaultStatus": "unknown" + }, + { + "cpes": [ + "cpe:2.3:a:gitlab:gitlab:17.0:*:*:*:*:*:*:*" + ], + "vendor": "gitlab", + "product": "gitlab", + "versions": [ + { + "status": "affected", + "version": "17.0", + "lessThan": "17.0.3", + "versionType": "custom" + } + ], + "defaultStatus": "unknown" + }, + { + "cpes": [ + "cpe:2.3:a:gitlab:gitlab:17.1:*:*:*:*:*:*:*" + ], + "vendor": "gitlab", + "product": "gitlab", + "versions": [ + { + "status": "affected", + "version": "17.1", + "lessThan": "17.1.1", + "versionType": "custom" + } + ], + "defaultStatus": "unknown" + } + ], + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2024-06-28T13:08:54.273Z" + } + } + ], + "cna": { + "title": "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') in GitLab", + "credits": [ + { + "lang": "en", + "type": "finder", + "value": "Thanks [yvvdwf](https://hackerone.com/yvvdwf) for reporting this vulnerability through our HackerOne bug bounty program" + } + ], + "metrics": [ + { + "format": "CVSS", + "cvssV3_1": { + "scope": "CHANGED", + "version": "3.1", + "baseScore": 8.7, + "attackVector": "NETWORK", + "baseSeverity": "HIGH", + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N", + "integrityImpact": "HIGH", + "userInteraction": "REQUIRED", + "attackComplexity": "LOW", + "availabilityImpact": "NONE", + "privilegesRequired": "LOW", + "confidentialityImpact": "HIGH" + }, + "scenarios": [ + { + "lang": "en", + "value": "GENERAL" + } + ] + } + ], + "affected": [ + { + "repo": "git://git@gitlab.com:gitlab-org/gitlab.git", + "vendor": "GitLab", + "product": "GitLab", + "versions": [ + { + "status": "affected", + "version": "16.9", + "lessThan": "16.11.5", + "versionType": "semver" + }, + { + "status": "affected", + "version": "17.0", + "lessThan": "17.0.3", + "versionType": "semver" + }, + { + "status": "affected", + "version": "17.1", + "lessThan": "17.1.1", + "versionType": "semver" + } + ], + "defaultStatus": "unaffected" + } + ], + "solutions": [ + { + "lang": "en", + "value": "Upgrade to versions 17.1.1, 17.0.3, 16.11.5 or above." + } + ], + "references": [ + { + "url": "https://gitlab.com/gitlab-org/gitlab/-/issues/461773", + "name": "GitLab Issue #461773", + "tags": [ + "issue-tracking", + "permissions-required" + ] + }, + { + "url": "https://hackerone.com/reports/2500163", + "name": "HackerOne Bug Bounty Report #2500163", + "tags": [ + "technical-description", + "exploit", + "permissions-required" + ] + } + ], + "descriptions": [ + { + "lang": "en", + "value": "An issue was discovered in GitLab CE/EE affecting all versions starting from 16.9 prior to 16.11.5, starting from 17.0 prior to 17.0.3, and starting from 17.1 prior to 17.1.1, where a stored XSS vulnerability could be imported from a project with malicious commit notes." + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "lang": "en", + "type": "CWE", + "cweId": "CWE-79", + "description": "CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')" + } + ] + } + ], + "providerMetadata": { + "orgId": "ceab7361-8a18-47b1-92ba-4d7d25f6715a", + "shortName": "GitLab", + "dateUpdated": "2024-06-26T23:31:05.422Z" + } + } + }, + "cveMetadata": { + "cveId": "CVE-2024-4901", + "state": "PUBLISHED", + "dateUpdated": "2024-06-28T13:08:59.344Z", + "dateReserved": "2024-05-15T09:30:34.902Z", + "assignerOrgId": "ceab7361-8a18-47b1-92ba-4d7d25f6715a", + "datePublished": "2024-06-26T23:31:05.422Z", + "assignerShortName": "GitLab" + }, + "dataVersion": "5.1" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_utils.py b/vulnerabilities/tests/test_utils.py index c9ba98e79..d9b97cd09 100644 --- a/vulnerabilities/tests/test_utils.py +++ b/vulnerabilities/tests/test_utils.py @@ -19,6 +19,7 @@ from vulnerabilities.utils import nearest_patched_package from vulnerabilities.utils import resolve_version_range from vulnerabilities.utils import split_markdown_front_matter +from vulnerabilities.utils import ssvc_calculator def test_nearest_patched_package(): @@ -151,3 +152,38 @@ def test_resolve_version_range_without_ignorable_versions(): def test_get_severity_range(): assert get_severity_range({""}) is None assert get_severity_range({}) is None + + +def test_ssvc_calculator1(): + assert ssvc_calculator( + { + "id": "CVE-2024-5396", + "role": "CISA Coordinator", + "options": [ + {"Exploitation": "poc"}, + {"Automatable": "no"}, + {"Technical Impact": "partial"}, + ], + "version": "2.0.3", + "timestamp": "2024-05-28T15:58:04.187512Z", + } + ) == ("SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2024-05-28T15:58:04Z/", "Track") + + +def test_ssvc_calculator2(): + assert ssvc_calculator( + { + "id": "CVE-2024-5396", + "role": "CISA Coordinator", + "options": [ + {"Exploitation": "active"}, + {"Automatable": "no"}, + {"Technical Impact": "total"}, + {"Mission Prevalence": "Minimal"}, + {"Public Well-being Impact": "Material"}, + {"Mission & Well-being": "medium"}, + ], + "version": "2.0.3", + "timestamp": "2024-05-28T15:58:04.187512Z", + } + ) == ("SSVCv2/E:A/A:N/T:T/P:M/B:A/M:M/D:A/2024-05-28T15:58:04Z/", "Attend") diff --git a/vulnerabilities/tests/test_vulnrichment.py b/vulnerabilities/tests/test_vulnrichment.py index 7c52122ec..bf2917e23 100644 --- a/vulnerabilities/tests/test_vulnrichment.py +++ b/vulnerabilities/tests/test_vulnrichment.py @@ -1,9 +1,17 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + import json import os from unittest import TestCase from vulnerabilities.importers.vulnrichment import parse_cve_advisory -from vulnerabilities.importers.vulnrichment import ssvc_calculator from vulnerabilities.tests import util_tests BASE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -34,36 +42,3 @@ def test_to_advisorie3(self): imported_data = parse_cve_advisory(mock_response, advisory_url="http://test.com") result = imported_data.to_dict() util_tests.check_results_against_json(result, expected_file) - - def test_make_ssvc_vector1(self): - assert ssvc_calculator( - { - "id": "CVE-2024-5396", - "role": "CISA Coordinator", - "options": [ - {"Exploitation": "poc"}, - {"Automatable": "no"}, - {"Technical Impact": "partial"}, - ], - "version": "2.0.3", - "timestamp": "2024-05-28T15:58:04.187512Z", - } - ) == ("SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2024-05-28T15:58:04Z/", "Track") - - def test_make_ssvc_vector2(self): - assert ssvc_calculator( - { - "id": "CVE-2024-5396", - "role": "CISA Coordinator", - "options": [ - {"Exploitation": "active"}, - {"Automatable": "no"}, - {"Technical Impact": "total"}, - {"Mission Prevalence": "Minimal"}, - {"Public Well-being Impact": "Material"}, - {"Mission & Well-being": "medium"}, - ], - "version": "2.0.3", - "timestamp": "2024-05-28T15:58:04.187512Z", - } - ) == ("SSVCv2/E:A/A:N/T:T/P:M/B:A/M:M/D:A/2024-05-28T15:58:04Z/", "Attend") diff --git a/vulnerabilities/utils.py b/vulnerabilities/utils.py index b65726a5d..67c6bc10f 100644 --- a/vulnerabilities/utils.py +++ b/vulnerabilities/utils.py @@ -26,6 +26,7 @@ from unittest.mock import MagicMock from urllib.parse import urljoin +import dateparser import requests import saneyaml import toml @@ -678,3 +679,117 @@ def create_registry(pipelines): registry[key] = pipeline return registry + + +def ssvc_calculator(ssvc_data): + """ + Return the ssvc vector and the decision value + """ + options = ssvc_data.get("options", []) + timestamp = ssvc_data.get("timestamp") + + # Extract the options into a dictionary + options_dict = {k: v.lower() for option in options for k, v in option.items()} + + # We copied the table value from this link. + # https://www.cisa.gov/sites/default/files/publications/cisa-ssvc-guide%20508c.pdf + + # Determining Mission and Well-Being Impact Value + mission_well_being_table = { + # (Mission Prevalence, Public Well-being Impact) : "Mission & Well-being" + ("minimal", "minimal"): "low", + ("minimal", "material"): "medium", + ("minimal", "irreversible"): "high", + ("support", "minimal"): "medium", + ("support", "material"): "medium", + ("support", "irreversible"): "high", + ("essential", "minimal"): "high", + ("essential", "material"): "high", + ("essential", "irreversible"): "high", + } + + if "Mission Prevalence" not in options_dict: + options_dict["Mission Prevalence"] = "minimal" + + if "Public Well-being Impact" not in options_dict: + options_dict["Public Well-being Impact"] = "material" + + options_dict["Mission & Well-being"] = mission_well_being_table[ + (options_dict["Mission Prevalence"], options_dict["Public Well-being Impact"]) + ] + + decision_key = ( + options_dict.get("Exploitation"), + options_dict.get("Automatable"), + options_dict.get("Technical Impact"), + options_dict.get("Mission & Well-being"), + ) + + decision_points = { + "Exploitation": {"E": {"none": "N", "poc": "P", "active": "A"}}, + "Automatable": {"A": {"no": "N", "yes": "Y"}}, + "Technical Impact": {"T": {"partial": "P", "total": "T"}}, + "Public Well-being Impact": {"B": {"minimal": "M", "material": "A", "irreversible": "I"}}, + "Mission Prevalence": {"P": {"minimal": "M", "support": "S", "essential": "E"}}, + "Mission & Well-being": {"M": {"low": "L", "medium": "M", "high": "H"}}, + } + + # Create the SSVC vector + ssvc_vector = "SSVCv2/" + for key, value_map in options_dict.items(): + options_key = decision_points.get(key) + for lhs, rhs_map in options_key.items(): + ssvc_vector += f"{lhs}:{rhs_map.get(value_map)}/" + + # "Decision": {"D": {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"}}, + decision_values = {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"} + + decision_lookup = { + ("none", "no", "partial", "low"): "Track", + ("none", "no", "partial", "medium"): "Track", + ("none", "no", "partial", "high"): "Track", + ("none", "no", "total", "low"): "Track", + ("none", "no", "total", "medium"): "Track", + ("none", "no", "total", "high"): "Track*", + ("none", "yes", "partial", "low"): "Track", + ("none", "yes", "partial", "medium"): "Track", + ("none", "yes", "partial", "high"): "Attend", + ("none", "yes", "total", "low"): "Track", + ("none", "yes", "total", "medium"): "Track", + ("none", "yes", "total", "high"): "Attend", + ("poc", "no", "partial", "low"): "Track", + ("poc", "no", "partial", "medium"): "Track", + ("poc", "no", "partial", "high"): "Track*", + ("poc", "no", "total", "low"): "Track", + ("poc", "no", "total", "medium"): "Track*", + ("poc", "no", "total", "high"): "Attend", + ("poc", "yes", "partial", "low"): "Track", + ("poc", "yes", "partial", "medium"): "Track", + ("poc", "yes", "partial", "high"): "Attend", + ("poc", "yes", "total", "low"): "Track", + ("poc", "yes", "total", "medium"): "Track*", + ("poc", "yes", "total", "high"): "Attend", + ("active", "no", "partial", "low"): "Track", + ("active", "no", "partial", "medium"): "Track", + ("active", "no", "partial", "high"): "Attend", + ("active", "no", "total", "low"): "Track", + ("active", "no", "total", "medium"): "Attend", + ("active", "no", "total", "high"): "Act", + ("active", "yes", "partial", "low"): "Attend", + ("active", "yes", "partial", "medium"): "Attend", + ("active", "yes", "partial", "high"): "Act", + ("active", "yes", "total", "low"): "Attend", + ("active", "yes", "total", "medium"): "Act", + ("active", "yes", "total", "high"): "Act", + } + + decision = decision_lookup.get(decision_key, "") + + if decision: + ssvc_vector += f"D:{decision_values.get(decision)}/" + + if timestamp: + timestamp_formatted = dateparser.parse(timestamp).strftime("%Y-%m-%dT%H:%M:%SZ") + + ssvc_vector += f"{timestamp_formatted}/" + return ssvc_vector, decision