From df6f662ac02c68fc31cebabbcf0973701f1a49cf Mon Sep 17 00:00:00 2001 From: Menachem Weinfeld <90556466+mmhw@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:48:46 +0300 Subject: [PATCH 1/3] Fix autopep8 errors (#30346) --- .../AWS_SecurityHub/AWS_SecurityHub.py | 2 +- .../AWS_SecurityHub/AWS_SecurityHub.yml | 14 +- Packs/AWS-SecurityHub/ReleaseNotes/1_3_15.md | 6 + Packs/AWS-SecurityHub/pack_metadata.json | 2 +- .../ReleaseNotes/1_1_1.md | 6 + .../Scripts/ExtFilter/ExtFilter.py | 2 +- .../Scripts/ExtFilter/ExtFilter.yml | 10 +- .../CommunityCommonScripts/pack_metadata.json | 2 +- .../Integrations/ConcentricAI/ConcentricAI.py | 2 +- .../ConcentricAI/ConcentricAI.yml | 22 +- Packs/ConcentricAI/ReleaseNotes/1_2_9.md | 6 + Packs/ConcentricAI/pack_metadata.json | 4 +- .../Integrations/Cybereason/Cybereason.py | 8 +- .../Integrations/Cybereason/Cybereason.yml | 354 +++++++++--------- Packs/Cybereason/ReleaseNotes/2_1_13.md | 6 + Packs/Cybereason/pack_metadata.json | 2 +- .../EmailCommunication/ReleaseNotes/2_0_13.md | 6 + .../Scripts/SendEmailReply/SendEmailReply.py | 4 +- .../Scripts/SendEmailReply/SendEmailReply.yml | 10 +- Packs/EmailCommunication/pack_metadata.json | 2 +- .../Integrations/McAfeeTIEV2/McAfeeTIEV2.py | 6 +- .../Integrations/McAfeeTIEV2/McAfeeTIEV2.yml | 2 +- Packs/McAfee-TIE/ReleaseNotes/2_0_15.md | 6 + Packs/McAfee-TIE/pack_metadata.json | 2 +- 24 files changed, 261 insertions(+), 225 deletions(-) create mode 100644 Packs/AWS-SecurityHub/ReleaseNotes/1_3_15.md create mode 100644 Packs/CommunityCommonScripts/ReleaseNotes/1_1_1.md create mode 100644 Packs/ConcentricAI/ReleaseNotes/1_2_9.md create mode 100644 Packs/Cybereason/ReleaseNotes/2_1_13.md create mode 100644 Packs/EmailCommunication/ReleaseNotes/2_0_13.md create mode 100644 Packs/McAfee-TIE/ReleaseNotes/2_0_15.md diff --git a/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.py b/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.py index 2350707c6e34..5fa06ff81281 100644 --- a/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.py +++ b/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.py @@ -549,7 +549,7 @@ def parse_filter_field(string_filters) -> dict: try: filters_list = string_filters.split(';') filters = {split_str[0].split('=')[1]: [{'Value': split_str[1].split('=')[1], - 'Comparison':split_str[2].split('=')[1].upper()}] + 'Comparison': split_str[2].split('=')[1].upper()}] for split_str in [filter_str.split(',') for filter_str in filters_list]} except Exception: demisto.error(f'Failed parsing filters: {string_filters}\n error: {Exception}') diff --git a/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.yml b/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.yml index 086f4d338972..cdd20390074c 100644 --- a/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.yml +++ b/Packs/AWS-SecurityHub/Integrations/AWS_SecurityHub/AWS_SecurityHub.yml @@ -236,7 +236,7 @@ script: - description: The identifier of the finding that was specified by the finding. Can be retrieved using the 'aws-securityhub-get-findings' command provider. name: finding_identifiers_id required: true - - description: The ARN generated by Security Hub that uniquely identifies a product that generates findings. This can be the ARN for a third-party product that is integrated with Security Hub, or the ARN for a custom integration. Can be retrieved using the 'aws-securityhub-get-findings' command + - description: The ARN generated by Security Hub that uniquely identifies a product that generates findings. This can be the ARN for a third-party product that is integrated with Security Hub, or the ARN for a custom integration. Can be retrieved using the 'aws-securityhub-get-findings' command. name: finding_identifiers_product_arn required: true - description: The updated note text. @@ -260,7 +260,7 @@ script: - TRUE_POSITIVE - FALSE_POSITIVE - BENIGN_POSITIVE - - description: "One or more finding types in the format of namespace/category/classifier that classify a finding. Valid namespace values are as follows. * Software and Configuration Checks * TTPs * Effects * Unusual Behaviors * Sensitive Data Identifications" + - description: "One or more finding types in the format of namespace/category/classifier that classify a finding. Valid namespace values are as follows. * Software and Configuration Checks * TTPs * Effects * Unusual Behaviors * Sensitive Data Identifications." name: types - description: A list of name/value string pairs associated with the finding. These are custom, user-defined fields added to a finding. name: user_defined_fields @@ -308,7 +308,7 @@ script: name: roleSessionDuration - description: Override arguments and send a formatted JSON file. name: raw_json - - description: 'List of Tags separated by Key Value. For example: "key=key1,value=value1;key=key2,value=value2"' + - description: 'List of Tags separated by Key Value. For example: "key=key1,value=value1;key=key2,value=value2".' name: tags description: Enables Security Hub for your account in the current Region or the Region you specify in the request. Enabling Security Hub also enables the CIS AWS Foundations standard. When you enable Security Hub, you grant to Security Hub the permissions necessary to gather findings from AWS Config, Amazon GuardDuty, Amazon Inspector, and Amazon Macie. To learn more, see Setting Up AWS Security Hub. name: aws-securityhub-enable-security-hub @@ -326,7 +326,7 @@ script: - description: The string filter value. name: product_arn_value - auto: PREDEFINED - description: The condition to be applied to a string value when querying for findings + description: The condition to be applied to a string value when querying for findings. name: product_arn_comparison predefined: - EQUALS @@ -875,7 +875,7 @@ script: description: The AWS account ID that a finding is generated in. type: string - contextPath: AWS-SecurityHub.Findings.Types - description: 'One or more finding types in the format of namespace/category/classifier that classify a finding. Valid namespace values are as follows. Software and Configuration Checks, TTPs, Effects, Unusual Behaviors, Sensitive Data Identifications' + description: 'One or more finding types in the format of namespace/category/classifier that classify a finding. Valid namespace values are as follows. Software and Configuration Checks, TTPs, Effects, Unusual Behaviors, Sensitive Data Identifications.' type: Unknown - contextPath: AWS-SecurityHub.Findings.FirstObservedAt description: An ISO8601-formatted timestamp that indicates when the security-findings provider first observed the potential security issue that a finding captured. @@ -1476,7 +1476,7 @@ script: - description: Override arguments and send a formatted JSON file. name: raw_json - auto: PREDEFINED - description:

Specifies which member accounts the response includes based on their relationship status with the master account. The default value is TRUE. If onlyAssociated is set to TRUE, the response includes member accounts whose relationship status with the master is set to ENABLED or DISABLED. If onlyAssociated is set to FALSE, the response includes all existing member accounts.

+ description:

Specifies which member accounts the response includes based on their relationship status with the master account. The default value is TRUE. If onlyAssociated is set to TRUE, the response includes member accounts whose relationship status with the master is set to ENABLED or DISABLED. If onlyAssociated is set to FALSE, the response includes all existing member accounts.

. name: only_associated predefined: - 'True' @@ -2068,7 +2068,7 @@ script: description: The UTC timestamp in seconds since the last update. The incident is only updated if it was modified after the last update time. - name: get-mapping-fields description: Returns the list of fields to map in outgoing mirroring. This command is only used for debugging purposes. - dockerimage: demisto/boto3py3:1.0.0.72851 + dockerimage: demisto/boto3py3:1.0.0.79189 isfetch: true ismappable: true isremotesyncin: true diff --git a/Packs/AWS-SecurityHub/ReleaseNotes/1_3_15.md b/Packs/AWS-SecurityHub/ReleaseNotes/1_3_15.md new file mode 100644 index 000000000000..393a6da84131 --- /dev/null +++ b/Packs/AWS-SecurityHub/ReleaseNotes/1_3_15.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### AWS - Security Hub + +- Updated the Docker image to: *demisto/boto3py3:1.0.0.79189*. diff --git a/Packs/AWS-SecurityHub/pack_metadata.json b/Packs/AWS-SecurityHub/pack_metadata.json index 29c4fce7fb00..a771828d3081 100644 --- a/Packs/AWS-SecurityHub/pack_metadata.json +++ b/Packs/AWS-SecurityHub/pack_metadata.json @@ -2,7 +2,7 @@ "name": "AWS - Security Hub", "description": "Amazon Web Services Security Hub Service.", "support": "xsoar", - "currentVersion": "1.3.14", + "currentVersion": "1.3.15", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CommunityCommonScripts/ReleaseNotes/1_1_1.md b/Packs/CommunityCommonScripts/ReleaseNotes/1_1_1.md new file mode 100644 index 000000000000..43ec6eaf0559 --- /dev/null +++ b/Packs/CommunityCommonScripts/ReleaseNotes/1_1_1.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### ExtFilter + +- Updated the Docker image to: *demisto/python3:3.10.13.78960*. diff --git a/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.py b/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.py index d6e64db1a2f0..67c3d25aa5af 100644 --- a/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.py +++ b/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.py @@ -936,7 +936,7 @@ def filter_with_expressions(self, r, conds, path, True) for r in root] if v]) elif not isinstance(root, dict): return None - (parent, parent_path),\ + (parent, parent_path), \ (child, child_name) = get_parent_child(root, path) for x in self.__conds_items(conds, root): diff --git a/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.yml b/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.yml index 794458f1552b..34aefffda3c0 100644 --- a/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.yml +++ b/Packs/CommunityCommonScripts/Scripts/ExtFilter/ExtFilter.yml @@ -17,10 +17,10 @@ system: true args: - name: value required: true - description: Value to be filtered + description: Value to be filtered. isArray: true - name: path - description: Context Path to which to filter + description: Context Path to which to filter. - name: operation required: true auto: PREDEFINED @@ -149,11 +149,11 @@ args: - 'wildcard: matches caseless' - is individually transformed with - is collectively transformed with - description: 'Filter Operation: value is filtered by,is filtered by,keeps,doesn''t keep,is,isn''t,equals,doesn''t equal,greater or equal,greater than,less or equal,less than,in range,starts with,starts with caseless,doesn''t start with,doesn''t start with caseless,email-header: decode,ends with,ends with caseless,doesn''t end with,doesn''t end with caseless,includes,includes caseless,doesn''t include,doesn''t include caseless,finds,finds caseless,doesn''t find,doesn''t find caseless,matches,matches caseless,doesn''t match,doesn''t match caseless,matches wildcard,matches caseless wildcard,doesn''t match wildcard,doesn''t match caseless wildcard,matches regex,matches caseless regex,doesn''t match regex,doesn''t match caseless regex,in list,in caseless list,not in list,not in caseless list,contains,contains caseless,doesn''t contain,doesn''t contain caseless,contains any match with wildcard,contains any match with caseless wildcard,doesn''t contain any match with wildcard,doesn''t contain any match with caseless wildcard,contains any match with regex,contains any match with caseless regex,doesn''t contain any match with regex,doesn''t contain any match with caseless regex,matches wildcard,matches caseless wildcard,doesn''t match wildcard,doesn''t match caseless wildcard,matches regex,matches caseless regex,doesn''t match regex,doesn''t match caseless regex,matches any string of,matches any caseless string of,doesn''t match any string of,doesn''t match any caseless string of,,matches any line of,,matches any caseless line of,,doesn''t match any line of,,doesn''t match any caseless line of,matches any wildcard of,matches any caseless wildcard of,doesn''t match any wildcard of,doesn''t match any caseless wildcard of,matches any regex of,matches any caseless regex of,doesn''t match any regex of,doesn''t match any caseless regex of,matches conditions of,matches custom conditions of,value matches conditions of,value matches custom conditions of,===,!==,==,!=,>=,>,<=,<' + description: 'Filter Operation: value is filtered by,is filtered by,keeps,doesn''t keep,is,isn''t,equals,doesn''t equal,greater or equal,greater than,less or equal,less than,in range,starts with,starts with caseless,doesn''t start with,doesn''t start with caseless,email-header: decode,ends with,ends with caseless,doesn''t end with,doesn''t end with caseless,includes,includes caseless,doesn''t include,doesn''t include caseless,finds,finds caseless,doesn''t find,doesn''t find caseless,matches,matches caseless,doesn''t match,doesn''t match caseless,matches wildcard,matches caseless wildcard,doesn''t match wildcard,doesn''t match caseless wildcard,matches regex,matches caseless regex,doesn''t match regex,doesn''t match caseless regex,in list,in caseless list,not in list,not in caseless list,contains,contains caseless,doesn''t contain,doesn''t contain caseless,contains any match with wildcard,contains any match with caseless wildcard,doesn''t contain any match with wildcard,doesn''t contain any match with caseless wildcard,contains any match with regex,contains any match with caseless regex,doesn''t contain any match with regex,doesn''t contain any match with caseless regex,matches wildcard,matches caseless wildcard,doesn''t match wildcard,doesn''t match caseless wildcard,matches regex,matches caseless regex,doesn''t match regex,doesn''t match caseless regex,matches any string of,matches any caseless string of,doesn''t match any string of,doesn''t match any caseless string of,,matches any line of,,matches any caseless line of,,doesn''t match any line of,,doesn''t match any caseless line of,matches any wildcard of,matches any caseless wildcard of,doesn''t match any wildcard of,doesn''t match any caseless wildcard of,matches any regex of,matches any caseless regex of,doesn''t match any regex of,doesn''t match any caseless regex of,matches conditions of,matches custom conditions of,value matches conditions of,value matches custom conditions of,===,!==,==,!=,>=,>,<=,<.' isArray: true - name: filter required: true - description: Filter Value + description: Filter Value. - name: ctx_demisto description: '`demisto` context: Input . (single dot) on `From previous tasks` to enable to extract the context data.' - name: ctx_inputs @@ -164,7 +164,7 @@ args: description: '`demisto` context: Input ''incident'' (no quotation) on `From previous tasks` to enable ${incident.} expression in DT.' scripttarget: 0 subtype: python3 -dockerimage: demisto/python3:3.10.12.63474 +dockerimage: demisto/python3:3.10.13.78960 runas: DBotWeakRole fromversion: 5.0.0 tests: diff --git a/Packs/CommunityCommonScripts/pack_metadata.json b/Packs/CommunityCommonScripts/pack_metadata.json index 5ebc49e22d03..e8c8ea9afb98 100644 --- a/Packs/CommunityCommonScripts/pack_metadata.json +++ b/Packs/CommunityCommonScripts/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Community Common Scripts", "description": "A pack that contains community scripts", "support": "community", - "currentVersion": "1.1.0", + "currentVersion": "1.1.1", "author": "", "url": "https://live.paloaltonetworks.com/t5/cortex-xsoar-discussions/bd-p/Cortex_XSOAR_Discussions", "email": "", diff --git a/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.py b/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.py index 561c0a7943ac..52efa2bd52c7 100644 --- a/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.py +++ b/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.py @@ -77,7 +77,7 @@ def initialise_scrolls_and_rules(): def initialize_global_values(): - global URL, MAX_INCIDENTS_TO_FETCH, COOKIE, AUTH_HEADERS,\ + global URL, MAX_INCIDENTS_TO_FETCH, COOKIE, AUTH_HEADERS, \ CLIENT_ID, CLIENT_SECRET, AUTH_HEADERS, DOMAIN, AUTHORIZATION CLIENT_ID = demisto.getParam('client_id') diff --git a/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.yml b/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.yml index efd1c5dec59d..4248dfe15ebd 100644 --- a/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.yml +++ b/Packs/ConcentricAI/Integrations/ConcentricAI/ConcentricAI.yml @@ -61,13 +61,13 @@ name: ConcentricAI script: commands: - arguments: - - description: Path of the file + - description: Path of the file. name: path required: true - - description: Name of File + - description: Name of File. name: file-name required: true - description: Get's file information + description: Get's file information. name: concentricai-get-file-details outputs: - contextPath: ConcentricAI.FileInfo.risk_names @@ -77,29 +77,29 @@ script: description: owner Details. type: String - contextPath: ConcentricAI.FileInfo.pii - description: PII present in file or not + description: PII present in file or not. type: String - contextPath: ConcentricAI.FileInfo.cid - description: File ID + description: File ID. type: String - arguments: - default: true defaultValue: '50' description: Maximum no. of users fetched per category. name: max_users - description: Get overview of Users involved + description: Get overview of Users involved. name: concentricai-get-users-overview - arguments: - - description: Enter user name + - description: Enter user name. name: user required: true - description: Get's user details + description: Get's user details. name: concentricai-get-user-details - arguments: - - description: File ID + - description: File ID. name: cid required: true - description: Get's file sharing details + description: Get's file sharing details. name: concentricai-get-file-sharing-details outputs: - contextPath: ConcentricAI.FileSharingInfo.type @@ -108,7 +108,7 @@ script: - contextPath: ConcentricAI.FileSharingInfo.user_name description: User name. type: Array - dockerimage: demisto/python3:3.10.12.68714 + dockerimage: demisto/python3:3.10.13.78960 isfetch: true runonce: false script: '-' diff --git a/Packs/ConcentricAI/ReleaseNotes/1_2_9.md b/Packs/ConcentricAI/ReleaseNotes/1_2_9.md new file mode 100644 index 000000000000..62a5db65458d --- /dev/null +++ b/Packs/ConcentricAI/ReleaseNotes/1_2_9.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### ConcentricAI + +- Updated the Docker image to: *demisto/python3:3.10.13.78960*. diff --git a/Packs/ConcentricAI/pack_metadata.json b/Packs/ConcentricAI/pack_metadata.json index f0e710222baa..cac638f94c5f 100644 --- a/Packs/ConcentricAI/pack_metadata.json +++ b/Packs/ConcentricAI/pack_metadata.json @@ -1,8 +1,8 @@ { "name": "ConcentricAI", - "description": "Plugin for Concentric.ai Concentric\u2019s Semantic Intelligence\u2122 solution discovers and protects business critical, unstructured data.\nWe use deep learning to identify risky sharing, inappropriate third party access, assets in the wrong location, \nmis-classified documents, or lateral movement of data \u2013 all without rules or complex upfront configuration.", + "description": "Plugin for Concentric.ai Concentric’s Semantic Intelligence™ solution discovers and protects business critical, unstructured data.\nWe use deep learning to identify risky sharing, inappropriate third party access, assets in the wrong location, \nmis-classified documents, or lateral movement of data – all without rules or complex upfront configuration.", "support": "partner", - "currentVersion": "1.2.8", + "currentVersion": "1.2.9", "author": "Shams Hasan Rizvi", "url": "https://concentric.ai", "email": "shams@concentric.ai", diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py index 90ff8e99acc0..5f21be9752e3 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.py +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.py @@ -666,7 +666,7 @@ def malop_processes_command(client: Client, args: dict): raise DemistoException("dateTime could not be parsed. Please enter a valid time parameter.") date_time_parser = date_time_parser.timestamp() milliseconds = int(date_time_parser * 1000) - filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult":True}] + filter_input = [{"facetName": "creationTime", "filterType": "GreaterThan", "values": [milliseconds], "isResult": True}] if isinstance(malop_guids, str): malop_guids = malop_guids.split(',') @@ -1620,8 +1620,8 @@ def fetch_malop_processes(client: Client, malop_id: str) -> list: { "requestedType": "MalopProcess", "filters": [], - "guidList":[malop_id], - "connectionFeature":{ + "guidList": [malop_id], + "connectionFeature": { "elementInstanceType": "MalopProcess", "featureName": "suspects" } @@ -1629,7 +1629,7 @@ def fetch_malop_processes(client: Client, malop_id: str) -> list: { "requestedType": "Process", "filters": [], - "isResult":True + "isResult": True } ], "totalResultLimit": 1000, diff --git a/Packs/Cybereason/Integrations/Cybereason/Cybereason.yml b/Packs/Cybereason/Integrations/Cybereason/Cybereason.yml index 5a55fe3edd94..a4dbc7aced49 100644 --- a/Packs/Cybereason/Integrations/Cybereason/Cybereason.yml +++ b/Packs/Cybereason/Integrations/Cybereason/Cybereason.yml @@ -108,31 +108,31 @@ script: - 'true' - 'false' - auto: PREDEFINED - description: If process has external connection + description: If process has external connection. name: hasExternalConnection predefined: - 'true' - 'false' - auto: PREDEFINED - description: If process is not known to reputation services and its image file is unsigned + description: If process is not known to reputation services and its image file is unsigned. name: unsignedUnknownReputation predefined: - 'true' - 'false' - auto: PREDEFINED - description: If process is running from temporary folder + description: If process is running from temporary folder. name: fromTemporaryFolder predefined: - 'true' - 'false' - auto: PREDEFINED - description: If process was identified elevating its privileges to local system user + description: If process was identified elevating its privileges to local system user. name: privilegesEscalation predefined: - 'true' - 'false' - auto: PREDEFINED - description: If the process was executed by PsExec service and is suspicious as being executed maliciously + description: If the process was executed by PsExec service and is suspicious as being executed maliciously. name: maliciousPsExec predefined: - 'true' @@ -141,65 +141,65 @@ script: name: cybereason-query-processes outputs: - contextPath: Cybereason.Process.Name - description: The process name + description: The process name. type: Unknown - contextPath: Cybereason.Process.Malicious - description: Malicious status of the process + description: Malicious status of the process. type: Unknown - contextPath: Cybereason.Process.CreationTime - description: The process creation time + description: The process creation time. type: Unknown - contextPath: Cybereason.Process.EndTime - description: The process end time + description: The process end time. type: Unknown - contextPath: Cybereason.Process.CommandLine - description: The command line of the process + description: The command line of the process. type: Unknown - contextPath: Cybereason.Process.SignedAndVerified - description: Is the process signed and verified + description: Is the process signed and verified. type: Unknown - contextPath: Cybereason.Process.ProductType - description: The product type + description: The product type. type: Unknown - contextPath: Cybereason.Process.Children - description: Children of the process + description: Children of the process. type: Unknown - contextPath: Cybereason.Process.Parent - description: The parent process + description: The parent process. type: Unknown - contextPath: Cybereason.Process.OwnerMachine - description: The machine's hostname + description: The machine's hostname. type: Unknown - contextPath: Cybereason.Process.User - description: The user who ran the process + description: The user who ran the process. type: Unknown - contextPath: Cybereason.Process.ImageFile - description: Image file of the process + description: Image file of the process. type: Unknown - contextPath: Cybereason.Process.SHA1 - description: SHA1 of the process file + description: SHA1 of the process file. type: Unknown - contextPath: Cybereason.Process.MD5 - description: MD5 of the process file + description: MD5 of the process file. type: Unknown - contextPath: Cybereason.Process.CompanyName - description: The company's name + description: The company's name. type: Unknown - contextPath: Cybereason.Process.ProductName - description: The product's name + description: The product's name. type: Unknown - arguments: - description: The hostname of the machine to check. name: machine required: true - description: Checks if the machine is currently connected to the Cybereason server + description: Checks if the machine is currently connected to the Cybereason server. name: cybereason-is-probe-connected outputs: - contextPath: Cybereason.Machine.isConnected - description: true if machine is connected, else false + description: true if machine is connected, else false. type: boolean - contextPath: Cybereason.Machine.Name - description: Machine name + description: Machine name. type: string - arguments: - description: Filter connections which contain this IP (in or out). @@ -217,70 +217,70 @@ script: name: cybereason-query-connections outputs: - contextPath: Cybereason.Connection.Name - description: The connection's name + description: The connection's name. type: Unknown - contextPath: Cybereason.Connection.Direction - description: OUTGOING/INCOMING + description: OUTGOING/INCOMING. type: Unknown - contextPath: Cybereason.Connection.ServerAddress - description: Address of the Cybereason machine + description: Address of the Cybereason machine. type: Unknown - contextPath: Cybereason.Connection.ServerPort - description: Port of the Cybereason machine + description: Port of the Cybereason machine. type: Unknown - contextPath: Cybereason.Connection.PortType - description: Type of the connection + description: Type of the connection. type: Unknown - contextPath: Cybereason.Connection.ReceivedBytes - description: Received bytes count + description: Received bytes count. type: Unknown - contextPath: Cybereason.Connection.TransmittedBytes - description: Transmitted bytes count + description: Transmitted bytes count. type: Unknown - contextPath: Cybereason.Connection.RemoteCountry - description: The connection's remote country + description: The connection's remote country. type: Unknown - contextPath: Cybereason.Connection.OwnerMachine - description: The machine's hostname + description: The machine's hostname. type: Unknown - contextPath: Cybereason.Connection.OwnerProcess - description: The process which performed the connection + description: The process which performed the connection. type: Unknown - contextPath: Cybereason.Connection.CreationTime - description: Creation time of the connection + description: Creation time of the connection. type: Unknown - contextPath: Cybereason.Connection.EndTime - description: End time of the connection + description: End time of the connection. type: Unknown - arguments: - default: true - description: Machine name to be isolated + description: Machine name to be isolated. name: machine required: true - description: Isolates a machine that has been infected from the rest of the network + description: Isolates a machine that has been infected from the rest of the network. execution: true name: cybereason-isolate-machine outputs: - contextPath: Cybereason.Machine - description: Machine name + description: Machine name. type: string - contextPath: Cybereason.IsIsolated - description: Is the machine isolated + description: Is the machine isolated. type: boolean - arguments: - default: true - description: Machine name to be un-isolated + description: Machine name to be un-isolated. name: machine required: true - description: Stops isolation of a machine + description: Stops isolation of a machine. execution: true name: cybereason-unisolate-machine outputs: - contextPath: Cybereason.Machine - description: Machine name + description: Machine name. type: string - contextPath: Cybereason.IsIsolated - description: Is the machine isolated + description: Is the machine isolated. type: boolean - arguments: - description: Filter to filter response by, given in Cybereason API syntax. @@ -299,9 +299,9 @@ script: - CUSTOM - DETAILS - OVERVIEW - - description: Return all the malops within the last days + - description: Return all the malops within the last days. name: withinLastDays - - description: Malop GUIDs to filter by (Comma separated values supported, e.g. 11.5681864988155542407,11.1773255057963879999) + - description: Malop GUIDs to filter by (Comma separated values supported, e.g. 11.5681864988155542407,11.1773255057963879999). name: malopGuid description: Returns a list of all Malops and details on the Malops. name: cybereason-query-malops @@ -319,94 +319,94 @@ script: description: Link to the Malop on Cybereason. type: string - contextPath: Cybereason.Malops.Suspects - description: Malop suspect type and name + description: Malop suspect type and name. type: string - contextPath: Cybereason.Malops.LastUpdatedTime - description: Last updated time of malop + description: Last updated time of malop. type: string - contextPath: Cybereason.Malops.AffectedMachine - description: List of machines affected by this Malop + description: List of machines affected by this Malop. type: string - contextPath: Cybereason.Malops.InvolvedHash - description: List of file hashes involved in this Malop + description: List of file hashes involved in this Malop. type: string - contextPath: Cybereason.Malops.Status - description: Malop managemant status + description: Malop managemant status. type: string - arguments: - - description: Array of malop GUIDs separated by comma. (Malop GUID can be retrieved with the command cybereason-query-malops command) + - description: Array of malop GUIDs separated by comma. (Malop GUID can be retrieved with the command cybereason-query-malops command). name: malopGuids required: true - - description: Machine names which were affected by malop. Comma separated values supported (e.g., machine1,machine2) + - description: Machine names which were affected by malop. Comma separated values supported (e.g., machine1,machine2). name: machineName - description: Starting Date and Time to filter the Processes based on their creation date. The format for the input is ("YYYY/MM/DD HH:MM:SS"). name: dateTime - description: Returns a list of malops + description: Returns a list of malops. name: cybereason-malop-processes outputs: - contextPath: Cybereason.Process.Name - description: The process name + description: The process name. type: string - contextPath: Cybereason.Process.Malicious - description: Malicious status of the process + description: Malicious status of the process. type: Unknown - contextPath: Cybereason.Process.CreationTime - description: The process creation time + description: The process creation time. type: date - contextPath: Cybereason.Process.EndTime - description: The process end time + description: The process end time. type: date - contextPath: Cybereason.Process.CommandLine - description: The command line of the process + description: The command line of the process. type: string - contextPath: Cybereason.Process.SignedAndVerified - description: Is the process signed and verified + description: Is the process signed and verified. type: Unknown - contextPath: Cybereason.Process.ProductType - description: The product type + description: The product type. type: Unknown - contextPath: Cybereason.Process.Children - description: Children of the process + description: Children of the process. type: Unknown - contextPath: Cybereason.Process.Parent - description: The parent process + description: The parent process. type: Unknown - contextPath: Cybereason.Process.OwnerMachine - description: The machine's hostname + description: The machine's hostname. type: Unknown - contextPath: Cybereason.Process.User - description: The user who ran the process + description: The user who ran the process. type: string - contextPath: Cybereason.Process.ImageFile - description: Image file of the process + description: Image file of the process. type: Unknown - contextPath: Cybereason.Process.SHA1 - description: SHA1 of the process file + description: SHA1 of the process file. type: string - contextPath: Cybereason.Process.MD5 - description: MD5 of the process file + description: MD5 of the process file. type: string - contextPath: Cybereason.Process.CompanyName - description: The company's name + description: The company's name. type: string - contextPath: Cybereason.Process.ProductName - description: The product's name + description: The product's name. type: string - arguments: - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment required: true - - description: Malop GUID to add comment to. (Malop GUID can be retrieved with the command cybereason-query-malops command) + - description: Malop GUID to add comment to. (Malop GUID can be retrieved with the command cybereason-query-malops command). name: malopGuid required: true - description: Add new comment to malop + description: Add new comment to malop. name: cybereason-add-comment - arguments: - - description: Malop GUID to update its status + - description: Malop GUID to update its status. name: malopGuid required: true - auto: PREDEFINED - description: Status to update + description: Status to update. name: status predefined: - To Review @@ -415,312 +415,312 @@ script: - Not Relevant - Open required: true - description: Updates malop status + description: Updates malop status. name: cybereason-update-malop-status outputs: - contextPath: Cybereason.Malops.GUID - description: Malop GUID + description: Malop GUID. type: string - contextPath: Cybereason.Malops.Status - description: 'Malop status: To Review,Unread,Remediated,Not Relevant' + description: 'Malop status: To Review,Unread,Remediated,Not Relevant.' type: string - arguments: - default: true - description: Malop process file MD5 to prevent + description: Malop process file MD5 to prevent. name: md5 required: true - description: Prevent malop process file + description: Prevent malop process file. name: cybereason-prevent-file outputs: - contextPath: Cybereason.Process.MD5 - description: Process file MD5 + description: Process file MD5. type: string - contextPath: Cybereason.Process.Prevent - description: True if process file is prevented, else false + description: True if process file is prevented, else false. type: boolean - arguments: - default: true - description: Malop process file MD5 to unprevent + description: Malop process file MD5 to unprevent. name: md5 required: true - description: Unprevent malop process file + description: Unprevent malop process file. name: cybereason-unprevent-file outputs: - contextPath: Cybereason.Process.MD5 - description: Process file MD5 + description: Process file MD5. type: string - contextPath: Cybereason.Process.Prevent - description: True if process file is prevented, else false + description: True if process file is prevented, else false. type: boolean - arguments: - default: true - description: File hash (SHA-1 and MD5 supported) + description: File hash (SHA-1 and MD5 supported). name: file_hash required: true - description: Query files as part of investigation + description: Query files as part of investigation. name: cybereason-query-file outputs: - contextPath: Cybereason.File.Path - description: File path + description: File path. type: string - contextPath: Cybereason.File.SHA1 - description: File SHA-1 hash + description: File SHA-1 hash. type: string - contextPath: Cybereason.File.Machine - description: Machine name on which file is located + description: Machine name on which file is located. type: string - contextPath: Cybereason.File.SuspicionsCount - description: File suspicions count + description: File suspicions count. type: number - contextPath: Cybereason.File.Name - description: File name + description: File name. type: string - contextPath: Cybereason.File.CreationTime - description: File creation time + description: File creation time. type: date - contextPath: Cybereason.File.Suspicion - description: File suspicions object of suspicion as key and detected date as value + description: File suspicions object of suspicion as key and detected date as value. type: string - contextPath: Cybereason.File.OSVersion - description: Machine OS version on which file is located + description: Machine OS version on which file is located. type: string - contextPath: Cybereason.File.ModifiedTime - description: File modified date + description: File modified date. type: date - contextPath: Cybereason.File.Malicious - description: Is file malicious + description: Is file malicious. type: boolean - contextPath: Cybereason.File.Company - description: Company name + description: Company name. type: string - contextPath: Cybereason.File.MD5 - description: File MD5 hash + description: File MD5 hash. type: string - contextPath: Cybereason.File.IsConnected - description: Is machine connected to Cybereason + description: Is machine connected to Cybereason. type: boolean - contextPath: Cybereason.File.Signed - description: Is file signed + description: Is file signed. type: boolean - contextPath: Cybereason.File.Evidence - description: File evidences + description: File evidences. type: string - arguments: - default: true - description: Domain to query + description: Domain to query. name: domain required: true - description: Query domains as part of investigation + description: Query domains as part of investigation. name: cybereason-query-domain outputs: - contextPath: Cybereason.Domain.Name - description: Domain name + description: Domain name. type: string - contextPath: Cybereason.Domain.Malicious - description: Is domain malicious + description: Is domain malicious. type: boolean - contextPath: Cybereason.Domain.IsInternalDomain - description: Is domain internal + description: Is domain internal. type: boolean - contextPath: Cybereason.Domain.Reputation - description: Domain reputation + description: Domain reputation. type: string - contextPath: Cybereason.Domain.SuspicionsCount - description: Domain suspicions count + description: Domain suspicions count. type: number - contextPath: Cybereason.Domain.WasEverResolved - description: Was domain ever resolved + description: Was domain ever resolved. type: boolean - contextPath: Cybereason.Domain.WasEverResolvedAsASecondLevelDomain - description: Was domain ever resolved as a second level domain + description: Was domain ever resolved as a second level domain. type: boolean - arguments: - default: true - description: Username to query + description: Username to query. name: username required: true - description: Query users as part of investigation + description: Query users as part of investigation. name: cybereason-query-user outputs: - contextPath: Cybereason.User.Username - description: User name + description: User name. type: string - contextPath: Cybereason.User.Domain - description: User domain + description: User domain. type: string - contextPath: Cybereason.User.LastMachineLoggedInTo - description: Last machine which user logged in to + description: Last machine which user logged in to. type: string - contextPath: Cybereason.User.LocalSystem - description: Is local system + description: Is local system. type: boolean - contextPath: Cybereason.User.Organization - description: User organization + description: User organization. type: string - arguments: - - description: Malop GUID for fetching a file from a sensor to download + - description: Malop GUID for fetching a file from a sensor to download. name: malopGUID required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - description: Start fetching the file to download + description: Start fetching the file to download. name: cybereason-start-fetchfile - arguments: - default: true - description: Malop GUID to know the progress for downloading a file + description: Malop GUID to know the progress for downloading a file. name: malopGuid required: true - description: Return a batch id for files waiting for download + description: Return a batch id for files waiting for download. name: cybereason-fetchfile-progress outputs: - contextPath: Cybereason.Download.Progress.fileName - description: Filename for tha given malop + description: Filename for tha given malop. type: string - contextPath: Cybereason.Download.Progress.status - description: Status for batch ID + description: Status for batch ID. type: boolean - contextPath: Cybereason.Download.Progress.batchID - description: Unique batch id + description: Unique batch id. type: Unknown - arguments: - default: true - description: The batch id for the file download operation + description: The batch id for the file download operation. name: batchID required: true - description: Downloads the actual file to the machine + description: Downloads the actual file to the machine. name: cybereason-download-file - arguments: - default: true - description: The batch id to abort a file download operation + description: The batch id to abort a file download operation. name: batchID required: true - description: Aborts a file download operation that is in progress + description: Aborts a file download operation that is in progress. name: cybereason-close-file-batch-id - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - description: Get all remediation action details whatever available for that malop + description: Get all remediation action details whatever available for that malop. name: cybereason-available-remediation-actions - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to kill the process + - description: Machine name to kill the process. name: machine required: true - - description: Target ID to kill the process + - description: Target ID to kill the process. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Kill a processes for the malicious file. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Kill a processes for the malicious file. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-kill-process - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to quarantine a file + - description: Machine name to quarantine a file. name: machine required: true - - description: Target ID to quarantine a file + - description: Target ID to quarantine a file. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Quarantine the detected malicious file in a secure location. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Quarantine the detected malicious file in a secure location. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-quarantine-file - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to unquarantine a file + - description: Machine name to unquarantine a file. name: machine required: true - - description: Target ID to unquarantine a file + - description: Target ID to unquarantine a file. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Unquarantine the detected malicious file in a secure location. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Unquarantine the detected malicious file in a secure location. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-unquarantine-file - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name whose files needs to be blocked + - description: Machine name whose files needs to be blocked. name: machine required: true - - description: Target ID of file to be blocked + - description: Target ID of file to be blocked. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Block a file only in particular machine. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Block a file only in particular machine. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-block-file - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to delete the registry key + - description: Machine name to delete the registry key. name: machine required: true - - description: Target ID to delete the registry key + - description: Target ID to delete the registry key. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Delete a registry entry associated with a malicious process. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Delete a registry entry associated with a malicious process. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-delete-registry-key - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to prevent detected ransomware from running on the machine + - description: Machine name to prevent detected ransomware from running on the machine. name: machine required: true - - description: Target ID to prevent detected ransomware from running on the machine + - description: Target ID to prevent detected ransomware from running on the machine. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Prevent detected ransomware from running on the machine. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Prevent detected ransomware from running on the machine. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-kill-prevent-unsuspend - arguments: - - description: The unique ID assigned by the Cybereason platform for the Malop + - description: The unique ID assigned by the Cybereason platform for the Malop. name: malopGuid required: true - - description: Machine name to prevent a file associated with ransomware + - description: Machine name to prevent a file associated with ransomware. name: machine required: true - - description: Target ID to prevent a file associated with ransomware + - description: Target ID to prevent a file associated with ransomware. name: targetId required: true - - description: The complete Cybereason user name string for the user performing the request + - description: The complete Cybereason user name string for the user performing the request. name: userName required: true - - description: Comment to add to the malop + - description: Comment to add to the malop. name: comment - description: Prevent a file associated with ransomware. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop) + description: Prevent a file associated with ransomware. (User will get inputs by executing the 'cybereason-available-remediation-actions' command if this remediation action is available for that Malop). name: cybereason-unsuspend-process - arguments: - description: Filter for Fetching Malwares by Malware needsAttention. @@ -738,7 +738,7 @@ script: - description: Filter for Fetching Malwares by Malware Limit. name: limit required: true - description: Malware query with options and values to filter + description: Malware query with options and values to filter. name: cybereason-malware-query - arguments: - description: Sensor ID of a sensor. (Comma separated values supported.) @@ -770,7 +770,7 @@ script: script: '-' type: python subtype: python3 - dockerimage: demisto/python3:3.10.13.72123 + dockerimage: demisto/python3:3.10.13.78960 tests: - Cybereason Test fromversion: 5.0.0 diff --git a/Packs/Cybereason/ReleaseNotes/2_1_13.md b/Packs/Cybereason/ReleaseNotes/2_1_13.md new file mode 100644 index 000000000000..5d2108352e2e --- /dev/null +++ b/Packs/Cybereason/ReleaseNotes/2_1_13.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Cybereason + +- Updated the Docker image to: *demisto/python3:3.10.13.78960*. diff --git a/Packs/Cybereason/pack_metadata.json b/Packs/Cybereason/pack_metadata.json index 82f7a6e2b7ea..0dc29ce6aca9 100644 --- a/Packs/Cybereason/pack_metadata.json +++ b/Packs/Cybereason/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Cybereason", "description": "Endpoint detection and response to manage and query malops, connections and processes.", "support": "partner", - "currentVersion": "2.1.12", + "currentVersion": "2.1.13", "author": "Cybereason", "url": "https://nest.cybereason.com/", "email": "support@cybereason.com", diff --git a/Packs/EmailCommunication/ReleaseNotes/2_0_13.md b/Packs/EmailCommunication/ReleaseNotes/2_0_13.md new file mode 100644 index 000000000000..bcdaefee798a --- /dev/null +++ b/Packs/EmailCommunication/ReleaseNotes/2_0_13.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### SendEmailReply + +- Updated the Docker image to: *demisto/python3:3.10.13.78960*. diff --git a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py index 73e3c40ca0be..75a4dc7d34af 100644 --- a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py +++ b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.py @@ -812,7 +812,7 @@ def collect_thread_details(incident_email_threads, email_selected_thread): # Keep track of the last processed list position last_thread_processed = idx - return thread_found, reply_to_message_id, outbound_only, reply_code, reply_subject, reply_recipients,\ + return thread_found, reply_to_message_id, outbound_only, reply_code, reply_subject, reply_recipients, \ reply_mailbox, thread_cc, thread_bcc, last_thread_processed @@ -870,7 +870,7 @@ def multi_thread_reply(new_email_body, incident_id, email_selected_thread, new_e elif type(incident_email_threads) == list: # Process existing thread entries in this email chain to gather re-usable data for new message thread_found, reply_to_message_id, outbound_only, reply_code, reply_subject, reply_recipients, \ - reply_mailbox, thread_cc, thread_bcc,\ + reply_mailbox, thread_cc, thread_bcc, \ last_thread_processed = collect_thread_details(incident_email_threads, email_selected_thread) if thread_found is False: diff --git a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml index 3258519738cf..07197f6586ab 100644 --- a/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml +++ b/Packs/EmailCommunication/Scripts/SendEmailReply/SendEmailReply.yml @@ -1,17 +1,17 @@ args: - defaultValue: ${File} - description: Files + description: Files. isArray: true name: files - defaultValue: ${incident.attachment} - description: Attachment + description: Attachment. isArray: true name: attachment - defaultValue: description: The mailbox from which emails are sent from the 3rd party integration. name: service_mail - name: mail_sender_instance - description: Name of the mail sender instance name for transmitting emails + description: Name of the mail sender instance name for transmitting emails. defaultValue: - name: new_thread auto: PREDEFINED @@ -19,7 +19,7 @@ args: - 'true' - 'false' - n/a - description: Specify whether to reply to an existing thread or start a new one. Default value of 'n/a' is for 'Email Communication' type incidents only + description: Specify whether to reply to an existing thread or start a new one. Default value of 'n/a' is for 'Email Communication' type incidents only. defaultValue: n/a - name: subject_include_incident_id description: Include the Incident ID within the email subject. @@ -46,7 +46,7 @@ subtype: python3 system: true type: python fromversion: 5.0.0 -dockerimage: demisto/python3:3.10.12.68300 +dockerimage: demisto/python3:3.10.13.78960 tests: - No tests (auto formatted) contentitemexportablefields: diff --git a/Packs/EmailCommunication/pack_metadata.json b/Packs/EmailCommunication/pack_metadata.json index d34a39203c2c..e4336a6b903d 100644 --- a/Packs/EmailCommunication/pack_metadata.json +++ b/Packs/EmailCommunication/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Email Communication", "description": "Do you have to send multiple emails to end users? This content pack helps you streamline the process and automate updates, notifications and more.\n", "support": "xsoar", - "currentVersion": "2.0.12", + "currentVersion": "2.0.13", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "videos": [ diff --git a/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.py b/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.py index 3c96e1ce6092..a1369765b695 100644 --- a/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.py +++ b/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.py @@ -7,7 +7,7 @@ from dxlclient.broker import Broker from dxltieclient import TieClient from typing import NamedTuple -from dxltieclient.constants import FileReputationProp, FileGtiAttrib, FileEnterpriseAttrib, AtdAttrib, TrustLevel,\ +from dxltieclient.constants import FileReputationProp, FileGtiAttrib, FileEnterpriseAttrib, AtdAttrib, TrustLevel, \ HashType, EnterpriseAttrib, FileProvider, FirstRefProp, AtdTrustLevel VENDOR_NAME = 'McAfee Threat Intelligence Exchange' @@ -520,8 +520,8 @@ def create_temp_credentials(temp_file: tempfile._TemporaryFileWrapper, data_to_w @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,\ + 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: broker_certs_file.delete create_temp_credentials(broker_certs_file, instance_cert.broker_ca_bundle) diff --git a/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.yml b/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.yml index 00ddd33a77f9..cb17fba190f9 100644 --- a/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.yml +++ b/Packs/McAfee-TIE/Integrations/McAfeeTIEV2/McAfeeTIEV2.yml @@ -272,7 +272,7 @@ script: - contextPath: McAfee.TIE.FilesReferences.Hash description: The value of the hash. type: String - dockerimage: demisto/dxl:1.0.0.73187 + dockerimage: demisto/dxl:1.0.0.78624 runonce: false script: "-" subtype: python3 diff --git a/Packs/McAfee-TIE/ReleaseNotes/2_0_15.md b/Packs/McAfee-TIE/ReleaseNotes/2_0_15.md new file mode 100644 index 000000000000..cda894f42552 --- /dev/null +++ b/Packs/McAfee-TIE/ReleaseNotes/2_0_15.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### McAfee Threat Intelligence Exchange v2 + +- Updated the Docker image to: *demisto/dxl:1.0.0.78624*. diff --git a/Packs/McAfee-TIE/pack_metadata.json b/Packs/McAfee-TIE/pack_metadata.json index bb342e576d47..45f2496d690c 100644 --- a/Packs/McAfee-TIE/pack_metadata.json +++ b/Packs/McAfee-TIE/pack_metadata.json @@ -2,7 +2,7 @@ "name": "McAfee Threat Intelligence Exchange", "description": "Connect to McAfee TIE using the McAfee DXL client.", "support": "xsoar", - "currentVersion": "2.0.14", + "currentVersion": "2.0.15", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", From 15659057e5accd912c92e26e3d5c49a61d0ef048 Mon Sep 17 00:00:00 2001 From: PierrickV Date: Wed, 19 Jul 2023 13:51:26 +0200 Subject: [PATCH 2/3] fix(sekoiaiocti): fix returned information for unknown indicator --- .../SEKOIAIntelligenceCenter.py | 148 +++++++++++++----- .../SEKOIAIntelligenceCenter_test.py | 84 +++++++--- 2 files changed, 177 insertions(+), 55 deletions(-) diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py index eb68a8d91caf..0c92775b12ca 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py @@ -149,13 +149,16 @@ def get_reputation_score(indicator_types: list[str]) -> int: return Common.DBotScore.NONE -def extract_indicator_from_pattern(pattern_str: str) -> str | None: +def extract_indicator_from_pattern(pattern_str: str | None) -> str | None: """ Extract indicator from STIX indicator pattern. i.e. [ipv4-addr:value = '198.51.100.1/32'] => 198.51.100.1/32 [ipv4-addr:value = '198.51.100.1/32' OR ipv4-addr:value = '203.0.113.33/32'] => 198.51.100.1/32 """ + if pattern_str is None: + return None + pattern = PatternParser(pattern_str) data = pattern.inspect() @@ -213,36 +216,65 @@ def get_tlp(object_marking_refs: list[str], stix_bundle: dict) -> str: """ for object_marking_ref in object_marking_refs: for stix_object in stix_bundle["objects"]: - if stix_object["id"] == object_marking_ref and stix_object.get("definition_type") == "tlp": + if ( + stix_object["id"] == object_marking_ref + and stix_object.get("definition_type") == "tlp" + ): return stix_object["definition"]["tlp"] return "red" -def get_stix_object_reputation(stix_bundle: dict, stix_object: dict) -> Optional[CommandResults]: +def get_stix_object_reputation( + stix_bundle: dict, stix_object: dict +) -> Optional[CommandResults]: """ " Transform a STIX object into a Cortex XSOAR indicator """ reputation_score: int = get_reputation_score(stix_object.get("indicator_types", [])) - reliability_score: str = get_reliability_score(int(stix_object.get("confidence", -1))) - tlp: str = get_tlp(stix_object["object_marking_refs"], stix_bundle) - - if "ipv4-addr" in stix_object["x_ic_observable_types"] or "ipv6-addr" in stix_object["x_ic_observable_types"]: - return get_ip_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) + reliability_score: str = get_reliability_score( + int(stix_object.get("confidence", -1)) + ) + tlp: str = get_tlp(stix_object.get("object_marking_refs", []), stix_bundle) + indicator_value: str | None = extract_indicator_from_pattern( + stix_object.get("pattern", None) + ) or stix_object.get("name") + + if ( + "ipv4-addr" in stix_object["x_ic_observable_types"] + or "ipv6-addr" in stix_object["x_ic_observable_types"] + ): + return get_ip_indicator_reputation( + indicator_value, stix_object, reputation_score, reliability_score, tlp + ) if "file" in stix_object["x_ic_observable_types"]: - return get_file_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) + return get_file_indicator_reputation( + stix_object, reputation_score, reliability_score, tlp + ) if "domain-name" in stix_object["x_ic_observable_types"]: - return get_domain_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) + return get_domain_indicator_reputation( + stix_object, reputation_score, reliability_score, tlp + ) if "url" in stix_object["x_ic_observable_types"]: - return get_url_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) + return get_url_indicator_reputation( + stix_object, reputation_score, reliability_score, tlp + ) if "email-addr" in stix_object["x_ic_observable_types"]: - return get_email_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) + return get_email_indicator_reputation( + stix_object, reputation_score, reliability_score, tlp + ) return None -def get_ip_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: +def get_ip_indicator_reputation( + indicator_value: str | None, + stix_object: dict, + reputation_score: int, + reliability_score: str, + tlp: str, +) -> CommandResults: """ Return stix_object of type IP as indicator """ @@ -254,9 +286,8 @@ def get_ip_indicator_reputation(stix_object: dict, reputation_score: int, reliab reliability=reliability_score, ) - ip_addr = extract_indicator_from_pattern(stix_object["pattern"]) ip = Common.IP( - ip=ip_addr, + ip=indicator_value, dbot_score=dbot_score, traffic_light_protocol=tlp, ) @@ -268,7 +299,9 @@ def get_ip_indicator_reputation(stix_object: dict, reputation_score: int, reliab ) -def get_file_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: +def get_file_indicator_reputation( + stix_object: dict, reputation_score: int, reliability_score: str, tlp: str +) -> CommandResults: """ Return stix_object of type file as indicator """ @@ -299,7 +332,9 @@ def get_file_indicator_reputation(stix_object: dict, reputation_score: int, reli ) -def get_domain_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: +def get_domain_indicator_reputation( + stix_object: dict, reputation_score: int, reliability_score: str, tlp: str +) -> CommandResults: """ Return stix_object of type domain as indicator """ @@ -327,7 +362,9 @@ def get_domain_indicator_reputation(stix_object: dict, reputation_score: int, re ) -def get_url_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: +def get_url_indicator_reputation( + stix_object: dict, reputation_score: int, reliability_score: str, tlp: str +) -> CommandResults: """ Return stix_object of type url as indicator """ @@ -374,7 +411,12 @@ def get_email_indicator_reputation( if not email_addr: return None - email = Common.EMAIL(address=email_addr, domain=email_addr.split("@")[-1], dbot_score=dbot_score, traffic_light_protocol=tlp) + email = Common.EMAIL( + address=email_addr, + domain=email_addr.split("@")[-1], + dbot_score=dbot_score, + traffic_light_protocol=tlp, + ) return CommandResults( outputs_prefix="SEKOIAIntelligenceCenter.EMAIL", @@ -426,7 +468,9 @@ def indicator_context_to_markdown(indicator_context: dict) -> str: if linked_stix_objects_refs: # Retrieve STIX objects which are the target in the relationship linked_stix_objects = [ - stix_object for stix_object in stix_bundle["objects"] if stix_object["id"] in linked_stix_objects_refs + stix_object + for stix_object in stix_bundle["objects"] + if stix_object["id"] in linked_stix_objects_refs ] # Add "more_info" link, which redirect to SEKOIA Intelligence Center @@ -445,10 +489,23 @@ def indicator_context_to_markdown(indicator_context: dict) -> str: return markdown -def extract_indicators(indicator_context: dict, command_results_list: list[CommandResults]) -> list: +def extract_indicators(indicator: dict, indicator_context: dict) -> list: """ Return each indicators of the STIX bundles as a list of CommandResults """ + # Indicator context for empty API response + if indicator_context["items"] == []: + stix_object = { + "name": indicator["value"], + "x_ic_observable_types": [indicator["type"]], + } + object_reputation = get_stix_object_reputation( + stix_bundle={}, stix_object=stix_object + ) + return [object_reputation] + + # Indicator context for known indicator + command_results_list: list = [] for stix_bundle in indicator_context["items"]: for stix_object in stix_bundle["objects"]: if stix_object["type"] == "indicator": @@ -481,7 +538,6 @@ def test_module(client: Client) -> str: try: client.get_validate_resource() except DemistoException as e: - doc = """Please visit the API Key documentation for more information: https://docs.sekoia.io/getting_started/generate_api_keys/""" @@ -517,18 +573,24 @@ def get_observable_command(client: Client, args: dict[str, str]) -> CommandResul indicator_value = args.get("value") indicator_type = args.get("type") if not indicator_value or not indicator_type: - raise ValueError(f"incomplete command for value {indicator_value} and type {indicator_type}") + raise ValueError( + f"incomplete command for value {indicator_value} and type {indicator_type}" + ) result = client.get_observable(value=indicator_value, indicator_type=indicator_type) indicator = {"value": indicator_value, "type": indicator_type} outputs = {"indicator": indicator, "items": result.get("items", [])} if result["items"] == []: - markdown = f"### {indicator_value} of type {indicator_type} is an unknown observable." + markdown = ( + f"### {indicator_value} of type {indicator_type} is an unknown observable." + ) else: table_title = f'Observable {result["items"][0].get("value")}' table_headers = ["modified", "created"] - markdown = tableToMarkdown(table_title, result["items"][0], headers=table_headers) + markdown = tableToMarkdown( + table_title, result["items"][0], headers=table_headers + ) table_headers = ["valid_from", "valid_until", "name"] markdown += tableToMarkdown( "Associated tags", @@ -569,7 +631,9 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult indicator_value = args.get("value") indicator_type = args.get("type") if not indicator_value or not indicator_type: - raise ValueError(f"incomplete command for value {indicator_value} and type {indicator_type}") + raise ValueError( + f"incomplete command for value {indicator_value} and type {indicator_type}" + ) result = client.get_indicator(value=indicator_value, indicator_type=indicator_type) indicator = {"value": indicator_value, "type": indicator_type} @@ -577,7 +641,9 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult # Format output if result["items"] == []: - markdown = f"### {indicator_value} of type {indicator_type} is an unknown indicator." + markdown = ( + f"### {indicator_value} of type {indicator_type} is an unknown indicator." + ) else: markdown = ( f'### Indicator {result["items"][0].get("name")}' @@ -603,7 +669,9 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult ) -def get_indicator_context_command(client: Client, args: dict[str, str]) -> list[CommandResults]: +def get_indicator_context_command( + client: Client, args: dict[str, str] +) -> list[CommandResults]: """ip command: Returns IP reputation for a list of IPs :type client: ``Client`` @@ -624,9 +692,9 @@ def get_indicator_context_command(client: Client, args: dict[str, str]) -> list[ if not indicator["value"] or not indicator["type"]: raise ValueError(f"incomplete command for {indicator}") - command_results_list: list[CommandResults] = [] - - indicator_context = client.get_indicator_context(value=indicator["value"], indicator_type=indicator["type"]) + indicator_context = client.get_indicator_context( + value=indicator["value"], indicator_type=indicator["type"] + ) outputs = {"indicator": indicator, "items": indicator_context.get("items", [])} if indicator_context["items"] == []: @@ -636,7 +704,9 @@ def get_indicator_context_command(client: Client, args: dict[str, str]) -> list[ markdown = indicator_context_to_markdown(indicator_context) # Extract STIX object type indicator from the STIX bundles - command_results_list = extract_indicators(indicator_context, command_results_list) + command_results_list: list = extract_indicators( + indicator=indicator, indicator_context=indicator_context + ) command_results_list.append( CommandResults( @@ -663,7 +733,9 @@ def ip_command(client: Client, args: dict[str, str]) -> list[CommandResults]: return results -def reputation_command(client: Client, args: dict[str, str], indicator_type) -> list[CommandResults]: +def reputation_command( + client: Client, args: dict[str, str], indicator_type +) -> list[CommandResults]: """reputation command: Returns reputation for a list of indicator This command is a wrapper around the `get_indicator_context_command` @@ -704,7 +776,9 @@ def main() -> None: try: headers = {"Authorization": f"Bearer {api_key}"} - client = Client(base_url=BASE_URL, verify=verify_certificate, headers=headers, proxy=proxy) + client = Client( + base_url=BASE_URL, verify=verify_certificate, headers=headers, proxy=proxy + ) if demisto.command() == "test-module": # This is the call made when pressing the integration Test button. @@ -725,7 +799,11 @@ def main() -> None: return_results(ip_command(client, demisto.args())) elif demisto.command() in ["url", "domain", "file", "email"]: - return_results(reputation_command(client, demisto.args(), indicator_type=demisto.command())) + return_results( + reputation_command( + client, demisto.args(), indicator_type=demisto.command() + ) + ) # Log exceptions and return errors except Exception as e: diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py index 986d0962cbe9..10090fc153e2 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py @@ -62,10 +62,13 @@ def test_extract_indicator_from_pattern_wrong_pattern(client): ("email-addr", "does-not-exist@sekoia.io", "test_data/observable_unknown.json"), ], ) -def test_get_observables(client, requests_mock, indicator_value, indicator_type, json_test_file): +def test_get_observables( + client, requests_mock, indicator_value, indicator_type, json_test_file +): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL + f"/v2/inthreat/observables?match[value]={indicator_value}&match[type]={indicator_type}", + MOCK_URL + + f"/v2/inthreat/observables?match[value]={indicator_value}&match[type]={indicator_type}", json=mock_response, ) @@ -114,7 +117,6 @@ def test_test_module_nok(client, requests_mock, api_response, expected): # This test only runs if SEKOIA.IO API_KEY is provided @pytest.mark.skipif("{'SEKOIAIO_APIKEY'}.issubset(os.environ.keys()) == False") def test_get_validate_resource_with_credentials(client): - result = client.get_validate_resource() assert result == "ok" @@ -123,7 +125,6 @@ def test_get_validate_resource_with_credentials(client): # This test only runs if SEKOIA.IO API_KEY is provided @pytest.mark.skipif("{'SEKOIAIO_APIKEY'}.issubset(os.environ.keys()) == False") def test_get_observables_with_credentials(client): - args = {"value": "eicar@sekoia.io", "type": "email-addr"} result = SEKOIAIntelligenceCenter.get_observable_command(client=client, args=args) @@ -138,10 +139,13 @@ def test_get_observables_with_credentials(client): ("email-addr", "does-not-exist@sekoia.io", "test_data/indicator_unknown.json"), ], ) -def test_get_indicator(client, requests_mock, indicator_value, indicator_type, json_test_file): +def test_get_indicator( + client, requests_mock, indicator_value, indicator_type, json_test_file +): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL + f"/v2/inthreat/indicators?value={indicator_value}&type={indicator_type}", + MOCK_URL + + f"/v2/inthreat/indicators?value={indicator_value}&type={indicator_type}", json=mock_response, ) args = {"value": {indicator_value}, "type": {indicator_type}} @@ -174,8 +178,9 @@ def test_get_indicator_with_credentials(client): (SEKOIAIntelligenceCenter.get_indicator_context_command, "", "ipv4-addr"), ], ) -def test_get_indicator_context_incomplete(client, command, indicator_type, indicator_value): - +def test_get_indicator_context_incomplete( + client, command, indicator_type, indicator_value +): args = {"value": indicator_value, "type": indicator_type} with pytest.raises(ValueError): command(client=client, args=args) @@ -196,7 +201,6 @@ def test_get_indicator_context_incomplete(client, command, indicator_type, indic "test_data/indicator_context_filename.json", ), ("ipv4-addr", "206.189.85.18", "test_data/indicator_context_ip.json"), - ("ipv4-addr", "1.1.1.1", "test_data/indicator_context_unknown.json"), ("url", "http://177.22.84.44:49467/.i", "test_data/indicator_context_url.json"), ( "domain-name", @@ -205,15 +209,45 @@ def test_get_indicator_context_incomplete(client, command, indicator_type, indic ), ], ) -def test_get_indicator_context(client, requests_mock, indicator_type, indicator_value, json_test_file): +def test_get_indicator_context( + client, requests_mock, indicator_type, indicator_value, json_test_file +): + mock_response = util_load_json(json_test_file) + requests_mock.get( + MOCK_URL + + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", + json=mock_response, + ) + + args = {"value": indicator_value, "type": indicator_type} + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( + client=client, args=args + ) + for result in command_results: + assert result.outputs != [] + assert result.to_context != [] + + +@pytest.mark.parametrize( + "indicator_type, indicator_value, json_test_file", + [ + ("ipv4-addr", "1.1.1.1", "test_data/indicator_context_unknown.json"), + ], +) +def test_get_indicator_context_unknown_indicator( + client, requests_mock, indicator_type, indicator_value, json_test_file +): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", + MOCK_URL + + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", json=mock_response, ) args = {"value": indicator_value, "type": indicator_type} - command_results = SEKOIAIntelligenceCenter.get_indicator_context_command(client=client, args=args) + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( + client=client, args=args + ) for result in command_results: assert result.outputs != [] assert result.to_context != [] @@ -233,9 +267,13 @@ def test_get_indicator_context(client, requests_mock, indicator_type, indicator_ ("domain-name", "buike.duckdns.org"), ], ) -def test_get_indicator_context_with_credentials(client, indicator_value, indicator_type): +def test_get_indicator_context_with_credentials( + client, indicator_value, indicator_type +): args = {"value": indicator_value, "type": indicator_type} - command_results = SEKOIAIntelligenceCenter.get_indicator_context_command(client=client, args=args) + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( + client=client, args=args + ) for result in command_results: assert result.outputs != [] @@ -330,15 +368,18 @@ def test_get_reputation_score(input: list, output: int): ), ], ) -def test_ip_command(client, requests_mock, indicator_type, indicator_value, json_test_file): - +def test_ip_command( + client, requests_mock, indicator_type, indicator_value, json_test_file +): mock_response = util_load_json(json_test_file) requests_mock.get( MOCK_URL + "/v2/inthreat/indicators/context", json=mock_response, ) - command_results = SEKOIAIntelligenceCenter.ip_command(client=client, args={"ip": indicator_value}) + command_results = SEKOIAIntelligenceCenter.ip_command( + client=client, args={"ip": indicator_value} + ) for result in command_results: assert result.outputs != [] @@ -374,14 +415,15 @@ def test_ip_version(client, input, output): ], ) def test_reputation_command(client, input, command, requests_mock): - mock_response = util_load_json("test_data/indicator_context_ip.json") requests_mock.get( MOCK_URL + "/v2/inthreat/indicators/context", json=mock_response, ) args = {command: input} - command_results = SEKOIAIntelligenceCenter.reputation_command(client=client, args=args, indicator_type=command) + command_results = SEKOIAIntelligenceCenter.reputation_command( + client=client, args=args, indicator_type=command + ) for result in command_results: assert result.outputs != [] @@ -392,4 +434,6 @@ def test_reputation_command_wrong_type(client): indicator_type = "wrong-type" args = {indicator_type: "1.1.1.1"} with pytest.raises(ValueError): - SEKOIAIntelligenceCenter.reputation_command(client=client, args=args, indicator_type=indicator_type) + SEKOIAIntelligenceCenter.reputation_command( + client=client, args=args, indicator_type=indicator_type + ) From 13739e1b3be49eea56141364d3e8818193bb40f3 Mon Sep 17 00:00:00 2001 From: PierrickV Date: Mon, 23 Oct 2023 09:44:06 +0000 Subject: [PATCH 3/3] chore(sekoiaiocti): linting --- .../SEKOIAIntelligenceCenter/README.md | 58 ++++++++- .../SEKOIAIntelligenceCenter.py | 119 +++++------------- .../SEKOIAIntelligenceCenter.yml | 6 +- .../SEKOIAIntelligenceCenter_test.py | 81 ++++-------- 4 files changed, 116 insertions(+), 148 deletions(-) diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/README.md b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/README.md index 0f0b596444b9..f0783a0ea4eb 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/README.md +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/README.md @@ -18,10 +18,14 @@ This integration was integrated and tested with version 2.20220712 of SEKOIA.IO | Source Reliability | Reliability of the source providing the intelligence data. | | 4. Click **Test** to validate the URLs, token, and connection. + ## Commands + You can execute these commands from the Cortex XSOAR 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. + ### GetObservable + *** Query SEKOIA.IO Intelligence Center for information about this observable. @@ -29,6 +33,7 @@ Query SEKOIA.IO Intelligence Center for information about this observable. #### Base Command `GetObservable` + #### Input | **Argument Name** | **Description** | **Required** | @@ -54,8 +59,11 @@ Query SEKOIA.IO Intelligence Center for information about this observable. | SEKOIAIntelligenceCenter.items.id | String | Unique identifier of the item | #### Command example + ```!GetObservable value="eicar@sekoia.io" type="email-addr"``` + #### Context Example + ```json { "SEKOIAIntelligenceCenter": { @@ -87,15 +95,19 @@ Query SEKOIA.IO Intelligence Center for information about this observable. #### Human Readable Output >### Observable eicar@sekoia.io + >|modified|created| >|---|---| >| 2020-11-04T00:27:15.9801Z | 2020-11-04T00:27:15.9801Z | + >### Associated tags + >**No entries.** >Please consult the [dedicated page](https://app.sekoia.io/intelligence/objects/email-addr--cd6440d1-725c-5eb9-bff0-5e62c65ee263) for more information. ### GetIndicator + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -103,6 +115,7 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Base Command `GetIndicator` + #### Input | **Argument Name** | **Description** | **Required** | @@ -140,8 +153,11 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf | SEKOIAIntelligenceCenter.items.indicator_types | String | STIX indicator types | #### Command example + ```!GetIndicator value="eicar@sekoia.io" type="email-addr"``` + #### Context Example + ```json { "SEKOIAIntelligenceCenter": { @@ -198,7 +214,9 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf >### Indicator eicar@sekoia.io is categorized as ['benign'] > >SEKOIA EICAR unit is known to have used in the past this email address to distribute EICAR dropper during phishing campaign. + >### Kill chain + >|kill_chain_name|phase_name| >|---|---| >| lockheed-martin-cyber-kill-chain | delivery | @@ -208,6 +226,7 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf ### ip + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -215,6 +234,7 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Base Command `ip` + #### Input | **Argument Name** | **Description** | **Required** | @@ -284,8 +304,11 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf | DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | #### Command example + ```!ip ip="206.189.85.18"``` + #### Context Example + ```json { "DBotScore": { @@ -1340,12 +1363,14 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Human Readable Output >### Indicator 206.189.85.18 is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| FinFisher | [FinFisher](https://attack.mitre.org/software/S0182) is a government-grade commercial surveillance spyware reportedly sold exclusively to government agencies for use in targeted and lawful criminal investigations. It is heavily obfuscated and uses multiple anti-analysis techniques. It has other variants including [Wingbird](https://attack.mitre.org/software/S0176). (Citation: FinFisher Citation) (Citation: Microsoft SIR Vol 21) (Citation: FireEye FinSpy Sept 2017) (Citation: Securelist BlackOasis Oct 2017) (Citation: Microsoft FinFisher March 2018) | malware | FinFisher | | false | 2019-07-19T15:25:38.820741Z | 2021-11-23T09:13:59.891896Z | [More info about FinFisher on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/malware--a36a2045-61dd-4462-8d5a-95d6732b74c3) | ### url + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -1354,6 +1379,7 @@ Notice: Submitting indicators using this command might make the indicator data p #### Base Command `url` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1423,8 +1449,11 @@ Notice: Submitting indicators using this command might make the indicator data p | DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | #### Command example + ```!url url="http://truesec.pro/"``` + #### Context Example + ```json { "DBotScore": { @@ -5938,13 +5967,15 @@ Notice: Submitting indicators using this command might make the indicator data p #### Human Readable Output ->### Indicator http://truesec.pro/ is linked to the following: +>### Indicator is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| Phishing | Adversaries may send phishing messages to gain access to victim systems. All forms of phishing are electronically delivered social engineering. Phishing can be targeted, known as spearphishing. In spearphishing, a specific individual, company, or industry will be targeted by the adversary. More generally, adversaries can conduct non-targeted phishing, such as in mass malware spam campaigns.

Adversaries may send victims emails containing malicious attachments or links, typically to execute malicious code on victim systems or to gather credentials for use of [Valid Accounts](https://attack.mitre.org/techniques/T1078). Phishing may also be conducted via third-party services, like social media platforms. | attack-pattern | | | false | 2020-08-27T16:06:57.165806Z | 2022-01-28T08:06:15.568392Z | [More info about Phishing on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/attack-pattern--a5911dd1-af0e-4164-a099-a1fa4909e42e) | ### domain + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -5953,6 +5984,7 @@ Notice: Submitting indicators using this command might make the indicator data p #### Base Command `domain` + #### Input | **Argument Name** | **Description** | **Required** | @@ -6022,8 +6054,11 @@ Notice: Submitting indicators using this command might make the indicator data p | DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | #### Command example + ```!domain domain="eicar.sekoia.io"``` + #### Context Example + ```json { "DBotScore": { @@ -6483,12 +6518,14 @@ Notice: Submitting indicators using this command might make the indicator data p #### Human Readable Output >### Indicator eicar.sekoia.io is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| Dropper TEST EICAR SEKOIA.IO | *Context*
This Dropper is used by SEKOIA Red Team as a demonstration to illustrate how an inoculated file could also be used as a malicious file to install dangerous content onto the corporate environment.

*Execution stages*
This dropper is known to be distributed as a Powershell script.
- At execution, it drops a text payload (inoculated payload part of the EICAR campaign)
- If Internet connectivity is available, the dropper contacts a Command and control server to install additional modules (deactivated in the EICAR campaign)
| malware | EICAR,
Malware TEST EICAR SEKOIA.IO,
Dropper TEST EICAR SEKOIA.IO | | false | 2020-05-26T13:19:41.236073Z | 2020-06-22T09:09:28.349981Z | [More info about Dropper TEST EICAR SEKOIA.IO on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/malware--2850a39e-39a1-4701-a3cc-185478464dc5) | ### file + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -6496,6 +6533,7 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Base Command `file` + #### Input | **Argument Name** | **Description** | **Required** | @@ -6568,8 +6606,11 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf | DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | #### Command example + ```!file file="e1d4d2e829885b322f7e619cbfc2615f"``` + #### Context Example + ```json { "DBotScore": { @@ -8857,16 +8898,20 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Human Readable Output >### Indicator [file:hashes.'SHA-256' = '8fdc11e44341c3df5a8020b3313eb0a33b2d77fa05d4af0168f911b3a4d3b74a' OR file:hashes.MD5 = 'e1d4d2e829885b322f7e619cbfc2615f' OR file:hashes.'SHA-1' = 'cb6dfb7d8732a74187f61db80aa9f31a29c10888'] is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| Agent Tesla | # Resume

Agent Tesla is a spyware that steals passwords and collects information about the actions of its victims by recording keystrokes and user interactions. The malware can be used by attackers to spy on victims, allowing them to see everything that has been typed in supported programs and web-browsers. The spyware has been observed in the world since 2014 and has become extremely popular in the cybercriminal community in recent years.

# Chain of infection

The most widespread delivery method for Agent Tesla is malicious spam, via Microsoft Word documents that contain an embedded executed file or exploit. The email accounts used to spread the spyware are often legitimate accounts that have been compromised. Agent Tesla operators act out of opportunism and lack the sophistication seen in elaborate operations such as big game hunting.

Once the user has clicked on the malicious document, the executable is downloaded and renamed. The downloaded file runs itself and creates a child process. Before taking actions on objectives, Agent Tesla checks the environment of the compromised machine to avoid being deployed in a Virtual Machine and therefore bypass sandbox analysis. Multiple sandbox evasion techniques are performed - such as reading hardware parameters, disabling AMSI scans, checking for user input or using sleeping functions.

Agent Tesla establishes persistence by creating a registry RUN key to run at boot, or creating a scheduled task via schtasks.exe. Once well installed, the malware takes actions on objectives and sends data to the Command & Control server. Latest Agent Tesla versions offer different means of communication - over SMTP, FTP or HTTP, but also using Telegram, Discord or Tor network.
According to SEKOIA research, most Agent Tesla operators employ SMTP communications on port 587 using compromised email accounts.

# Capacity

* Taking fingerprint:
For example, it corresponds to the footprint of an infected machine:
\`\`\`
Time: 02/11/2021 08:45:53
User Name: JohnDoe
Computer Name: ACME-JOHN-DOE-PC
OSFullName: Microsoft Windows 7 Édition Intégrale
CPU: Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
RAM: 3931,59 MB
IP Address:
\`\`\`
In some cases, Agent Tesla requests \`api.ipify[.]org\`, a simple public IP address API, to retrieve the victim IP address.
The body of each email sent to C2 begins with the fingerprint.

* Stealing password (from many applications):
Those information are sent by email whose subject is \`PW_JohnDoe/ACME-JOHN-DOE-PC\`, \`PW\` for password.

* Keystroke logging:
The subject of the email is \`KL_JohnDoe/ACME-JOHN-DOE-PC\`, \`KL\` for Keystroke logging.

* Stealing cookies:
Agent Tesla archives the directories that store the cookies of different browsers, e.g.: \`C:\Users\JohnDoe\AppData\Local\Google\Chrome\User Data\Default\`, and adds it as attachment to emails whose subject is \`CO_JohnDoe/ACME-JOHN-DOE-PC\`, \`CO\` for Cookies.

* Capturing clipboard:
Screenshots are taken by the spyware and sent by email whose subject is \`SC_JohnDoe/ACME-JOHN-DOE-PC\`, \`SC\` for SCreenshot.

Other capabilities are available, but are less used. | malware | Agent Tesla,
AgentTesla,
AgenTesla,
Negasteal | | false | 2019-07-19T15:25:33.745282Z | 2021-12-23T19:52:16.428429Z | [More info about Agent Tesla on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/malware--1db42657-baba-4ada-a07b-a55d21bfdb9f) | + >### Indicator [file:hashes.MD5 = 'e1d4d2e829885b322f7e619cbfc2615f' OR file:hashes.'SHA-1' = 'cb6dfb7d8732a74187f61db80aa9f31a29c10888' OR file:hashes.'SHA-256' = '8fdc11e44341c3df5a8020b3313eb0a33b2d77fa05d4af0168f911b3a4d3b74a' OR file:hashes.'SHA-512' = '346c463b203b4aa72b5a6a3dee547d29aa03b85027f8dbb6ae61b4a81dd1f3c939f0e21b041124a0a070c1d82ef39820e191bc551d44bde8153df9a24e2f002b'] is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| Agent Tesla | # Resume

Agent Tesla is a spyware that steals passwords and collects information about the actions of its victims by recording keystrokes and user interactions. The malware can be used by attackers to spy on victims, allowing them to see everything that has been typed in supported programs and web-browsers. The spyware has been observed in the world since 2014 and has become extremely popular in the cybercriminal community in recent years.

# Chain of infection

The most widespread delivery method for Agent Tesla is malicious spam, via Microsoft Word documents that contain an embedded executed file or exploit. The email accounts used to spread the spyware are often legitimate accounts that have been compromised. Agent Tesla operators act out of opportunism and lack the sophistication seen in elaborate operations such as big game hunting.

Once the user has clicked on the malicious document, the executable is downloaded and renamed. The downloaded file runs itself and creates a child process. Before taking actions on objectives, Agent Tesla checks the environment of the compromised machine to avoid being deployed in a Virtual Machine and therefore bypass sandbox analysis. Multiple sandbox evasion techniques are performed - such as reading hardware parameters, disabling AMSI scans, checking for user input or using sleeping functions.

Agent Tesla establishes persistence by creating a registry RUN key to run at boot, or creating a scheduled task via schtasks.exe. Once well installed, the malware takes actions on objectives and sends data to the Command & Control server. Latest Agent Tesla versions offer different means of communication - over SMTP, FTP or HTTP, but also using Telegram, Discord or Tor network.
According to SEKOIA research, most Agent Tesla operators employ SMTP communications on port 587 using compromised email accounts.

# Capacity

* Taking fingerprint:
For example, it corresponds to the footprint of an infected machine:
\`\`\`
Time: 02/11/2021 08:45:53
User Name: JohnDoe
Computer Name: ACME-JOHN-DOE-PC
OSFullName: Microsoft Windows 7 Édition Intégrale
CPU: Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
RAM: 3931,59 MB
IP Address:
\`\`\`
In some cases, Agent Tesla requests \`api.ipify[.]org\`, a simple public IP address API, to retrieve the victim IP address.
The body of each email sent to C2 begins with the fingerprint.

* Stealing password (from many applications):
Those information are sent by email whose subject is \`PW_JohnDoe/ACME-JOHN-DOE-PC\`, \`PW\` for password.

* Keystroke logging:
The subject of the email is \`KL_JohnDoe/ACME-JOHN-DOE-PC\`, \`KL\` for Keystroke logging.

* Stealing cookies:
Agent Tesla archives the directories that store the cookies of different browsers, e.g.: \`C:\Users\JohnDoe\AppData\Local\Google\Chrome\User Data\Default\`, and adds it as attachment to emails whose subject is \`CO_JohnDoe/ACME-JOHN-DOE-PC\`, \`CO\` for Cookies.

* Capturing clipboard:
Screenshots are taken by the spyware and sent by email whose subject is \`SC_JohnDoe/ACME-JOHN-DOE-PC\`, \`SC\` for SCreenshot.

Other capabilities are available, but are less used. | malware | Agent Tesla,
AgentTesla,
AgenTesla,
Negasteal | | false | 2019-07-19T15:25:33.745282Z | 2021-12-23T19:52:16.428429Z | [More info about Agent Tesla on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/malware--1db42657-baba-4ada-a07b-a55d21bfdb9f) | ### email + *** Query SEKOIA.IO Intelligence Center for information about this indicator. No information is returned if the value is not a known by SEKOIA.IO as an indicator (IoC). STIX IDs can be resolved from SEKOIA.IO Intelligence Center application. @@ -8874,6 +8919,7 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Base Command `email` + #### Input | **Argument Name** | **Description** | **Required** | @@ -8943,8 +8989,11 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf | DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | #### Command example + ```!email email="eicar@sekoia.io"``` + #### Context Example + ```json { "DBotScore": { @@ -9174,12 +9223,14 @@ Query SEKOIA.IO Intelligence Center for information about this indicator. No inf #### Human Readable Output >### Indicator eicar@sekoia.io is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| EICAR Unit of SEKOIA | This Intrusion Set is known to be operated by SEKOIA by its EICAR unit. This unit aims at creating fictitious environment mimicking real attackers to present how threat intelligence can help real organizations to protect themselves.
| intrusion-set | EICAR,
TEST EICAR SEKOIA.IO,
EICAR Unit of SEKOIA | Simulation of real Threat Actor for Test purpose | false | 2020-05-26T13:18:26.429787Z | 2020-06-02T13:28:51.131904Z | [More info about EICAR Unit of SEKOIA on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/intrusion-set--4d1fd514-d9a4-45f3-988a-d811df72df2f) | ### GetIndicatorContext + *** Query SEKOIA.IO Intelligence Center for context around this indicator @@ -9187,6 +9238,7 @@ Query SEKOIA.IO Intelligence Center for context around this indicator #### Base Command `GetIndicatorContext` + #### Input | **Argument Name** | **Description** | **Required** | @@ -9261,8 +9313,11 @@ Query SEKOIA.IO Intelligence Center for context around this indicator | File.SHA256 | String | The SHA256 hash of the file. | #### Command example + ```!GetIndicatorContext value="eicar@sekoia.io" type="email-addr"``` + #### Context Example + ```json { "DBotScore": { @@ -9492,6 +9547,7 @@ Query SEKOIA.IO Intelligence Center for context around this indicator #### Human Readable Output >### Indicator eicar@sekoia.io is linked to the following: + >|name|description|type|aliases|goals|revoked|created|modified|more_info| >|---|---|---|---|---|---|---|---|---| >| EICAR Unit of SEKOIA | This Intrusion Set is known to be operated by SEKOIA by its EICAR unit. This unit aims at creating fictitious environment mimicking real attackers to present how threat intelligence can help real organizations to protect themselves.
| intrusion-set | EICAR,
TEST EICAR SEKOIA.IO,
EICAR Unit of SEKOIA | Simulation of real Threat Actor for Test purpose | false | 2020-05-26T13:18:26.429787Z | 2020-06-02T13:28:51.131904Z | [More info about EICAR Unit of SEKOIA on SEKOIA.IO](https://app.sekoia.io/intelligence/objects/intrusion-set--4d1fd514-d9a4-45f3-988a-d811df72df2f) | diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py index 0c92775b12ca..0a00d92e6552 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.py @@ -1,5 +1,6 @@ import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 + """SEKOIA.IO Integration for Cortex XSOAR (aka Demisto) """ import ipaddress @@ -63,9 +64,7 @@ def get_validate_resource(self) -> str: ) return "ok" except DemistoException as e: - raise DemistoException( - f"{INTEGRATION_NAME} error: the request failed due to: {e}" - ) + raise DemistoException(f"{INTEGRATION_NAME} error: the request failed due to: {e}") def get_observable(self, value: str, indicator_type: str) -> dict: """Find observable matching the given value @@ -216,54 +215,32 @@ def get_tlp(object_marking_refs: list[str], stix_bundle: dict) -> str: """ for object_marking_ref in object_marking_refs: for stix_object in stix_bundle["objects"]: - if ( - stix_object["id"] == object_marking_ref - and stix_object.get("definition_type") == "tlp" - ): + if stix_object["id"] == object_marking_ref and stix_object.get("definition_type") == "tlp": return stix_object["definition"]["tlp"] return "red" -def get_stix_object_reputation( - stix_bundle: dict, stix_object: dict -) -> Optional[CommandResults]: +def get_stix_object_reputation(stix_bundle: dict, stix_object: dict) -> Optional[CommandResults]: """ " Transform a STIX object into a Cortex XSOAR indicator """ reputation_score: int = get_reputation_score(stix_object.get("indicator_types", [])) - reliability_score: str = get_reliability_score( - int(stix_object.get("confidence", -1)) - ) + reliability_score: str = get_reliability_score(int(stix_object.get("confidence", -1))) tlp: str = get_tlp(stix_object.get("object_marking_refs", []), stix_bundle) - indicator_value: str | None = extract_indicator_from_pattern( - stix_object.get("pattern", None) - ) or stix_object.get("name") - - if ( - "ipv4-addr" in stix_object["x_ic_observable_types"] - or "ipv6-addr" in stix_object["x_ic_observable_types"] - ): - return get_ip_indicator_reputation( - indicator_value, stix_object, reputation_score, reliability_score, tlp - ) + indicator_value: str | None = extract_indicator_from_pattern(stix_object.get("pattern", None)) or stix_object.get("name") + + if "ipv4-addr" in stix_object["x_ic_observable_types"] or "ipv6-addr" in stix_object["x_ic_observable_types"]: + return get_ip_indicator_reputation(indicator_value, stix_object, reputation_score, reliability_score, tlp) if "file" in stix_object["x_ic_observable_types"]: - return get_file_indicator_reputation( - stix_object, reputation_score, reliability_score, tlp - ) + return get_file_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) if "domain-name" in stix_object["x_ic_observable_types"]: - return get_domain_indicator_reputation( - stix_object, reputation_score, reliability_score, tlp - ) + return get_domain_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) if "url" in stix_object["x_ic_observable_types"]: - return get_url_indicator_reputation( - stix_object, reputation_score, reliability_score, tlp - ) + return get_url_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) if "email-addr" in stix_object["x_ic_observable_types"]: - return get_email_indicator_reputation( - stix_object, reputation_score, reliability_score, tlp - ) + return get_email_indicator_reputation(stix_object, reputation_score, reliability_score, tlp) return None @@ -299,9 +276,7 @@ def get_ip_indicator_reputation( ) -def get_file_indicator_reputation( - stix_object: dict, reputation_score: int, reliability_score: str, tlp: str -) -> CommandResults: +def get_file_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: """ Return stix_object of type file as indicator """ @@ -332,9 +307,7 @@ def get_file_indicator_reputation( ) -def get_domain_indicator_reputation( - stix_object: dict, reputation_score: int, reliability_score: str, tlp: str -) -> CommandResults: +def get_domain_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: """ Return stix_object of type domain as indicator """ @@ -362,9 +335,7 @@ def get_domain_indicator_reputation( ) -def get_url_indicator_reputation( - stix_object: dict, reputation_score: int, reliability_score: str, tlp: str -) -> CommandResults: +def get_url_indicator_reputation(stix_object: dict, reputation_score: int, reliability_score: str, tlp: str) -> CommandResults: """ Return stix_object of type url as indicator """ @@ -468,9 +439,7 @@ def indicator_context_to_markdown(indicator_context: dict) -> str: if linked_stix_objects_refs: # Retrieve STIX objects which are the target in the relationship linked_stix_objects = [ - stix_object - for stix_object in stix_bundle["objects"] - if stix_object["id"] in linked_stix_objects_refs + stix_object for stix_object in stix_bundle["objects"] if stix_object["id"] in linked_stix_objects_refs ] # Add "more_info" link, which redirect to SEKOIA Intelligence Center @@ -499,9 +468,7 @@ def extract_indicators(indicator: dict, indicator_context: dict) -> list: "name": indicator["value"], "x_ic_observable_types": [indicator["type"]], } - object_reputation = get_stix_object_reputation( - stix_bundle={}, stix_object=stix_object - ) + object_reputation = get_stix_object_reputation(stix_bundle={}, stix_object=stix_object) return [object_reputation] # Indicator context for known indicator @@ -573,24 +540,18 @@ def get_observable_command(client: Client, args: dict[str, str]) -> CommandResul indicator_value = args.get("value") indicator_type = args.get("type") if not indicator_value or not indicator_type: - raise ValueError( - f"incomplete command for value {indicator_value} and type {indicator_type}" - ) + raise ValueError(f"incomplete command for value {indicator_value} and type {indicator_type}") result = client.get_observable(value=indicator_value, indicator_type=indicator_type) indicator = {"value": indicator_value, "type": indicator_type} outputs = {"indicator": indicator, "items": result.get("items", [])} if result["items"] == []: - markdown = ( - f"### {indicator_value} of type {indicator_type} is an unknown observable." - ) + markdown = f"### {indicator_value} of type {indicator_type} is an unknown observable." else: table_title = f'Observable {result["items"][0].get("value")}' table_headers = ["modified", "created"] - markdown = tableToMarkdown( - table_title, result["items"][0], headers=table_headers - ) + markdown = tableToMarkdown(table_title, result["items"][0], headers=table_headers) table_headers = ["valid_from", "valid_until", "name"] markdown += tableToMarkdown( "Associated tags", @@ -631,9 +592,7 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult indicator_value = args.get("value") indicator_type = args.get("type") if not indicator_value or not indicator_type: - raise ValueError( - f"incomplete command for value {indicator_value} and type {indicator_type}" - ) + raise ValueError(f"incomplete command for value {indicator_value} and type {indicator_type}") result = client.get_indicator(value=indicator_value, indicator_type=indicator_type) indicator = {"value": indicator_value, "type": indicator_type} @@ -641,9 +600,7 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult # Format output if result["items"] == []: - markdown = ( - f"### {indicator_value} of type {indicator_type} is an unknown indicator." - ) + markdown = f"### {indicator_value} of type {indicator_type} is an unknown indicator." else: markdown = ( f'### Indicator {result["items"][0].get("name")}' @@ -669,9 +626,7 @@ def get_indicator_command(client: Client, args: dict[str, str]) -> CommandResult ) -def get_indicator_context_command( - client: Client, args: dict[str, str] -) -> list[CommandResults]: +def get_indicator_context_command(client: Client, args: dict[str, str]) -> list[CommandResults]: """ip command: Returns IP reputation for a list of IPs :type client: ``Client`` @@ -692,9 +647,7 @@ def get_indicator_context_command( if not indicator["value"] or not indicator["type"]: raise ValueError(f"incomplete command for {indicator}") - indicator_context = client.get_indicator_context( - value=indicator["value"], indicator_type=indicator["type"] - ) + indicator_context = client.get_indicator_context(value=indicator["value"], indicator_type=indicator["type"]) outputs = {"indicator": indicator, "items": indicator_context.get("items", [])} if indicator_context["items"] == []: @@ -704,9 +657,7 @@ def get_indicator_context_command( markdown = indicator_context_to_markdown(indicator_context) # Extract STIX object type indicator from the STIX bundles - command_results_list: list = extract_indicators( - indicator=indicator, indicator_context=indicator_context - ) + command_results_list: list = extract_indicators(indicator=indicator, indicator_context=indicator_context) command_results_list.append( CommandResults( @@ -725,7 +676,7 @@ def ip_command(client: Client, args: dict[str, str]) -> list[CommandResults]: This command is a wrapper around the `get_indicator_context_command` """ ips = argToList(args["ip"]) - results: list[CommandResults] = list() + results: list[CommandResults] = [] for ip in ips: indicator = {"value": ip, "type": ip_version(ip)} @@ -733,15 +684,13 @@ def ip_command(client: Client, args: dict[str, str]) -> list[CommandResults]: return results -def reputation_command( - client: Client, args: dict[str, str], indicator_type -) -> list[CommandResults]: +def reputation_command(client: Client, args: dict[str, str], indicator_type) -> list[CommandResults]: """reputation command: Returns reputation for a list of indicator This command is a wrapper around the `get_indicator_context_command` """ indicators = argToList(args[indicator_type]) - results: list[CommandResults] = list() + results: list[CommandResults] = [] ic_type = REPUTATION_MAPPING.get(indicator_type) if not ic_type: @@ -776,9 +725,7 @@ def main() -> None: try: headers = {"Authorization": f"Bearer {api_key}"} - client = Client( - base_url=BASE_URL, verify=verify_certificate, headers=headers, proxy=proxy - ) + client = Client(base_url=BASE_URL, verify=verify_certificate, headers=headers, proxy=proxy) if demisto.command() == "test-module": # This is the call made when pressing the integration Test button. @@ -799,11 +746,7 @@ def main() -> None: return_results(ip_command(client, demisto.args())) elif demisto.command() in ["url", "domain", "file", "email"]: - return_results( - reputation_command( - client, demisto.args(), indicator_type=demisto.command() - ) - ) + return_results(reputation_command(client, demisto.args(), indicator_type=demisto.command())) # Log exceptions and return errors except Exception as e: diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.yml b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.yml index 4e8e632312b7..1ad7630128de 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.yml +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter.yml @@ -21,12 +21,12 @@ configuration: type: 4 - display: Trust any certificate (not secure) name: insecure - type: 8 required: false + type: 8 - display: Use system proxy settings name: proxy - type: 8 required: false + type: 8 - name: integrationReliability additionalinfo: Reliability of the source providing the intelligence data. defaultvalue: C - Fairly reliable @@ -1256,7 +1256,7 @@ script: script: '-' type: python subtype: python3 - dockerimage: demisto/py3-tools:1.0.0.77497 + dockerimage: demisto/py3-tools:1.0.0.79242 fromversion: 6.2.0 tests: - No tests (auto formatted) diff --git a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py index 10090fc153e2..3ba1b4120d93 100644 --- a/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py +++ b/Packs/SEKOIAIntelligenceCenter/Integrations/SEKOIAIntelligenceCenter/SEKOIAIntelligenceCenter_test.py @@ -46,7 +46,7 @@ def client(): ], ) def test_extract_indicator_from_pattern(input, output): - SEKOIAIntelligenceCenter.extract_indicator_from_pattern(input) == output + assert SEKOIAIntelligenceCenter.extract_indicator_from_pattern(input) == output def test_extract_indicator_from_pattern_wrong_pattern(client): @@ -62,13 +62,10 @@ def test_extract_indicator_from_pattern_wrong_pattern(client): ("email-addr", "does-not-exist@sekoia.io", "test_data/observable_unknown.json"), ], ) -def test_get_observables( - client, requests_mock, indicator_value, indicator_type, json_test_file -): +def test_get_observables(client, requests_mock, indicator_value, indicator_type, json_test_file): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL - + f"/v2/inthreat/observables?match[value]={indicator_value}&match[type]={indicator_type}", + MOCK_URL + f"/v2/inthreat/observables?match[value]={indicator_value}&match[type]={indicator_type}", json=mock_response, ) @@ -107,9 +104,7 @@ def test_test_module_ok(client, requests_mock): ], ) def test_test_module_nok(client, requests_mock, api_response, expected): - requests_mock.get( - MOCK_URL + "/v1/auth/validate", json=api_response, status_code=401 - ) + requests_mock.get(MOCK_URL + "/v1/auth/validate", json=api_response, status_code=401) assert expected in SEKOIAIntelligenceCenter.test_module(client) @@ -139,16 +134,13 @@ def test_get_observables_with_credentials(client): ("email-addr", "does-not-exist@sekoia.io", "test_data/indicator_unknown.json"), ], ) -def test_get_indicator( - client, requests_mock, indicator_value, indicator_type, json_test_file -): +def test_get_indicator(client, requests_mock, indicator_value, indicator_type, json_test_file): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL - + f"/v2/inthreat/indicators?value={indicator_value}&type={indicator_type}", + MOCK_URL + f"/v2/inthreat/indicators?value={indicator_value}&type={indicator_type}", json=mock_response, ) - args = {"value": {indicator_value}, "type": {indicator_type}} + args = {"value": indicator_value, "type": indicator_type} result = SEKOIAIntelligenceCenter.get_indicator_command(client=client, args=args) @@ -178,9 +170,7 @@ def test_get_indicator_with_credentials(client): (SEKOIAIntelligenceCenter.get_indicator_context_command, "", "ipv4-addr"), ], ) -def test_get_indicator_context_incomplete( - client, command, indicator_type, indicator_value -): +def test_get_indicator_context_incomplete(client, command, indicator_type, indicator_value): args = {"value": indicator_value, "type": indicator_type} with pytest.raises(ValueError): command(client=client, args=args) @@ -209,20 +199,15 @@ def test_get_indicator_context_incomplete( ), ], ) -def test_get_indicator_context( - client, requests_mock, indicator_type, indicator_value, json_test_file -): +def test_get_indicator_context(client, requests_mock, indicator_type, indicator_value, json_test_file): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL - + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", + MOCK_URL + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", json=mock_response, ) args = {"value": indicator_value, "type": indicator_type} - command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( - client=client, args=args - ) + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command(client=client, args=args) for result in command_results: assert result.outputs != [] assert result.to_context != [] @@ -234,20 +219,15 @@ def test_get_indicator_context( ("ipv4-addr", "1.1.1.1", "test_data/indicator_context_unknown.json"), ], ) -def test_get_indicator_context_unknown_indicator( - client, requests_mock, indicator_type, indicator_value, json_test_file -): +def test_get_indicator_context_unknown_indicator(client, requests_mock, indicator_type, indicator_value, json_test_file): mock_response = util_load_json(json_test_file) requests_mock.get( - MOCK_URL - + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", + MOCK_URL + f"/v2/inthreat/indicators/context?value={indicator_value}&type={indicator_type}", json=mock_response, ) args = {"value": indicator_value, "type": indicator_type} - command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( - client=client, args=args - ) + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command(client=client, args=args) for result in command_results: assert result.outputs != [] assert result.to_context != [] @@ -267,13 +247,9 @@ def test_get_indicator_context_unknown_indicator( ("domain-name", "buike.duckdns.org"), ], ) -def test_get_indicator_context_with_credentials( - client, indicator_value, indicator_type -): +def test_get_indicator_context_with_credentials(client, indicator_value, indicator_type): args = {"value": indicator_value, "type": indicator_type} - command_results = SEKOIAIntelligenceCenter.get_indicator_context_command( - client=client, args=args - ) + command_results = SEKOIAIntelligenceCenter.get_indicator_context_command(client=client, args=args) for result in command_results: assert result.outputs != [] @@ -307,7 +283,7 @@ def test_get_reliability_score(input: int, output: str): ) def test_get_tlp(input): marking_definition: str = "marking-definition--123" - stix_bundle: dict[list[dict]] = { + stix_bundle: dict[str, list[dict]] = { "objects": [ { "id": "abc", @@ -325,7 +301,7 @@ def test_get_tlp(input): def test_get_tlp_not_found(): marking_definition: str = "marking-definition--123" - stix_bundle: dict[list[dict]] = { + stix_bundle: dict[str, list[dict]] = { "objects": [ { "id": "abc", @@ -347,7 +323,7 @@ def test_get_tlp_not_found(): ("", Common.DBotScore.NONE), ], ) -def test_get_reputation_score(input: list, output: int): +def test_get_reputation_score(input: str, output: int): assert SEKOIAIntelligenceCenter.get_reputation_score([input]) == output @@ -368,18 +344,15 @@ def test_get_reputation_score(input: list, output: int): ), ], ) -def test_ip_command( - client, requests_mock, indicator_type, indicator_value, json_test_file -): +def test_ip_command(client, requests_mock, indicator_type, indicator_value, json_test_file): mock_response = util_load_json(json_test_file) + api_url = urljoin(MOCK_URL, "/v2/inthreat/indicators/context",) requests_mock.get( - MOCK_URL + "/v2/inthreat/indicators/context", + api_url, json=mock_response, ) - command_results = SEKOIAIntelligenceCenter.ip_command( - client=client, args={"ip": indicator_value} - ) + command_results = SEKOIAIntelligenceCenter.ip_command(client=client, args={"ip": indicator_value}) for result in command_results: assert result.outputs != [] @@ -421,9 +394,7 @@ def test_reputation_command(client, input, command, requests_mock): json=mock_response, ) args = {command: input} - command_results = SEKOIAIntelligenceCenter.reputation_command( - client=client, args=args, indicator_type=command - ) + command_results = SEKOIAIntelligenceCenter.reputation_command(client=client, args=args, indicator_type=command) for result in command_results: assert result.outputs != [] @@ -434,6 +405,4 @@ def test_reputation_command_wrong_type(client): indicator_type = "wrong-type" args = {indicator_type: "1.1.1.1"} with pytest.raises(ValueError): - SEKOIAIntelligenceCenter.reputation_command( - client=client, args=args, indicator_type=indicator_type - ) + SEKOIAIntelligenceCenter.reputation_command(client=client, args=args, indicator_type=indicator_type)