Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions vulnerabilities/importers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -97,6 +98,7 @@
npm_importer.NpmImporterPipeline,
nginx_importer.NginxImporterPipeline,
pysec_importer.PyPIImporterPipeline,
fireeye_importer_v2.FireeyeImporterPipeline,
apache_tomcat.ApacheTomcatImporter,
postgresql.PostgreSQLImporter,
debian.DebianImporter,
Expand Down
218 changes: 218 additions & 0 deletions vulnerabilities/pipelines/v2_importers/fireeye_importer_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
#
# 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_ids = 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
aliases = dedupe([cve_id.strip() for cve_id in cve_ids])
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=aliases,
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 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)]
38 changes: 38 additions & 0 deletions vulnerabilities/tests/pipelines/v2_importers/test_fireeye_v2.py
Original file line number Diff line number Diff line change
@@ -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 / "FEYE-2019-0002.md",
TEST_DATA / "FEYE-2020-0020.md",
TEST_DATA / "MNDT-2025-0009.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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"advisory_id": "FEYE-2019-0002",
"aliases": [
"CVE-2019-7245"
],
"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/FEYE-2019-0002.md"
}
]
41 changes: 41 additions & 0 deletions vulnerabilities/tests/test_data/fireeye_v2/FEYE-2019-0002.md
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"advisory_id": "FEYE-2020-0020",
"aliases": [
"CVE-2020-12878"
],
"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/FEYE-2020-0020.md"
}
]
Loading
Loading