diff --git a/vulnerabilities/importers/__init__.py b/vulnerabilities/importers/__init__.py index 65c8a79ef..98726beb2 100644 --- a/vulnerabilities/importers/__init__.py +++ b/vulnerabilities/importers/__init__.py @@ -49,6 +49,7 @@ elixir_security_importer as elixir_security_importer_v2, ) from vulnerabilities.pipelines.v2_importers import epss_importer_v2 +from vulnerabilities.pipelines.v2_importers import fireeye_importer_v2 from vulnerabilities.pipelines.v2_importers import github_osv_importer as github_osv_importer_v2 from vulnerabilities.pipelines.v2_importers import gitlab_importer as gitlab_importer_v2 from vulnerabilities.pipelines.v2_importers import istio_importer as istio_importer_v2 @@ -93,6 +94,7 @@ npm_importer.NpmImporterPipeline, nginx_importer.NginxImporterPipeline, pysec_importer.PyPIImporterPipeline, + fireeye_importer_v2.FireeyeImporterPipeline, apache_tomcat.ApacheTomcatImporter, postgresql.PostgreSQLImporter, debian.DebianImporter, diff --git a/vulnerabilities/pipelines/v2_importers/fireeye_importer_v2.py b/vulnerabilities/pipelines/v2_importers/fireeye_importer_v2.py new file mode 100644 index 000000000..0b9dd6ff5 --- /dev/null +++ b/vulnerabilities/pipelines/v2_importers/fireeye_importer_v2.py @@ -0,0 +1,228 @@ +# +# 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 logging +import re +from pathlib import Path +from typing import Iterable +from typing import List + +from fetchcode.vcs import fetch_via_vcs + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import ReferenceV2 +from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 +from vulnerabilities.severity_systems import GENERIC +from vulnerabilities.utils import build_description +from vulnerabilities.utils import create_weaknesses_list +from vulnerabilities.utils import cwe_regex +from vulnerabilities.utils import dedupe +from vulnerabilities.utils import get_advisory_url + +logger = logging.getLogger(__name__) + + +class FireeyeImporterPipeline(VulnerableCodeBaseImporterPipelineV2): + spdx_license_expression = "CC-BY-SA-4.0 AND MIT" + license_url = "https://github.com/mandiant/Vulnerability-Disclosures/blob/master/README.md" + notice = """ + Copyright (c) Mandiant + The following licenses/licensing apply to this Mandiant repository: + 1. CC BY-SA 4.0 - For CVE related information not including source code (such as PoCs) + 2. MIT - For source code contained within provided CVE information + """ + repo_url = "git+https://github.com/mandiant/Vulnerability-Disclosures" + pipeline_id = "fireeye_importer_v2" + + @classmethod + def steps(cls): + return ( + cls.clone, + cls.collect_and_store_advisories, + cls.clean_downloads, + ) + + def advisories_count(self): + base_path = Path(self.vcs_response.dest_dir) + return sum( + 1 + for p in base_path.glob("**/*") + if p.suffix.lower() == ".md" or p.stem.upper() == "README" + ) + + def clone(self): + self.log(f"Cloning `{self.repo_url}`") + self.vcs_response = fetch_via_vcs(self.repo_url) + + def collect_advisories(self) -> Iterable[AdvisoryData]: + base_path = Path(self.vcs_response.dest_dir) + for file_path in base_path.glob("**/*"): + if file_path.suffix.lower() != ".md": + continue + + if file_path.stem.upper() == "README": + continue + + try: + with open(file_path, encoding="utf-8-sig") as f: + yield parse_advisory_data( + raw_data=f.read(), file_path=file_path, base_path=base_path + ) + except UnicodeError: + logger.error(f"Invalid File UnicodeError: {file_path}") + + 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() + + +def parse_advisory_data(raw_data, file_path, base_path) -> AdvisoryData: + """ + Parse a fireeye advisory repo and return an AdvisoryData or None. + These files are in Markdown format. + """ + raw_data = raw_data.replace("\n\n", "\n") + md_list = raw_data.split("\n") + md_dict = md_list_to_dict(md_list) + + database_id = md_list[0][1::] + summary = md_dict.get(database_id[1::]) or [] + description = md_dict.get("## Description") or [] + impact = md_dict.get("## Impact") + cve_ref = md_dict.get("## CVE Reference") or [] + references = md_dict.get("## References") or [] + cwe_data = md_dict.get("## Common Weakness Enumeration") or [] + + advisory_id = file_path.stem + advisory_url = get_advisory_url( + file=file_path, + base_path=base_path, + url="https://github.com/mandiant/Vulnerability-Disclosures/blob/master/", + ) + + return AdvisoryData( + advisory_id=advisory_id, + aliases=get_aliases(database_id, cve_ref), + summary=build_description(" ".join(summary), " ".join(description)), + references_v2=get_references(references), + severities=get_severities(impact), + weaknesses=get_weaknesses(cwe_data), + url=advisory_url, + original_advisory_text=raw_data, + ) + + +def get_references(references): + """ + Return a list of Reference from a list of URL reference in md format + >>> get_references(["- http://1-4a.com/cgi-bin/alienform/af.cgi"]) + [ReferenceV2(reference_id='', reference_type='', url='http://1-4a.com/cgi-bin/alienform/af.cgi')] + >>> get_references(["- [Mitre CVE-2021-42712](https://www.cve.org/CVERecord?id=CVE-2021-42712)"]) + [ReferenceV2(reference_id='', reference_type='', url='https://www.cve.org/CVERecord?id=CVE-2021-42712')] + """ + urls = [] + for ref in references: + clean_ref = ref.strip() + clean_ref = clean_ref.lstrip("-* ") + url = matcher_url(clean_ref) + if url: + urls.append(url) + return [ReferenceV2(url=url) for url in urls if url] + + +def matcher_url(ref) -> str: + """ + Returns URL of the reference markup from reference url in Markdown format + """ + markup_regex = "\[([^\[]+)]\(\s*(http[s]?://.+)\s*\)" + matched_markup = re.findall(markup_regex, ref) + if matched_markup: + return matched_markup[0][1] + else: + return ref + + +def get_aliases(database_id, cve_ref) -> List: + """ + Returns a List of Aliases from a database_id and a list of CVEs + >>> get_aliases("MNDT-2021-0012", ["CVE-2021-44207"]) + ['CVE-2021-44207', 'MNDT-2021-0012'] + """ + cleaned_db_id = database_id.strip() + cve_ref.append(cleaned_db_id) + return dedupe(cve_ref) + + +def md_list_to_dict(md_list): + """ + Returns a dictionary of md_list from a list of a md file splited by \n + >>> md_list_to_dict(["# Header","hello" , "hello again" ,"# Header2"]) + {'# Header': ['hello', 'hello again'], '# Header2': []} + """ + md_dict = {} + md_key = "" + for md_line in md_list: + if md_line.startswith("#"): + md_dict[md_line] = [] + md_key = md_line + else: + md_dict[md_key].append(md_line) + return md_dict + + +def get_weaknesses(cwe_data): + """ + Return the list of CWE IDs as integers from a list of weakness summaries, e.g., [379]. + >>> get_weaknesses([ + ... "CWE-379: Creation of Temporary File in Directory with Insecure Permissions", + ... "CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')" + ... ]) + [379, 362] + """ + cwe_list = [] + for line in cwe_data: + cwe_ids = re.findall(cwe_regex, line) + cwe_list.extend(cwe_ids) + + weaknesses = create_weaknesses_list(cwe_list) + return weaknesses + + +def get_severities(impact): + """ + Return a list of VulnerabilitySeverity extracted from the impact string. + >>> get_severities([ + ... "High - Arbitrary Ring 0 code execution", + ... ]) + [VulnerabilitySeverity(system=ScoringSystem(identifier='generic_textual', name='Generic textual severity rating', url='', notes='Severity for generic scoring systems. Contains generic textual values like High, Low etc'), value='High', scoring_elements='', published_at=None, url=None)] + >>> get_severities([]) + [] + """ + if not impact: + return [] + + impact_text = impact[0] + value = "" + if " - " in impact_text: + value = impact_text.split(" - ")[0] + elif ": " in impact_text: + value = impact_text.split(": ")[0] + else: + parts = impact_text.split(" ") + if parts: + value = parts[0] + + if not value.lower() in ["high", "medium", "low"]: + return [] + + return [VulnerabilitySeverity(system=GENERIC, value=value)] diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_fireeye_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_fireeye_v2.py new file mode 100644 index 000000000..d22c8c9ec --- /dev/null +++ b/vulnerabilities/tests/pipelines/v2_importers/test_fireeye_v2.py @@ -0,0 +1,38 @@ +# +# 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. +# + +from pathlib import Path +from unittest.mock import Mock +from unittest.mock import patch + +import pytest + +from vulnerabilities.pipelines.v2_importers.fireeye_importer_v2 import FireeyeImporterPipeline +from vulnerabilities.tests import util_tests + +TEST_DATA = Path(__file__).parent.parent.parent / "test_data" / "fireeye_v2" + +TEST_CVE_FILES = [ + TEST_DATA / "fireeye_test1.md", + TEST_DATA / "fireeye_test2.md", + TEST_DATA / "fireeye_test3.md", +] + + +@pytest.mark.django_db +@pytest.mark.parametrize("md_file", TEST_CVE_FILES) +def test_fireeye_advisories_per_file(md_file): + pipeline = FireeyeImporterPipeline() + pipeline.vcs_response = Mock(dest_dir=TEST_DATA) + + with patch.object(Path, "glob", return_value=[md_file]): + result = [adv.to_dict() for adv in pipeline.collect_advisories()] + + expected_file = md_file.with_name(md_file.stem + "-expected.json") + util_tests.check_results_against_json(result, expected_file) diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1-expected.json b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1-expected.json new file mode 100644 index 000000000..ec3422ae9 --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1-expected.json @@ -0,0 +1,23 @@ +[ + { + "advisory_id": "fireeye_test1", + "aliases": [ + "CVE-2019-7245 ", + "FEYE-2019-0002" + ], + "summary": "GPU-Z.sys, part of the GPU-Z package from TechPowerUp, exposes the wrmsr instruction to user-mode callers without properly validating the target Model Specific Register (MSR). This can result in arbitrary unsigned code being executed in Ring 0.", + "affected_packages": [], + "references_v2": [], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "High", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [], + "url": "https://github.com/mandiant/Vulnerability-Disclosures/blob/master/fireeye_test1.md" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1.md b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1.md new file mode 100644 index 000000000..3f990e06d --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test1.md @@ -0,0 +1,41 @@ +# FEYE-2019-0002 +## Description +GPU-Z.sys, part of the GPU-Z package from TechPowerUp, exposes the wrmsr instruction to user-mode callers without properly validating the target Model Specific Register (MSR). This can result in arbitrary unsigned code being executed in Ring 0. + +## Impact +High - Arbitrary Ring 0 code execution + +## Exploitability +Medium/Low - Driver must be loaded or attacker will require admin rights. Newer versions require admin callers. + +## CVE Reference +CVE-2019-7245 + +## Technical Details +IOCTL 0x8000644C in the GPU-Z driver instructs the binary to modify a Model Specific Register (MSR) on the target system. These registers control a wide variety of system functionality and can be used to monitor CPU temperature, track branches in code, tweak voltages, etc. MSRs are also responsible for setting the kernel mode function responsible for handling system calls. + +The driver does not appropriately filter access to MSRs, allowing an attacker to overwrite the system call handler and run unsigned code in Ring 0. Allowing access to any of the following MSRs can result in arbitrary Ring 0 code being executed: + +* 0xC0000081 +* 0xC0000082 +* 0xC0000083 +* 0x174 +* 0x175 +* 0x176 + +For exploitation details see the INFILTRATE presentation in the references. + +## Resolution +This issue is fixed in v2.23.0: [https://www.techpowerup.com/257995/techpowerup-releases-gpu-z-v2-23-0](https://www.techpowerup.com/257995/techpowerup-releases-gpu-z-v2-23-0) + +## Discovery Credits +Ryan Warns + +## Disclosure Timeline +- 2 February 2019 - Contacted vendor +- 2 February 2019 - Vendor response, confirmation of issue +- 25 July 2019 - Vendor confirmed fix +- 6 August 2019 - Fixed version released + +## References +[Exploitation Details](https://downloads.immunityinc.com/infiltrate2019-slidepacks/ryan-warns-timothy-harrison-device-driver-debauchery-msr-madness/MSR_Madness_v2.9_INFILTRATE.pptx) \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2-expected.json b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2-expected.json new file mode 100644 index 000000000..8ad9fa142 --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2-expected.json @@ -0,0 +1,39 @@ +[ + { + "advisory_id": "fireeye_test2", + "aliases": [ + "CVE-2020-12878", + "FEYE-2020-0020" + ], + "summary": "Digi International's ConnectPort X2e is susceptible to a local privilege escalation vulnerable to the privileged user `root`.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-12878" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://www.fireeye.com/blog/threat-research/2021/02/solarcity-exploitation-of-x2e-iot-device-part-one.html" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://www.fireeye.com/blog/threat-research/2021/02/solarcity-exploitation-of-x2e-iot-device-part-two.html" + } + ], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "High", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [], + "url": "https://github.com/mandiant/Vulnerability-Disclosures/blob/master/fireeye_test2.md" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2.md b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2.md new file mode 100644 index 000000000..3f9d18e2e --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test2.md @@ -0,0 +1,41 @@ +# FEYE-2020-0020 +## Description + +Digi International's ConnectPort X2e is susceptible to a local privilege escalation vulnerable to the privileged user `root`. + +## Impact +High - An attacker with remote network access to a X2e could remotely compromise the device. This could be used to install malware, modify system behavior, or stage a more serious attack. + +## Exploitability +Medium - An attacker would need to read and write files as the system user python. On production devices, this can be accomplished remotely by establishing an SSH connection or access via a TTY. + +## CVE Reference +CVE-2020-12878 + +## Technical Details +The ConnectPort X2e performed filesystem actions as the privileged system user root on files controllable by the less-privileged user python. A malicious attacker could use this to escalate privileges from the local user `python` user to `root`. + +Mandiant determined that the user `root` executed the file `/etc/init.d/S50dropbear.sh` during normal system boot. The shell script performed a `chown` on the directory `/WEB/python/.ssh/`, which was writable as the user `python`. + +To exploit this, Mandiant used Linux symbolic links to force the system to set the ownership of the directory `/etc/init.d/` to `python:python`. Mandiant could then create a malicious `init` script in the `/etc/init.d/` directory that would be executed by `root` on future system boots. + +## Resolution +Digi International has fixed the reported vulnerability in [version 3.2.30.6](https://ftp1.digi.com/support/firmware/93001304_D.pdf) (May 2020) of the ConnectPort X2e software. + +## Discovery Credits +- Jake Valletta, FireEye Mandiant +- Sam Sabetan, FireEye Mandiant + +## Disclosure Timeline + +- 13 February 2020 - Issue reported to vendor +- 11 March 2020 - Issue confirmed by Digi International +- 14 May 2020 - CVE reserved with MITRE +- May 2020 - Digi Releases Patch +- 17 February 2021 - FireEye Mandiant advisory published + +## References + +- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-12878 +- https://www.fireeye.com/blog/threat-research/2021/02/solarcity-exploitation-of-x2e-iot-device-part-one.html +- https://www.fireeye.com/blog/threat-research/2021/02/solarcity-exploitation-of-x2e-iot-device-part-two.html \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3-expected.json b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3-expected.json new file mode 100644 index 000000000..6f8f07483 --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3-expected.json @@ -0,0 +1,35 @@ +[ + { + "advisory_id": "fireeye_test3", + "aliases": [ + "MNDT-2025-0009" + ], + "summary": "Improper verification of cryptographic signature in the installer for Zoom Workplace VDI Client for Windows may allow an authenticated user to conduct an escalation of privilege via local access.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://www.zoom.com/en/trust/security-bulletin/zsb-25042/" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://www.cve.org/CVERecord?id=CVE-2025-64740" + } + ], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "Medium", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [ + 347 + ], + "url": "https://github.com/mandiant/Vulnerability-Disclosures/blob/master/fireeye_test3.md" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3.md b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3.md new file mode 100644 index 000000000..aee1a5386 --- /dev/null +++ b/vulnerabilities/tests/test_data/fireeye_v2/fireeye_test3.md @@ -0,0 +1,38 @@ +# MNDT-2025-0009 + +## Description +Improper verification of cryptographic signature in the installer for Zoom Workplace VDI Client for Windows may allow an authenticated user to conduct an escalation of privilege via local access. + +## Impact +Medium: Executing untrusted, unsigned code can aid an adversary in bypassing endpoint security controls such as application whitelisting or endpoint detection and response products. It can also lead to the compromise of the VDI Client entirely. + +## Exploitability +High: Adversaries need standard user access to a system with the affected version of Zoom's Workplace VDI client for Windows installed. + +## CVE ID +[CVE-2025-64740](https://www.cve.org/CVERecord?id=CVE-2025-64740) + +## Common Weakness Enumeration +CWE-347: Improper Verification of Cryptographic Signature + +## Details +The Zoom VDI Client attempted to load a DLL named WFAPI64.dll which does not exist on a system as part of the standard installation process. Additionally, a path formatting issue also existed where the directory name of the user's PATH variable is appended to the name of the DLL to search for which led to a unique DLL load attempt upon every execution. The Zoom Client also did not verify the signature of the DLL when loaded. + +By crafting a specific DLL and making a modification to the PATH variable, it's possible to execute unauthorized, unsigned code in the context of Zoom's VDI Client. + +## Resolution +Upgrade to Zoom Workplace VDI Client for Windows, versions 6.3.14, 6.4.12 and 6.5.10 or greater in their respective tracks. + +## Discovery Credits +* Cory Baker, Mandiant + +## Disclosure Timeline +* July 24, 2025: Initial report to the Zoom Vulnerability Disclosure team +* August 8, 2025: Issue confirmed by Zoom's engineering team +* September 5, 2025: Zoom released Workspace VDI Client v6.5.10 +* November 11, 2025: Zoom Security Bulletin issued + +## References +* https://www.zoom.com/en/trust/security-bulletin/zsb-25042/ +* https://www.cve.org/CVERecord?id=CVE-2025-64740 +