McAfee Threat Intelligence Exchange V2
Connect to McAfee TIE using the McAfee DXL client.
Data Enrichment & Threat Intelligence · McAfee Threat Intelligence Exchange
Details
| ID | McAfee Threat Intelligence Exchange V2 |
|---|---|
| Provider | Trellix |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.0.0 |
| Docker Image | demisto/dxl:1.0.0.10133006 |
| Supported Modules | Agentix XSIAM EDR Cortex Cloud Cloud Runtime Security |
README
Use the McAfee Threat Intelligence Exchange (TIE) integration to get file reputations and the systems that reference the files.
Connect to McAfee TIE using the McAfee DXL client.
This integration was integrated and tested with version 2.0 of McAfee Threat Intelligence Exchange V2
Some changes have been made that might affect your existing content.
If you are upgrading from a previous version of this integration, see Breaking Changes.
Detailed Instructions
This section includes information required for configuring an integration instance.
Prerequisites - Connect to McAfee Threat Intelligence Exchange (TIE) using the DXL TIE Client
To connect the McAfee TIE using the DXL TIE client, you need to create certificates and configure DXL. For more information, see the documentation. After you complete this configuration, you will have the following files:
- Broker CA certificates (
brokercerts.crtfile) - Client certificate (
client.crtfile) - Client private key (
client.keyfile) - Broker list properties file (
brokerlist.propertiesfile)
Important: These are the actual certificates, not request certificates.
set-file instruction
To use the tie-set-file-reputation command, you need to authorize the client (Cortex XSOAR) to run the command. Follow the instructions to do so. In step 4, instead of selecting Active Response Server API, select TIE Server Set Enterprise Reputation.
Dependencies (Python packages)
You don’t need to install the packages, they are included in the Docker image.
- DXL Client documentation
- DXL TIE Client documentation
Configure McAfee Threat Intelligence Exchange V2 in Cortex
| Parameter | Description | Required |
|---|---|---|
| Broker CA certificates | From `brokercerts.crt` file. | True |
| Client certificates | From `client.crt` file. | True |
| Client private key | From `client.key` file. Make sure that the type of the field is not `encrypted` when filling it out. | True |
| Broker URLs | The format should be: [ssl://]<hostname>[:port]. Get the hostname and port from the `brokerlist.properties` file. The broker should be reachable from Cortex XSOAR server. |
True |
| Source Reliability | Reliability of the source providing the intelligence data. | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
file
Retrieves the reputations for the specified hashes. Can be “MD5”, “SHA1”, or “SHA256”.
Base Command
file
Input
| Argument Name | Description | Required |
|---|---|---|
| file | Hashes of the files to query. Supports “MD5”, “SHA1”, and “SHA256”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| File.Hashes.type | String | The type of the hash. |
| File.Hashes.value | String | The value of the hash. |
| File.MD5 | String | The MD5 hash of the file. |
| File.SHA1 | String | The SHA1 hash of the file. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.Malicious.Vendor | String | The vendor that reported the file as malicious. |
| File.Malicious.Description | String | A description of why this file was found malicious. |
| DBotScore.Score | Number | The actual score. |
| DBotScore.Vendor | String | The vendor used to calculate the score. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Reliability | String | How reliable the score is (for example, “C - fairly reliable”). |
| McAfee.TIE.FilesReputations.Reputations.Hash | String | The value of the hash. |
| McAfee.TIE.FilesReputations.Reputations.GTI.Provider_ID | Number | The identifier of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.GTI.Trust_Level | Number | The trust level for the reputation subject. |
| McAfee.TIE.FilesReputations.Reputations.GTI.Create_Date | String | The time this reputation was created (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.GTI.Provider | String | The name of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.GTI.Original_Response | String | The raw response as returned by the Global Threat Intelligence (GTI) reputation provider. |
| McAfee.TIE.FilesReputations.Reputations.GTI.First_Contact | String | The time the file was first seen (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.GTI.Prevalence | String | The number of times the file has been requested. |
| McAfee.TIE.FilesReputations.Reputations.ATD.Provider_ID | Number | The identifier of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.ATD.Trust_Level | Number | The trust level for the reputation subject. |
| McAfee.TIE.FilesReputations.Reputations.ATD.Create_Date | String | The time this reputation was created (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.ATD.Provider | String | The name of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.ATD.GAM_Score | String | The trust score reported by the Gateway Anti-Malware (GAM). |
| McAfee.TIE.FilesReputations.Reputations.ATD.AV_Engine_Score | String | The trust score reported by the Anti-Virus engine. |
| McAfee.TIE.FilesReputations.Reputations.ATD.Sandbox_Score | String | The trust score as a result of the sandbox evaluation. |
| McAfee.TIE.FilesReputations.Reputations.ATD.Verdict | String | The overall verdict (taking into consideration all available information). |
| McAfee.TIE.FilesReputations.Reputations.ATD.Behaviors | String | An encoded structure that contains observed behaviors of the file. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Provider_ID | Number | The identifier of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Trust_Level | Number | The trust level for the reputation subject. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Create_Date | String | The time this reputation was created (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Provider | String | The name of the particular provider that provided the reputation. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Server_Version | String | The version of the TIE server that returned the reputations (encoded version string). |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.First_Contact | String | The time the file was first seen (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Prevalence | String | The number of unique systems that have executed the file. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Enterprise_Size | String | The number of systems within the local enterprise. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Min_Local_Rep | String | The lowest reputation found locally on a system. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Max_Local_Rep | String | The highest reputation found locally on a system. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Avg_Local_Rep | String | The average reputation found locally on systems. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Parent_Min_Local_Rep | String | The lowest reputation for the parent found locally on a system. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Parent_Max_Local_Rep | String | The highest reputation for the parent found locally on a system. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Parent_Avg_Local_Rep | String | The average reputation for the parent found locally on systems. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.File_Name_Count | String | The number of unique file names for the file. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Detection_Count | String | The number of detections for the file or certificate. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Last_Detection_Time | String | The last time a detection occurred (UTC timezone). |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Is_Prevalent | String | Whether the file is considered to be prevalent within the enterprise. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Child_File_Reps | String | The child file reputations (aggregate string) according to the following format: - The number of files. - The maximum trust level found across the files. - The minimum trust level found across the files. - The trust level for the last file. - The average trust level across the files. |
| McAfee.TIE.FilesReputations.Reputations.Enterprise.Parent_File_Reps | String | The parent file reputations (aggregate string) according to the following format: - The number of files. - The maximum trust level found across the files. - The minimum trust level found across the files. - The trust level for the last file. - The average trust level across the files. |
Providers Table
| Provider | Numeric | Description |
|---|---|---|
| GTI | 1 | Global Threat Intelligence (GTI). |
| ENTERPRISE | 3 | Enterprise reputation (specific to the local enterprise). |
| ATD | 5 | McAfee Advanced Threat Defense (ATD). |
Trust Level Table
| Trust Level | Numeric | Description |
|---|---|---|
| KNOWN_TRUSTED_INSTALLER | 100 | It is a trusted installer. |
| KNOWN_TRUSTED | 99 | It is a trusted file. |
| MOST_LIKELY_TRUSTED | 85 | It is almost certain that the file is trusted. |
| MIGHT_BE_TRUSTED | 70 | It seems to be a benign file. |
| UNKNOWN | 50 | The reputation provider has encountered the file before but the provider can’t determine its reputation at the moment. |
| MIGHT_BE_MALICIOUS | 30 | It seems to be a suspicious file. |
| MOST_LIKELY_MALICIOUS | 15 | It is almost certain that the file is malicious. |
| KNOWN_MALICIOUS | 1 | It is a malicious file. |
| NOT_SET | 0 | The file’s reputation hasn’t been determined yet. |
ATD Trust Score Table
| Trust Level | Numeric | Description |
|---|---|---|
| KNOWN_TRUSTED | -1 | It is a trusted file. |
| MOST_LIKELY_TRUSTED | 0 | It is almost certain that the file is trusted. |
| MIGHT_BE_TRUSTED | 1 | It seems to be a benign file. |
| UNKNOWN | 2 | The reputation provider has encountered the file before but the provider can’t determine its reputation at the moment. |
| MIGHT_BE_MALICIOUS | 3 | It seems to be a suspicious file. |
| MOST_LIKELY_MALICIOUS | 4 | It is almost certain that the file is malicious. |
| KNOWN_MALICIOUS | 5 | It is a malicious file. |
| NOT_SET | -2 | The file’s reputation hasn’t been determined yet. |
Command Example
!file file=f2c7bb8acc97f92e987a2d4087d021b1,7eb0139d2175739b3ccb0d1110067820be6abd29
Context Example
{
"DBotScore": [
{
"Indicator": "f2c7bb8acc97f92e987a2d4087d021b1",
"Reliability": "C - Fairly reliable",
"Score": 1,
"Type": "file",
"Vendor": "McAfee Threat Intelligence Exchange V2"
},
{
"Indicator": "7eb0139d2175739b3ccb0d1110067820be6abd29",
"Reliability": "C - Fairly reliable",
"Score": 3,
"Type": "file",
"Vendor": "McAfee Threat Intelligence Exchange V2"
}
],
"File": [
{
"Hashes": [
{
"type": "MD5",
"value": "f2c7bb8acc97f92e987a2d4087d021b1"
}
],
"MD5": "f2c7bb8acc97f92e987a2d4087d021b1"
},
{
"Hashes": [
{
"type": "SHA1",
"value": "7eb0139d2175739b3ccb0d1110067820be6abd29"
}
],
"Malicious": {
"Description": "Trust level is 1",
"Vendor": "McAfee Threat Intelligence Exchange V2"
},
"SHA1": "7eb0139d2175739b3ccb0d1110067820be6abd29"
}
],
"McAfee": {
"TIE": {
"FilesReputations": [
{
"Reputations": {
"Enterprise": {
"Create_Date": "2017-10-15 15:33:20",
"Enterprise_Size": "167565",
"File_Name_Count": "3",
"First_Contact": "2017-10-15 15:33:20",
"Is_Prevalent": "0",
"Prevalence": "4336",
"Provider": "Enterprise reputation",
"Provider_ID": 3,
"Server_Version": "3.0.0.480",
"Trust_Level": 85
},
"GTI": {
"Create_Date": "2017-10-15 15:33:20",
"Original_Response": "2139160704",
"Provider": "Global Threat Intelligence (GTI)",
"Provider_ID": 1,
"Trust_Level": 99
},
"Hash": "f2c7bb8acc97f92e987a2d4087d021b1"
}
},
{
"Reputations": {
"Enterprise": {
"Create_Date": "2017-10-15 16:30:54",
"Enterprise_Size": "167566",
"File_Name_Count": "1",
"First_Contact": "2017-10-15 16:30:54",
"Is_Prevalent": "0",
"Prevalence": "2736",
"Provider": "Enterprise reputation",
"Provider_ID": 3,
"Server_Version": "3.0.0.480",
"Trust_Level": 1
},
"GTI": {
"Create_Date": "2018-06-04 13:31:02",
"Original_Response": "2139160704",
"Provider": "Global Threat Intelligence (GTI)",
"Provider_ID": 1,
"Trust_Level": 99
},
"Hash": "7eb0139d2175739b3ccb0d1110067820be6abd29"
}
}
]
}
}
}
Human Readable Output
McAfee TIE Hash Reputations For f2c7bb8acc97f92e987a2d4087d021b1
| Created date | Provider (verbose) | Provider ID | Trust level | Trust level (verbose) |
|---|---|---|---|---|
| 2017-10-15 15:33:20 | Global Threat Intelligence (GTI) | 1 | 99 | KNOWN_TRUSTED |
| 2017-10-15 15:33:20 | Enterprise reputation | 3 | 85 | MOST_LIKELY_TRUSTED |
McAfee TIE Hash Reputations For 7eb0139d2175739b3ccb0d1110067820be6abd29
| Created date | Provider (verbose) | Provider ID | Trust level | Trust level (verbose) |
|---|---|---|---|---|
| 2017-10-15 16:30:54 | Enterprise reputation | 3 | 1 | KNOWN_MALICIOUS |
| 2018-06-04 13:31:02 | Global Threat Intelligence (GTI) | 1 | 99 | KNOWN_TRUSTED |
tie-set-file-reputation
Sets the “Enterprise” reputation (trust level, filename, and comment) of the specified hashes. Hashes that represent the same file can have a different “Enterprise” reputation if they are given different reputations. Permissions are required to invoke this method. See the instruction section.
Base Command
tie-set-file-reputation
Input
| Argument Name | Description | Required |
|---|---|---|
| file | Hashes of the files for which to set the reputation. Can be “MD5”, “SHA1”, or “SHA256”. | Required |
| trust_level | The new trust level for the files. Possible values are: NOT_SET, KNOWN_MALICIOUS, MOST_LIKELY_MALICIOUS, MIGHT_BE_MALICIOUS, UNKNOWN, MIGHT_BE_TRUSTED, MOST_LIKELY_TRUSTED, KNOWN_TRUSTED, KNOWN_TRUSTED_INSTALLER. | Required |
| filename | A file name to associate with the specified files. | Optional |
| comment | A comment to associate with the specified files. | Optional |
Context Output
There is no context output for this command.
Command Example
!tie-set-file-reputation file=f2c7bb8acc97f92e987a2d4087d021b1,7eb0139d2175739b3ccb0d1110067820be6abd29 trust_level=MOST_LIKELY_TRUSTED comment="For testing" filename="tesing.exe"
Human Readable Output
Successfully set files reputation.
tie-file-references
Retrieves the set of systems which have referenced (typically executed) the specified hashes.
Base Command
tie-file-references
Input
| Argument Name | Description | Required |
|---|---|---|
| file | Hashes of the files for which to search. Can be “MD5”, “SHA1”, or “SHA256”. | Required |
| query_limit | The maximum number of results to return. The default and maximum number is 500 results. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| File.Hashes.type | String | The type of the hash. |
| File.Hashes.value | String | The value of the hash. |
| File.MD5 | String | The MD5 hash of the file. |
| File.SHA1 | String | The SHA1 hash of the file. |
| File.SHA256 | String | The SHA256 hash of the file. |
| McAfee.TIE.FilesReferences.References.AgentGuid | String | The GUID of the system that referenced the file. |
| McAfee.TIE.FilesReferences.References.Date | String | The time the system first referenced the file (UTC timezone). |
| McAfee.TIE.FilesReferences.Hash | String | The value of the hash. |
Command Example
!tie-file-references file=f2c7bb8acc97f92e987a2d4087d021b1,7eb0139d2175739b3ccb0d1110067820be6abd29 query_limit=5
Context Example
{
"File": [
{
"Hashes": [
{
"type": "MD5",
"value": "f2c7bb8acc97f92e987a2d4087d021b1"
}
],
"MD5": "f2c7bb8acc97f92e987a2d4087d021b1"
},
{
"Hashes": [
{
"type": "SHA1",
"value": "7eb0139d2175739b3ccb0d1110067820be6abd29"
}
],
"SHA1": "7eb0139d2175739b3ccb0d1110067820be6abd29"
}
],
"McAfee": {
"TIE": {
"FilesReferences": [
{
"Hash": "f2c7bb8acc97f92e987a2d4087d021b1",
"References": [
{
"AgentGuid": "0c906be0-224c-45d4-8e6f-bc89da69d268",
"Date": "2017-10-15 15:33:20"
},
{
"AgentGuid": "70be2ee9-7166-413b-b03e-64a48f6ab6c8",
"Date": "2017-10-15 15:34:11"
},
{
"AgentGuid": "c21b8995-9c5a-412c-b727-c4284d42380a",
"Date": "2017-10-15 16:30:48"
},
{
"AgentGuid": "24e0e935-2241-47d7-822b-20dfe0fe86de",
"Date": "2017-10-15 16:30:49"
},
{
"AgentGuid": "e50a8b51-2063-42cb-a85f-10bd0a698323",
"Date": "2017-10-15 16:30:51"
}
]
},
{
"Hash": "7eb0139d2175739b3ccb0d1110067820be6abd29",
"References": [
{
"AgentGuid": "157eaf84-88ab-4d95-9456-30878fded9d5",
"Date": "2017-10-15 16:30:54"
},
{
"AgentGuid": "0bbcd439-aaed-4931-b9f4-b37e4a49b980",
"Date": "2017-10-16 13:28:43"
},
{
"AgentGuid": "f87fb2c3-2032-4fc5-a54f-7d36b441a122",
"Date": "2017-10-16 13:28:46"
},
{
"AgentGuid": "33b05a2e-6bb2-46c2-998f-893668c46402",
"Date": "2017-10-16 14:12:17"
},
{
"AgentGuid": "99ed15bb-ebc5-4b48-9a4d-5ad1b30abaac",
"Date": "2017-10-16 14:14:36"
}
]
}
]
}
}
}
Human Readable Output
References For Hash f2c7bb8acc97f92e987a2d4087d021b1
| AgentGuid | Date |
|---|---|
| 0c906be0-224c-45d4-8e6f-bc89da69d268 | 2017-10-15 15:33:20 |
| 70be2ee9-7166-413b-b03e-64a48f6ab6c8 | 2017-10-15 15:34:11 |
| c21b8995-9c5a-412c-b727-c4284d42380a | 2017-10-15 16:30:48 |
| 24e0e935-2241-47d7-822b-20dfe0fe86de | 2017-10-15 16:30:49 |
| e50a8b51-2063-42cb-a85f-10bd0a698323 | 2017-10-15 16:30:51 |
References For Hash 7eb0139d2175739b3ccb0d1110067820be6abd29
| AgentGuid | Date |
|---|---|
| 157eaf84-88ab-4d95-9456-30878fded9d5 | 2017-10-15 16:30:54 |
| 0bbcd439-aaed-4931-b9f4-b37e4a49b980 | 2017-10-16 13:28:43 |
| f87fb2c3-2032-4fc5-a54f-7d36b441a122 | 2017-10-16 13:28:46 |
| 33b05a2e-6bb2-46c2-998f-893668c46402 | 2017-10-16 14:12:17 |
| 99ed15bb-ebc5-4b48-9a4d-5ad1b30abaac | 2017-10-16 14:14:36 |
Breaking Changes
The following sections list the changes in this version.
- You can now pass more than one file to the following commands:
- tie-set-file-reputation
- tie-file-references
- Added additional context outputs to the following commands:
- file
- tie-file-references
Configuration parameters
broker_ca_bundle— Broker CA certificates (required)cert_file— Client certificates (required)private_key— Client private key (required)broker_urls— Broker URLs (required)integrationReliability— Source ReliabilityfeedExpirationPolicy—feedExpirationInterval—
Commands (3)
-
fileRetrieves the reputations for the specified hashes. Can be "MD5", "SHA1", or "SHA256".
-
tie-file-referencesRetrieves the set of systems which have referenced (typically executed) the specified hashes.
-
tie-set-file-reputationSets the “Enterprise” reputation (trust level, filename, and comment) of the specified hashes. Hashes that represent the same file can have a different "Enterprise" reputation if they are given different reputations. Permissions are required to invoke this method. See the 'How-to' in the instance instruction.
import abc import contextlib import tempfile from typing import NamedTuple from CommonServerPython import * from dxlclient.broker import Broker from dxlclient.client import DxlClient from dxlclient.client_config import DxlClientConfig from dxltieclient import TieClient from dxltieclient.constants import ( AtdAttrib, AtdTrustLevel, EnterpriseAttrib, FileEnterpriseAttrib, FileGtiAttrib, FileProvider, FileReputationProp, FirstRefProp, HashType, TrustLevel, ) VENDOR_NAME = "McAfee Threat Intelligence Exchange" OUTPUT_PREFIX = "McAfee.TIE" LOWEST_TRUST_LEVEL_KEY = "lowest_trust_level_key" LOWEST_SCORE_KEY = "lowest_score_key" MAX_QUERY_LIMIT = 500 class DXLConfigFiles(NamedTuple): broker_ca_bundle_file: str client_cert_file: str private_key_file: str broker_urls: list[str] class InstanceCertificates(NamedTuple): broker_ca_bundle: str client_cert: str private_key: str broker_urls: list[str] class ProviderInfo(NamedTuple): name: str abbreviation: str PROVIDER_INFO = { FileProvider.GTI: ProviderInfo(name="Global Threat Intelligence (GTI)", abbreviation="GTI"), FileProvider.ENTERPRISE: ProviderInfo(name="Enterprise reputation", abbreviation="Enterprise"), FileProvider.ATD: ProviderInfo(name="Advanced Threat Defense (ATD)", abbreviation="ATD"), FileProvider.MWG: ProviderInfo(name="Web Gateway (MWG)", abbreviation="MWG"), } TRUST_LEVELS = { TrustLevel.KNOWN_TRUSTED_INSTALLER: "KNOWN_TRUSTED_INSTALLER", TrustLevel.KNOWN_TRUSTED: "KNOWN_TRUSTED", TrustLevel.MOST_LIKELY_TRUSTED: "MOST_LIKELY_TRUSTED", TrustLevel.MIGHT_BE_TRUSTED: "MIGHT_BE_TRUSTED", TrustLevel.UNKNOWN: "UNKNOWN", TrustLevel.MIGHT_BE_MALICIOUS: "MIGHT_BE_MALICIOUS", TrustLevel.MOST_LIKELY_MALICIOUS: "MOST_LIKELY_MALICIOUS", TrustLevel.KNOWN_MALICIOUS: "KNOWN_MALICIOUS", TrustLevel.NOT_SET: "NOT_SET", } HASH_TYPE_KEYS = {"md5": HashType.MD5, "sha1": HashType.SHA1, "sha256": HashType.SHA256} class GeneralFileReputationParser(abc.ABC): """ This abstract class is in charge of parsing the reputations' data returned from the following API call: https://opendxl.github.io/opendxl-tie-client-python/pydoc/dxltieclient.client.html#dxltieclient.client.TieClient.get_file_reputation Since all reputations have two sections, one that it is unique to each vendor, and the second that it is mutual to all, this class provides a method to parse the mutual section, and an abstract method that each child class (representing a specific vendor) must implement to parse the unique section of each vendor. """ GENERAL_REPUTATION_KEYS = { FileReputationProp.PROVIDER_ID: "Provider", FileReputationProp.TRUST_LEVEL: "Trust_Level", FileReputationProp.CREATE_DATE: "Create_Date", } @staticmethod def init(provider: int): if provider == FileProvider.GTI: return GtiFileReputationParser() elif provider == FileProvider.ENTERPRISE: return EnterpriseFileReputationParser() elif provider == FileProvider.ATD: return AtdFileReputationParser() else: demisto.debug(f"Unexpected provider ID returned - {provider}") return UnknownReputationHandler() @abstractmethod # noqa: B027 def parse_attributes(self, attributes: Dict[str, Any]): """ The abstract method that is in charge of parsing the vendor's unique attributes. Each child class implementing this abstract method holds a dictionary that maps the data returned from the API (which are in numeric form) to humand readable data in order for the user to understand the returned results. """ def parse_reputation_key(self, reputation_key: str, val: Union[str, int]): """ This method is in charge of parsing the mutual section of the reputations by using the dictionary that is defined in the parent class (GeneralFileReputationParser). """ if reputation_key == FileReputationProp.PROVIDER_ID: return {self.GENERAL_REPUTATION_KEYS[reputation_key]: get_provider_name(provider_id=val)} elif reputation_key == FileReputationProp.CREATE_DATE: return {self.GENERAL_REPUTATION_KEYS[reputation_key]: epoch_to_localtime(int(val))} elif reputation_key in self.GENERAL_REPUTATION_KEYS: return {self.GENERAL_REPUTATION_KEYS[reputation_key]: val} else: return {reputation_key: val} def parse_data(self, reputation_data: Dict[str, Any]): """ This method is in charge of parsing the full reputation, it does so by parsing the vendror's unique attributes, and the mutual attributes of all vendors. """ parsed_res: Dict[str, Any] = {} for key, val in reputation_data.items(): if key == FileReputationProp.ATTRIBUTES: parsed_res |= self.parse_attributes(attributes=val) else: parsed_res |= self.parse_reputation_key(reputation_key=key, val=val) return parsed_res class GtiFileReputationParser(GeneralFileReputationParser): ATTRIBUTES_KEYS = { FileGtiAttrib.FIRST_CONTACT: "First_Contact", FileGtiAttrib.PREVALENCE: "Prevalence", FileGtiAttrib.ORIGINAL_RESPONSE: "Original_Response", } def parse_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]: parsed_res: Dict[str, Any] = {} for key, val in attributes.items(): if key == FileGtiAttrib.FIRST_CONTACT: parsed_res[self.ATTRIBUTES_KEYS[key]] = epoch_to_localtime(int(val)) elif key in self.ATTRIBUTES_KEYS: parsed_res[self.ATTRIBUTES_KEYS[key]] = val else: parsed_res[key] = val return parsed_res class EnterpriseFileReputationParser(GeneralFileReputationParser): ATTRIBUTES_KEYS = { FileEnterpriseAttrib.SERVER_VERSION: "Server_Version", FileEnterpriseAttrib.FIRST_CONTACT: "First_Contact", FileEnterpriseAttrib.PREVALENCE: "Prevalence", FileEnterpriseAttrib.ENTERPRISE_SIZE: "Enterprise_Size", FileEnterpriseAttrib.MIN_LOCAL_REP: "Min_Local_Rep", FileEnterpriseAttrib.MAX_LOCAL_REP: "Max_Local_Rep", FileEnterpriseAttrib.AVG_LOCAL_REP: "Avg_Local_Rep", FileEnterpriseAttrib.PARENT_MIN_LOCAL_REP: "Parent_Min_Local_Rep", FileEnterpriseAttrib.PARENT_MAX_LOCAL_REP: "Parent_Max_Local_Rep", FileEnterpriseAttrib.PARENT_AVG_LOCAL_REP: "Parent_Avg_Local_Rep", FileEnterpriseAttrib.FILE_NAME_COUNT: "File_Name_Count", FileEnterpriseAttrib.DETECTION_COUNT: "Detection_Count", FileEnterpriseAttrib.LAST_DETECTION_TIME: "Last_Detection_Time", FileEnterpriseAttrib.IS_PREVALENT: "Is_Prevalent", FileEnterpriseAttrib.CHILD_FILE_REPS: "Child_File_Reps", FileEnterpriseAttrib.PARENT_FILE_REPS: "Parent_File_Reps", } def parse_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]: parsed_res: Dict[str, Any] = {} for key, val in attributes.items(): if key == FileEnterpriseAttrib.FIRST_CONTACT or key == FileEnterpriseAttrib.LAST_DETECTION_TIME: parsed_res[self.ATTRIBUTES_KEYS[key]] = epoch_to_localtime(int(val)) elif key == FileEnterpriseAttrib.SERVER_VERSION: parsed_res[self.ATTRIBUTES_KEYS[key]] = EnterpriseAttrib.to_version_string(val) elif key == FileEnterpriseAttrib.CHILD_FILE_REPS or key == FileEnterpriseAttrib.PARENT_FILE_REPS: parsed_res[self.ATTRIBUTES_KEYS[key]] = val elif key in self.ATTRIBUTES_KEYS: parsed_res[self.ATTRIBUTES_KEYS[key]] = val else: parsed_res[key] = val return parsed_res class AtdFileReputationParser(GeneralFileReputationParser): ATTRIBUTES_KEYS = { AtdAttrib.GAM_SCORE: "GAM_Score", AtdAttrib.AV_ENGINE_SCORE: "AV_Engine_Score", AtdAttrib.SANDBOX_SCORE: "Sandbox_Score", AtdAttrib.VERDICT: "Verdict", AtdAttrib.BEHAVIORS: "Behaviors", } ATD_TRUST_LEVELS = { AtdTrustLevel.KNOWN_TRUSTED: "KNOWN_TRUSTED", AtdTrustLevel.MOST_LIKELY_TRUSTED: "MOST_LIKELY_TRUSTED", AtdTrustLevel.MIGHT_BE_TRUSTED: "MIGHT_BE_TRUSTED", AtdTrustLevel.UNKNOWN: "UNKNOWN", AtdTrustLevel.MIGHT_BE_MALICIOUS: "MIGHT_BE_MALICIOUS", AtdTrustLevel.MOST_LIKELY_MALICIOUS: "MOST_LIKELY_MALICIOUS", AtdTrustLevel.KNOWN_MALICIOUS: "KNOWN_MALICIOUS", AtdTrustLevel.NOT_SET: "NOT_SET", } def parse_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]: parsed_res: Dict[str, Any] = {} for key, val in attributes.items(): if key in self.ATTRIBUTES_KEYS: parsed_res[self.ATTRIBUTES_KEYS[key]] = val else: parsed_res[key] = val return parsed_res class UnknownReputationHandler(GeneralFileReputationParser): def parse_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]: return attributes def get_client_config(dxl_config_files: DXLConfigFiles) -> DxlClientConfig: config = DxlClientConfig( broker_ca_bundle=dxl_config_files.broker_ca_bundle_file, cert_file=dxl_config_files.client_cert_file, private_key=dxl_config_files.private_key_file, brokers=[Broker.parse(url) for url in dxl_config_files.broker_urls], ) config.connect_retries = 1 config.reconnect_delay = 1 config.reconnect_delay_max = 10 return config def get_provider_name(provider_id: Union[int, str]) -> str: provider_id_int = arg_to_number(provider_id) provider_info = PROVIDER_INFO.get(provider_id_int, None) if provider_info: return provider_info.name else: return str(provider_id) def get_provider_abbr(provider_id: Union[int, str]) -> str: provider_id_int = arg_to_number(provider_id) provider_info = PROVIDER_INFO.get(provider_id_int, None) if provider_info: return provider_info.abbreviation else: return str(provider_id) def epoch_to_localtime(epoch_time: int) -> str: try: date = datetime.fromtimestamp(epoch_time, tz=timezone.utc) except ValueError: date = datetime.fromtimestamp(epoch_time / 1000, tz=timezone.utc) return date.strftime("%Y-%m-%d %H:%M:%S") def parse_reputation_human_readable(reputation): trust_level = reputation.get(FileReputationProp.TRUST_LEVEL) verbose_trust_level = TRUST_LEVELS.get(trust_level, trust_level) provider_id = reputation.get(FileReputationProp.PROVIDER_ID) provider = get_provider_name(provider_id) create_date = reputation.get(FileReputationProp.CREATE_DATE) create_date_str = epoch_to_localtime(int(create_date)) res = { "Trust level": trust_level, "Trust level (verbose)": verbose_trust_level, "Provider ID": provider_id, "Provider (verbose)": provider, "Created date": create_date_str, } return res def parse_reference_human_readable(reference): agent_guid = reference.get(FirstRefProp.SYSTEM_GUID) date = reference.get(FirstRefProp.DATE) return { "Date": epoch_to_localtime(date), "AgentGuid": agent_guid.replace("{", "").replace("}", ""), # Remove brackets if exist } def reputations_to_human_readable(reputations): return [parse_reputation_human_readable(rep) for rep in reputations] def references_to_human_readable(references): return [parse_reference_human_readable(ref) for ref in references] def trust_level_to_score(trust_level): if trust_level >= TrustLevel.MIGHT_BE_TRUSTED: return Common.DBotScore.GOOD elif trust_level == TrustLevel.MIGHT_BE_MALICIOUS: return Common.DBotScore.SUSPICIOUS elif trust_level == TrustLevel.NOT_SET or trust_level == TrustLevel.UNKNOWN: return Common.DBotScore.NONE elif trust_level < TrustLevel.MIGHT_BE_MALICIOUS: return Common.DBotScore.BAD else: # Shouldn't reach here, as the API doesn't support 31-69 values except for 50) return Common.DBotScore.NONE def test_module(dxl_client: DxlClient): """Tests if there is a connection with DxlClient(which is used for connection with McAfee TIE, instead of the Client class)""" dxl_client.connect() return "ok" def safe_get_file_reputation(tie_client: TieClient, api_input: Dict[str, str]): try: res = tie_client.get_file_reputation(api_input) except Exception as e: demisto.info(f"McAfee failed to get file reputation with error: {e!s}") return None return res def get_hash_type_key(file_hash: str): hash_type = get_hash_type(file_hash) hash_type_key = HASH_TYPE_KEYS.get(hash_type, None) if not hash_type_key: raise DemistoException(f"Invalid value, {file_hash} is not a valid SHA1, SHA256 or MD5 value.") return hash_type_key def get_file_instance(dbot_score: Union[Common.DBotScore, None], file_hash: str, hash_type_key: str) -> Common.File: return Common.File( dbot_score=dbot_score, md5=file_hash if hash_type_key == HashType.MD5 else None, sha1=file_hash if hash_type_key == HashType.SHA1 else None, sha256=file_hash if hash_type_key == HashType.SHA256 else None, ) def parse_reputation(provider_id: int, reputation: Dict): file_reputation_parser = GeneralFileReputationParser.init(provider=provider_id) parsed_reputation = file_reputation_parser.parse_data(reputation_data=reputation) parsed_reputation["Provider_ID"] = provider_id return parsed_reputation def parse_file_reputation_raw_result(raw_result: Dict, file_hash: str, reliability: str, hash_type_key: str): context_data = {} parsed_reputation_data = {} # Since the range of trust levels is [0,1,...,100], we want to get the minimum trust level # that is not 0, therefore we define a variable that is larger than the maximum in the predefined range # and iterate in order to retrieve the minimum, if our minimum was not changed, that means all the trust levels # are zero. max_num = TrustLevel.KNOWN_TRUSTED_INSTALLER + 1 # More than the maximum possible trust level lowest_trust_level = max_num reputations = raw_result.values() for reputation in reputations: # Parse the raw result of each reputation result provider_id = reputation[FileReputationProp.PROVIDER_ID] parsed_reputation_data[get_provider_abbr(provider_id=provider_id)] = parse_reputation( provider_id=provider_id, reputation=reputation ) # Get the vendor's data with the lowest score rep_trust_level = reputation.get(FileReputationProp.TRUST_LEVEL, TrustLevel.NOT_SET) if rep_trust_level != TrustLevel.NOT_SET and rep_trust_level < lowest_trust_level: lowest_trust_level = rep_trust_level if lowest_trust_level == max_num: lowest_tl_score = {LOWEST_TRUST_LEVEL_KEY: TrustLevel.NOT_SET, LOWEST_SCORE_KEY: Common.DBotScore.NONE} else: lowest_tl_score = {LOWEST_TRUST_LEVEL_KEY: lowest_trust_level, LOWEST_SCORE_KEY: trust_level_to_score(lowest_trust_level)} dbot_score = Common.DBotScore( indicator=file_hash, indicator_type=DBotScoreType.FILE, reliability=reliability, score=lowest_tl_score[LOWEST_SCORE_KEY], ) file_instance = get_file_instance(dbot_score=dbot_score, file_hash=file_hash, hash_type_key=hash_type_key) if lowest_tl_score[LOWEST_SCORE_KEY] >= Common.DBotScore.SUSPICIOUS: dbot_score.malicious_description = f"Trust level is {lowest_tl_score[LOWEST_TRUST_LEVEL_KEY]!s}" context_data = {"Reputations": {"Hash": file_hash}} context_data["Reputations"] |= parsed_reputation_data table = reputations_to_human_readable(reputations) return CommandResults( readable_output=tableToMarkdown(f"McAfee TIE Hash Reputations For {file_hash}:", table), raw_response=raw_result, outputs_prefix=f"{OUTPUT_PREFIX}.FilesReputations", outputs=context_data, indicator=file_instance, ) def files_reputations_command(hashes: List[str], tie_client: TieClient, reliability: str) -> List[CommandResults]: command_results: List[CommandResults] = [] for file_hash in hashes: hash_type_key = get_hash_type_key(file_hash=file_hash) api_input = {hash_type_key: file_hash} raw_result = safe_get_file_reputation(tie_client, api_input) if not raw_result: dbot_score = Common.DBotScore( indicator=file_hash, indicator_type=DBotScoreType.FILE, reliability=reliability, score=Common.DBotScore.NONE, ) file_instance = get_file_instance(dbot_score=dbot_score, file_hash=file_hash, hash_type_key=hash_type_key) command_result = CommandResults( readable_output=f"McAfee TIE Hash Reputation For {file_hash} was not found", indicator=file_instance, ) else: command_result = parse_file_reputation_raw_result( raw_result=raw_result, file_hash=file_hash, reliability=reliability, hash_type_key=hash_type_key, ) command_results.append(command_result) return command_results def files_references_command(hashes: List[str], tie_client: TieClient, query_limit: int) -> List[CommandResults]: if query_limit > MAX_QUERY_LIMIT: raise DemistoException(f"Query limit must not exceed {MAX_QUERY_LIMIT}") elif query_limit <= 0: raise DemistoException("Query limit must not be zero or negative") command_results: List[CommandResults] = [] for file_hash in hashes: hash_type_key = get_hash_type_key(file_hash=file_hash) api_input = {hash_type_key: file_hash} raw_result = tie_client.get_file_first_references(api_input, query_limit=query_limit) table = references_to_human_readable(raw_result) file_instance = get_file_instance(dbot_score=None, file_hash=file_hash, hash_type_key=hash_type_key) if not raw_result: command_result = CommandResults( readable_output=f"McAfee TIE Hash Reference For {file_hash} was not found", indicator=file_instance, ) else: context_data = {"Hash": file_hash} context_data["References"] = table command_result = CommandResults( readable_output=tableToMarkdown(f"References For Hash {file_hash}:", table), raw_response=raw_result, outputs_prefix=f"{OUTPUT_PREFIX}.FilesReferences", indicator=file_instance, outputs=context_data, ) command_results.append(command_result) return command_results def get_trust_level_key(trust_level: str): trust_level_key = [key for (key, val) in TRUST_LEVELS.items() if val == trust_level] if not trust_level_key: raise DemistoException(f"Illegal argument trust_level {trust_level}. Choose value from predefined values") else: return trust_level_key[0] def set_files_reputation_command(hashes: List[str], tie_client: TieClient, trust_level: str, filename: str, comment: str): # Find trust_level key trust_level_key = get_trust_level_key(trust_level=trust_level) for file_hash in hashes: hash_type_key = get_hash_type_key(file_hash=file_hash) api_input = {hash_type_key: file_hash} tie_client.set_file_reputation(trust_level=trust_level_key, hashes=api_input, filename=filename, comment=comment) return CommandResults(readable_output="Successfully set files reputation") def create_temp_credentials(temp_file: tempfile._TemporaryFileWrapper, data_to_write: str): temp_file.write(data_to_write) temp_file.seek(0) @contextlib.contextmanager def create_dxl_config(instance_cert: InstanceCertificates) -> DxlClientConfig: with ( tempfile.NamedTemporaryFile(mode="w+", dir="./", suffix=".crt") as broker_certs_file, tempfile.NamedTemporaryFile(mode="w+", dir="./", suffix=".crt") as client_cert_file, tempfile.NamedTemporaryFile(mode="w+", dir="./", suffix=".key") as private_key_file, ): demisto.debug("McAfeeTIEV2: created temp files for broker CA bundle, client cert, and private key") create_temp_credentials(broker_certs_file, instance_cert.broker_ca_bundle) create_temp_credentials(client_cert_file, instance_cert.client_cert) create_temp_credentials(private_key_file, instance_cert.private_key) dxl_config_files = DXLConfigFiles( broker_ca_bundle_file=broker_certs_file.name, client_cert_file=client_cert_file.name, private_key_file=private_key_file.name, broker_urls=instance_cert.broker_urls, ) demisto.debug( f"McAfeeTIEV2: wrote credentials to temp files, building DXL client config " f"for brokers {instance_cert.broker_urls}" ) yield get_client_config(dxl_config_files=dxl_config_files) @contextlib.contextmanager def create_dxl_client(instance_cert: InstanceCertificates): with create_dxl_config(instance_cert=instance_cert) as dxl_client_config: dxl_client_cm = DxlClient(dxl_client_config) with dxl_client_cm as dxl_client: yield dxl_client def get_tie_client(dxl_client: DxlClient): dxl_client.connect() # We need to connect to the DXL fabric in order to create a TIE Client instance return TieClient(dxl_client) def get_instance_certificates(params: Dict[str, str]) -> InstanceCertificates: return InstanceCertificates( broker_ca_bundle=params["broker_ca_bundle"], client_cert=params["cert_file"], private_key=params["private_key"], broker_urls=params["broker_urls"].split(","), ) def files_reputations(dxl_client: DxlClient, hashes: List[str], reliability: str) -> List[CommandResults]: tie_client = get_tie_client(dxl_client) return files_reputations_command(hashes=hashes, tie_client=tie_client, reliability=reliability) def files_references(dxl_client: DxlClient, hashes: List[str], args_query_limit: Union[int, None]) -> List[CommandResults]: tie_client = get_tie_client(dxl_client) query_limit = args_query_limit if args_query_limit else MAX_QUERY_LIMIT return files_references_command( hashes=hashes, tie_client=tie_client, query_limit=query_limit, ) def set_files_reputation( dxl_client: DxlClient, hashes: List[str], trust_level: str, filename: str, comment: str ) -> CommandResults: tie_client = get_tie_client(dxl_client) return set_files_reputation_command( hashes=hashes, tie_client=tie_client, trust_level=trust_level, filename=filename, comment=comment, ) def main(): # pragma: no cover try: command = demisto.command() args = demisto.args() params = demisto.params() instance_cert = get_instance_certificates(params=params) reliability = DBotScoreReliability.get_dbot_score_reliability_from_str( demisto.params().get("integrationReliability", "C - Fairly reliable") ) hashes = argToList(args.get("file")) demisto.debug(f"Command being called is {command}") with create_dxl_client(instance_cert=instance_cert) as dxl_client: # We must configure the DxlClient before trying to connect, which is why # we wrapped the following code with a "with" statement according to the DxlClient Docs. # Only after successfully configuring, can we try to connect using dxl_client.connect # If a configuration error is returned from the configuration phase, it will be caught before trying to connect. if command == "test-module": # This is the call made when clicking the integration Test button. return_results(test_module(dxl_client=dxl_client)) elif command == "file": return_results(files_reputations(dxl_client=dxl_client, hashes=hashes, reliability=reliability)) elif command == "tie-file-references": return_results( files_references( dxl_client=dxl_client, hashes=hashes, args_query_limit=arg_to_number(args.get("query_limit", None)) ) ) elif command == "tie-set-file-reputation": return_results( set_files_reputation( dxl_client=dxl_client, hashes=hashes, trust_level=args.get("trust_level"), filename=args.get("filename", ""), comment=args.get("comment", ""), ) ) else: raise NotImplementedError(f"Command {command} is not supported.") except Exception as e: demisto.error(traceback.format_exc()) # print the traceback exception_des = str(e) if "4044" in exception_des: return_error("Invalid value - Client certificates") elif "4293" in exception_des: return_error("Invalid value - Broker CA certificates") elif "4065" in exception_des: return_error("Invalid value - Client private key") else: return_error(f"Failed to execute {command} command.\nError:\n{e!s}") if __name__ in ["__main__", "__builtin__", "builtins"]: main()