diff --git a/.circleci/config.yml b/.circleci/config.yml index 6317c133dacd..0ddc968d2e54 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,9 +5,9 @@ jobs: - image: devdemisto/content-build:3.0.0.7332 # disable-secrets-detection parallelism: 2 environment: - CONTENT_VERSION: "20.6.0" + CONTENT_VERSION: "20.6.1" SERVER_VERSION: "5.5.0" - GIT_SHA1: "63646dff0fba977f91d6d9fc2d7fd233bfb5561b" # guardrails-disable-line disable-secrets-detection + GIT_SHA1: "85b138633bcc10cedb4d6f4ed6e7074c28dd13d7" # guardrails-disable-line disable-secrets-detection steps: - checkout - setup_remote_docker diff --git a/Packs/AttivoBotsink/Integrations/AttivoBotsink/AttivoBotsink.py b/Packs/AttivoBotsink/Integrations/AttivoBotsink/AttivoBotsink.py index 92439c404020..eed84a2d038c 100644 --- a/Packs/AttivoBotsink/Integrations/AttivoBotsink/AttivoBotsink.py +++ b/Packs/AttivoBotsink/Integrations/AttivoBotsink/AttivoBotsink.py @@ -72,7 +72,11 @@ def do_request(self, url, data=None, headers=None, files=None, method=None, cont demisto.error("Type is: {type}".format(type=e.__class__.__name__)) if r is not None and r.content: - return r.json() + try: + json_res = r.json() + except ValueError: + return_error('Failed deserializing response JSON - {}'.format(r.content)) + return json_res else: return None diff --git a/Packs/AttivoBotsink/ReleaseNotes/1_0_1.md b/Packs/AttivoBotsink/ReleaseNotes/1_0_1.md new file mode 100644 index 000000000000..364c41f19e86 --- /dev/null +++ b/Packs/AttivoBotsink/ReleaseNotes/1_0_1.md @@ -0,0 +1,4 @@ + +#### Integrations +##### Attivo Botsink +- Fixed an issue where errors were not handled as expected. diff --git a/Packs/AttivoBotsink/pack_metadata.json b/Packs/AttivoBotsink/pack_metadata.json index 2515905137d4..25eaafbde67e 100644 --- a/Packs/AttivoBotsink/pack_metadata.json +++ b/Packs/AttivoBotsink/pack_metadata.json @@ -1,16 +1,16 @@ { - "name": "Attivo Botsink", - "description": "Network-based Threat Deception for Post-Compromise Threat Detection.", - "support": "xsoar", - "currentVersion": "1.0.0", - "author": "Cortex XSOAR", - "url": "https://www.paloaltonetworks.com/cortex", - "email": "", - "created": "2020-04-14T00:00:00Z", - "categories": [ - "Deception" - ], - "tags": [], - "useCases": [], - "keywords": [] -} + "name": "Attivo Botsink", + "description": "Network-based Threat Deception for Post-Compromise Threat Detection.", + "support": "xsoar", + "currentVersion": "1.0.1", + "author": "Cortex XSOAR", + "url": "https://www.paloaltonetworks.com/cortex", + "email": "", + "created": "2020-04-14T00:00:00Z", + "categories": [ + "Deception" + ], + "tags": [], + "useCases": [], + "keywords": [] +} \ No newline at end of file diff --git a/Packs/Base/ReleaseNotes/1_0_14.md b/Packs/Base/ReleaseNotes/1_0_14.md new file mode 100644 index 000000000000..4230fe7aea67 --- /dev/null +++ b/Packs/Base/ReleaseNotes/1_0_14.md @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/Packs/Base/ReleaseNotes/1_0_15.md b/Packs/Base/ReleaseNotes/1_0_15.md new file mode 100644 index 000000000000..c1450dc8f566 --- /dev/null +++ b/Packs/Base/ReleaseNotes/1_0_15.md @@ -0,0 +1,5 @@ + +#### Scripts +##### CommonServerPython + - Fixed an issue where the ***to_context*** function did not return the proper outputs when the **CommandResult** object was supplied with only ***readable_outputs***. + - Fixed and issue where ***to_context*** function returned null instead of an empty list when supplied with empty outputs. \ No newline at end of file diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py index 85d6d71cddaf..5c0619fc0f9c 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py @@ -2581,10 +2581,12 @@ class CommandResults: :return: None :rtype: ``None`` """ - def __init__(self, outputs_prefix, outputs_key_field, outputs, indicators=None, readable_output=None, + def __init__(self, outputs_prefix=None, outputs_key_field=None, outputs=None, indicators=None, readable_output=None, raw_response=None): - # type: (str, str, object, list, str, object) -> None + if raw_response is None: + raw_response = outputs + self.indicators = indicators self.outputs_prefix = outputs_prefix @@ -2596,7 +2598,10 @@ def __init__(self, outputs_prefix, outputs_key_field, outputs, indicators=None, def to_context(self): outputs = {} # type: dict - human_readable = None + if self.readable_output: + human_readable = self.readable_output + else: + human_readable = None raw_response = None if self.indicators: @@ -2612,16 +2617,10 @@ def to_context(self): if self.raw_response: raw_response = self.raw_response - if self.outputs: + if self.outputs is not None: if not self.readable_output: # if markdown is not provided then create table by default human_readable = tableToMarkdown('Results', self.outputs) - else: - human_readable = self.readable_output - - if not self.raw_response: - raw_response = self.outputs - if self.outputs_prefix and self.outputs_key_field: # if both prefix and key field provided then create DT key outputs_key = '{0}(val.{1} == obj.{1})'.format(self.outputs_prefix, self.outputs_key_field) @@ -2631,7 +2630,6 @@ def to_context(self): outputs[outputs_key] = self.outputs else: outputs = self.outputs - human_readable = self.readable_output # prefix and key field not provided, human readable should return_entry = { 'Type': EntryType.NOTE, diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py index aee1063f1a63..2ce690d4a598 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py @@ -460,19 +460,12 @@ def test_argToList(): test2 = 'a,b,c' test3 = '["a","b","c"]' test4 = 'a;b;c' - test5 = 1 - test6 = '1' - test7 = True results = [argToList(test1), argToList(test2), argToList(test2, ','), argToList(test3), argToList(test4, ';')] for result in results: assert expected == result, 'argToList test failed, {} is not equal to {}'.format(str(result), str(expected)) - assert argToList(test5) == [1] - assert argToList(test6) == ['1'] - assert argToList(test7) == [True] - def test_remove_nulls(): temp_dictionary = {"a": "b", "c": 4, "e": [], "f": {}, "g": None, "h": "", "i": [1], "k": ()} @@ -922,6 +915,43 @@ def test_file_indicators(self): class TestCommandResults: + def test_readable_only_context(self): + """ + Given: + - Markdown entry to CommandResults + + When: + - Returning results + + Then: + - Validate HumanReadable exists + """ + from CommonServerPython import CommandResults + markdown = '## Something' + context = CommandResults(readable_output=markdown).to_context() + assert context.get('HumanReadable') == markdown + + def test_empty_outputs(self): + """ + Given: + - Empty outputs + + When: + - Returning results + + Then: + - Validate EntryContext key value + + """ + from CommonServerPython import CommandResults + res = CommandResults( + outputs_prefix='FoundIndicators', + outputs_key_field='value', + outputs=[] + ) + context = res.to_context() + assert {'FoundIndicators(val.value == obj.value)': []} == context.get('EntryContext') + def test_return_command_results(self): from CommonServerPython import Common, CommandResults, EntryFormat, EntryType, DBotScoreType @@ -1109,7 +1139,7 @@ def test_return_list_of_items_the_old_way(self): raw_response=tickets ) - assert results.to_context() == { + assert sorted(results.to_context()) == sorted({ 'Type': EntryType.NOTE, 'ContentsFormat': EntryFormat.JSON, 'Contents': tickets, @@ -1117,7 +1147,7 @@ def test_return_list_of_items_the_old_way(self): 'EntryContext': { 'Jira.Ticket(val.ticket_id == obj.ticket_id)': tickets } - } + }) def test_create_dbot_score_with_invalid_score(self): from CommonServerPython import Common, DBotScoreType diff --git a/Packs/Base/Scripts/DBotSuggestClassifierMapping/DBotSuggestClassifierMapping.py b/Packs/Base/Scripts/DBotSuggestClassifierMapping/DBotSuggestClassifierMapping.py index f805b265b40d..d094968dfc75 100644 --- a/Packs/Base/Scripts/DBotSuggestClassifierMapping/DBotSuggestClassifierMapping.py +++ b/Packs/Base/Scripts/DBotSuggestClassifierMapping/DBotSuggestClassifierMapping.py @@ -370,19 +370,19 @@ def validate(self, validator_name, field_name, value, json_field_name=None): return validate_func(field_name, value, json_field_name) -def is_sublist_of_list(s, l): +def is_sublist_of_list(s, lst): sub_set = False if s == []: sub_set = True - elif s == l: + elif s == lst: sub_set = True - elif len(s) > len(l): + elif len(s) > len(lst): sub_set = False else: - for i in range(len(l)): - if l[i] == s[0]: + for i in range(len(lst)): + if lst[i] == s[0]: n = 1 - while (n < len(s)) and (i + n) < len(l) and (l[i + n] == s[n]): + while (n < len(s)) and (i + n) < len(lst) and (lst[i + n] == s[n]): n += 1 if n == len(s): diff --git a/Packs/Base/pack_metadata.json b/Packs/Base/pack_metadata.json index 23c3ccf1fb72..bed135bbb551 100644 --- a/Packs/Base/pack_metadata.json +++ b/Packs/Base/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Base", "description": "The base pack for Cortex XSOAR.", "support": "xsoar", - "currentVersion": "1.0.13", + "currentVersion": "1.0.15", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", @@ -17,4 +17,4 @@ "common" ], "dependencies": {} -} +} \ No newline at end of file diff --git a/Packs/CommonScripts/ReleaseNotes/1_1_10.md b/Packs/CommonScripts/ReleaseNotes/1_1_10.md new file mode 100644 index 000000000000..fbf5d0b98269 --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_1_10.md @@ -0,0 +1,4 @@ + +#### Scripts +##### ParseEmailFiles +- Fixed an issue where errors were not handled as expected. diff --git a/Packs/CommonScripts/Scripts/ExtractDomainFromUrlFormat/ExtractDomainFromUrlFormat_test.py b/Packs/CommonScripts/Scripts/ExtractDomainFromUrlFormat/ExtractDomainFromUrlFormat_test.py index 553ffbfddc8f..ec2318e4cb15 100644 --- a/Packs/CommonScripts/Scripts/ExtractDomainFromUrlFormat/ExtractDomainFromUrlFormat_test.py +++ b/Packs/CommonScripts/Scripts/ExtractDomainFromUrlFormat/ExtractDomainFromUrlFormat_test.py @@ -5,16 +5,17 @@ @pytest.mark.parametrize('input,domain', [ - ('http://this.is.test.com', 'test.com'), - ('http:example.com', 'example.com'), - ('http:\\\\example.com', 'example.com'), - ('https://caseapi.phishlabs.com', 'phishlabs.com'), - # output needs to be bytes string utf-8 encoded (otherwise python loop demisto.results fails) - (u'www.bücher.de', u'bücher.de'.encode('utf-8')), - ('https://urldefense.proofpoint.com/v2/url?u=http-3A__go.getpostman.com_y4wULsdG0h0DDMY0Dv00100&d=DwMFaQ&c=ywDJJevdGcjv4rm9P3FcNg&r=s5kA2oIAQRXsacJiBKmTORIWyRN39ZKhobje2GyRgNs&m=vN1dVSiZvEoM9oExtQqEptm9Dbvq9tnjACDZzrBLaWI&s=zroN7KQdBCPBOfhOmv5SP1DDzZKZ1y9I3x4STS5PbHA&e=', 'getpostman.com'), # noqa: E501 - ('hxxps://www[.]demisto[.]com', 'demisto.com'), - ('https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftwitter.com%2FPhilipsBeLux&data=02|01||cb2462dc8640484baf7608d638d2a698|1a407a2d76754d178692b3ac285306e4|0|0|636758874714819880&sdata=dnJiphWFhnAKsk5Ps0bj0p%2FvXVo8TpidtGZcW6t8lDQ%3D&reserved=0%3E%5bcid:image003.gif@01CF4D7F.1DF62650%5d%3C', 'twitter.com'), # noqa: E501 disable-secrets-detection - ]) # noqa: E124 + ('http://this.is.test.com', 'test.com'), + ('http:example.com', 'example.com'), + ('http:\\\\example.com', 'example.com'), + ('https://caseapi.phishlabs.com', 'phishlabs.com'), + # output needs to be bytes string utf-8 encoded (otherwise python loop demisto.results fails) + (u'www.bücher.de', u'bücher.de'.encode('utf-8')), + ('https://urldefense.proofpoint.com/v2/url?u=http-3A__go.getpostman.com_y4wULsdG0h0DDMY0Dv00100&d=DwMFaQ&c=ywDJJevdGcjv4rm9P3FcNg&r=s5kA2oIAQRXsacJiBKmTORIWyRN39ZKhobje2GyRgNs&m=vN1dVSiZvEoM9oExtQqEptm9Dbvq9tnjACDZzrBLaWI&s=zroN7KQdBCPBOfhOmv5SP1DDzZKZ1y9I3x4STS5PbHA&e=', 'getpostman.com'), # noqa: E501 + ('hxxps://www[.]demisto[.]com', 'demisto.com'), + ('https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftwitter.com%2FPhilipsBeLux&data=02|01||cb2462dc8640484baf7608d638d2a698|1a407a2d76754d178692b3ac285306e4|0|0|636758874714819880&sdata=dnJiphWFhnAKsk5Ps0bj0p%2FvXVo8TpidtGZcW6t8lDQ%3D&reserved=0%3E%5bcid:image003.gif@01CF4D7F.1DF62650%5d%3C', 'twitter.com'), # noqa: E501 disable-secrets-detection +] +) # noqa: E124 def test_extract_domain(input, domain): res = extract_domain(input) assert res == domain diff --git a/Packs/CommonScripts/Scripts/ParseEmailFiles/ParseEmailFiles.py b/Packs/CommonScripts/Scripts/ParseEmailFiles/ParseEmailFiles.py index e5ae69e3b843..d23498ef3a1d 100644 --- a/Packs/CommonScripts/Scripts/ParseEmailFiles/ParseEmailFiles.py +++ b/Packs/CommonScripts/Scripts/ParseEmailFiles/ParseEmailFiles.py @@ -3181,9 +3181,8 @@ def parse_email_headers(header, raw=False): def get_msg_mail_format(msg_dict): try: return msg_dict.get('Headers', 'Content-type:').split('Content-type:')[1].split(';')[0] - except ValueError: - return '' - except IndexError: + except Exception as e: + demisto.debug('Got exception while trying to get msg mail format - {}'.format(str(e))) return '' diff --git a/Packs/CommonScripts/Scripts/ParseEmailFiles/parse_email_files_test.py b/Packs/CommonScripts/Scripts/ParseEmailFiles/parse_email_files_test.py index b4d1cde93533..3e0277926261 100644 --- a/Packs/CommonScripts/Scripts/ParseEmailFiles/parse_email_files_test.py +++ b/Packs/CommonScripts/Scripts/ParseEmailFiles/parse_email_files_test.py @@ -562,15 +562,20 @@ def test_no_content_type_file(mocker): def test_get_msg_mail_format(): - format = get_msg_mail_format({ + msg_mail_format = get_msg_mail_format({ 'Headers': 'Content-type:text/plain;' }) - assert format == 'text/plain' + assert msg_mail_format == 'text/plain' - format = get_msg_mail_format({ + msg_mail_format = get_msg_mail_format({ 'Something': 'else' }) - assert format == '' + assert msg_mail_format == '' + + msg_mail_format = get_msg_mail_format({ + 'Headers': None + }) + assert msg_mail_format == '' def test_no_content_file(mocker): diff --git a/Packs/CommonScripts/pack_metadata.json b/Packs/CommonScripts/pack_metadata.json index fb48a310adb9..b19efed74f01 100644 --- a/Packs/CommonScripts/pack_metadata.json +++ b/Packs/CommonScripts/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Common Scripts", "description": "Frequently used scripts pack.", "support": "xsoar", - "currentVersion": "1.1.9", + "currentVersion": "1.1.10", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.py b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.py index 9f9330aeb634..993036647260 100644 --- a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.py +++ b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.py @@ -3,10 +3,12 @@ from CommonServerUserPython import * # noqa: E402 lgtm [py/polluting-import] import requests +import traceback from asyncio import Event, create_task, sleep, run from contextlib import asynccontextmanager from aiohttp import ClientSession, TCPConnector from typing import Dict, AsyncGenerator, AsyncIterator +from collections import deque requests.packages.urllib3.disable_warnings() @@ -116,6 +118,7 @@ async def _discover_refresh_stream(self, event: Event) -> None: raise ValueError(f'Did not get event stream resources - {str(discover_stream_response)}') resource = resources[0] self.data_feed_url = resource.get('dataFeedURL') + demisto.debug(f'Discovered data feed URL: {self.data_feed_url}') self.session_token = resource.get('sessionToken', {}).get('token') refresh_url = resource.get('refreshActiveSessionURL') client.refresh_stream_url = refresh_url @@ -123,40 +126,64 @@ async def _discover_refresh_stream(self, event: Event) -> None: await sleep(MINUTES_25) event.clear() - async def fetch_event(self, offset: int = 0, event_type: str = '') -> AsyncGenerator[Dict, None]: + async def fetch_event(self, initial_offset: int = 0, event_type: str = '') -> AsyncGenerator[Dict, None]: """Retrieves events from a CrowdStrike Falcon stream starting from given offset. Args: - offset (int): Stream offset to start the fetch from. + initial_offset (int): Stream offset to start the fetch from. event_type (str): Stream event type to fetch. Yields: AsyncGenerator[Dict, None]: Event fetched from the stream. """ - demisto.debug('Fetching event') - event = Event() - create_task(self._discover_refresh_stream(event)) - demisto.debug('Waiting for stream discovery or refresh') - await event.wait() - demisto.debug('Done waiting for stream discovery or refresh') - async with ClientSession( - connector=TCPConnector(ssl=self.verify_ssl), - headers={'Authorization': f'Token {self.session_token}'}, - trust_env=self.proxy - ) as session: - try: - async with session.get(self.data_feed_url, params={'offset': offset, 'eventType': event_type}) as res: - demisto.debug(f'Fetched event: {res.content}') - async for line in res.content: - stripped_line = line.strip() - if stripped_line: - try: - yield json.loads(stripped_line) - except json.decoder.JSONDecodeError: - demisto.debug(f'Failed decoding event (skipping it) - {str(stripped_line)}') - except Exception as e: - demisto.debug(f'Failed to fetch event: {e} - Going to sleep for 10 seconds and then retry') - await sleep(10) + while True: + demisto.debug('Fetching event') + event = Event() + create_task(self._discover_refresh_stream(event)) + demisto.debug('Waiting for stream discovery or refresh') + await event.wait() + demisto.debug('Done waiting for stream discovery or refresh') + events_fetched = 0 + new_lines_fetched = 0 + last_fetch_stats_print = datetime.utcnow() + async with ClientSession( + connector=TCPConnector(ssl=self.verify_ssl), + headers={'Authorization': f'Token {self.session_token}'}, + trust_env=self.proxy, + timeout=None + ) as session: + try: + integration_context = demisto.getIntegrationContext() + offset = integration_context.get('offset', 0) or initial_offset + demisto.debug(f'Starting to fetch from offset {offset} events of type {event_type}') + async with session.get( + self.data_feed_url, + params={'offset': offset, 'eventType': event_type}, + timeout=None + ) as res: + demisto.debug(f'Fetched event: {res.content}') + async for line in res.content: + stripped_line = line.strip() + if stripped_line: + events_fetched += 1 + try: + yield json.loads(stripped_line) + except json.decoder.JSONDecodeError: + demisto.debug(f'Failed decoding event (skipping it) - {str(stripped_line)}') + else: + new_lines_fetched += 1 + if last_fetch_stats_print + timedelta(minutes=1) <= datetime.utcnow(): + demisto.info( + f'Fetched {events_fetched} events and' + f' {new_lines_fetched} new lines' + f' from the stream in the last minute.') + events_fetched = 0 + new_lines_fetched = 0 + last_fetch_stats_print = datetime.utcnow() + except Exception as e: + demisto.debug(f'Failed to fetch event: {e} - Going to sleep for 10 seconds and then retry -' + f' {traceback.format_exc()}') + await sleep(10) class RefreshToken: @@ -288,7 +315,9 @@ async def long_running_loop( offset: int, event_type: str, verify_ssl: bool, - proxy: bool + proxy: bool, + incident_type: str, + store_samples: bool = False ) -> None: """Connects to a CrowdStrike Falcon stream and fetches events from it in a loop. @@ -299,25 +328,57 @@ async def long_running_loop( stream (EventStream): CrowdStrike Falcon stream to fetch events from. offset (int): Stream offset to start the fetch from. event_type (str): Stream event type to fetch. - verify_ssl (bool): Whether the request should verify the SSL certificate. - proxy (bool): Whether to run the integration using the system proxy. + verify_ssl (bool): Whether the request should verify the SSL certificate or not. + proxy (bool): Whether to run the integration using the system proxy or not. + incident_type (str): Type of incident to create. + store_samples (bool): Whether to store sample events in the integration context or not. Returns: None: No data returned. """ - async with init_refresh_token(base_url, client_id, client_secret, verify_ssl, proxy) as refresh_token: - stream.set_refresh_token(refresh_token) - async for event in stream.fetch_event(offset=offset, event_type=event_type): - event_metadata = event.get('metadata', {}) - event_type = event_metadata.get('eventType', '') - event_offset = event_metadata.get('offset', '') - demisto.info(f'Fetching event with offset: {event_offset}') - incident_name = f'{event_type} - offset {event_offset}' - incident = [{ - 'name': incident_name, - 'details': json.dumps(event) - }] - demisto.createIncidents(incident) + try: + offset_to_store = offset + sample_events_to_store = deque(maxlen=20) # type: ignore[var-annotated] + last_integration_context_set = datetime.utcnow() + async with init_refresh_token(base_url, client_id, client_secret, verify_ssl, proxy) as refresh_token: + stream.set_refresh_token(refresh_token) + async for event in stream.fetch_event(initial_offset=offset, event_type=event_type): + event_metadata = event.get('metadata', {}) + event_type = event_metadata.get('eventType', '') + event_offset = event_metadata.get('offset', '') + demisto.info(f'Fetching event with offset: {event_offset}') + incident_name = f'{event_type} - offset {event_offset}' + event_dump = json.dumps(event) + incident = [{ + 'name': incident_name, + 'details': event_dump, + 'rawJSON': event_dump, + 'type': incident_type + }] + demisto.createIncidents(incident) + offset_to_store = int(event_offset) + 1 + if last_integration_context_set + timedelta(minutes=1) <= datetime.utcnow(): + integration_context = demisto.getIntegrationContext() + integration_context['offset'] = offset_to_store + if store_samples: + try: + sample_events_to_store.append(event) + demisto.debug(f'Storing new {len(sample_events_to_store)} sample events') + sample_events = deque(json.loads(integration_context.get('sample_events', '[]')), maxlen=20) + sample_events += sample_events_to_store + integration_context['sample_events'] = json.dumps(list(sample_events)) + except Exception as e: + demisto.error(f'Failed storing sample events - {e}') + demisto.debug(f'Storing offset {offset_to_store}') + demisto.setIntegrationContext(integration_context) + last_integration_context_set = datetime.utcnow() + except Exception as e: + demisto.error(f'An error occurred in the long running loop: {e}') + finally: + # store latest fetched event offset in case the loop crashes and we did not reach the 1 minute to store it + integration_context = demisto.getIntegrationContext() + integration_context['offset'] = offset_to_store + demisto.setIntegrationContext(integration_context) async def test_module(base_url: str, client_id: str, client_secret: str, verify_ssl: bool, proxy: bool) -> None: @@ -326,6 +387,30 @@ async def test_module(base_url: str, client_id: str, client_secret: str, verify_ demisto.results('ok') +def get_sample_events(store_samples: bool = False) -> None: + """Extracts sample events stored in the integration context and returns them + + Args: + store_samples (bool): Whether to store sample events in the integration context or not. + + Returns: + None: No data returned. + """ + integration_context = demisto.getIntegrationContext() + sample_events = integration_context.get('sample_events') + if sample_events: + try: + demisto.results(json.loads(sample_events)) + except json.decoder.JSONDecodeError as e: + raise ValueError(f'Failed deserializing sample events - {e}') + else: + output = 'No sample events found.' + if not store_samples: + output += ' The "Store sample events for mapping" integration parameter ' \ + 'need to be enabled for this command to return results.' + demisto.results(output) + + def main(): params: Dict = demisto.params() base_url: str = params.get('base_url', '') @@ -339,6 +424,8 @@ def main(): offset = int(offset) except ValueError: offset = 0 + incident_type = params.get('incidentType', '') + store_samples = params.get('store_samples', False) stream = EventStream(base_url=base_url, app_id='Demisto', verify_ssl=verify_ssl, proxy=proxy) @@ -347,7 +434,12 @@ def main(): if demisto.command() == 'test-module': run(test_module(base_url, client_id, client_secret, verify_ssl, proxy)) elif demisto.command() == 'long-running-execution': - run(long_running_loop(base_url, client_id, client_secret, stream, offset, event_type, verify_ssl, proxy)) + run(long_running_loop( + base_url, client_id, client_secret, stream, offset, event_type, verify_ssl, proxy, incident_type, + store_samples + )) + elif demisto.command() == 'crowdstrike-falcon-streaming-get-sample-events': + get_sample_events(store_samples) except Exception as e: error_msg = f'Error in CrowdStrike Falcon Streaming v2: {str(e)}' demisto.error(error_msg) diff --git a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.yml b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.yml index a0b1961fdea3..f62e31938ec5 100644 --- a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.yml +++ b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2.yml @@ -47,6 +47,14 @@ configuration: name: incidentType required: false type: 13 +- additionalinfo: Because this is a push-based streaming integration, it cannot fetch sample events in + the mapping wizard. In order to view sample events, you need to enable events storage and + run the crowdstrike-falcon-streaming-get-sample-events command. + display: Store sample events for mapping + hidden: false + name: store_samples + required: false + type: 8 - display: Trust any certificate (not secure) name: insecure required: false @@ -59,7 +67,12 @@ description: Use the CrowdStrike Falcon Stream v2 integration to stream detectio display: CrowdStrike Falcon Streaming v2 name: CrowdStrike Falcon Streaming v2 script: - dockerimage: demisto/aiohttp:1.0.0.6695 + commands: + - deprecated: false + description: Returns a list of sample events fetched from the stream. + execution: false + name: crowdstrike-falcon-streaming-get-sample-events + dockerimage: demisto/aiohttp:1.0.0.8854 feed: false isfetch: false longRunning: true diff --git a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2_test.py b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2_test.py new file mode 100644 index 000000000000..7d463483f2c7 --- /dev/null +++ b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/CrowdStrikeFalconStreamingV2_test.py @@ -0,0 +1,136 @@ +import json +import demistomock as demisto +from CrowdStrikeFalconStreamingV2 import get_sample_events + + +def test_get_sample_events_with_results(mocker): + """ + Given: + - Samples events stored in the integration context. + - Store events integration parameter is enabled. + + When: + - Running get sample events command. + + Then: + - Ensure the command runs successfully + - Verify expected results are returned. + """ + sample_events = [ + { + 'event': { + 'AuditKeyValues': [ + { + 'Key': 'partition', + 'ValueString': '0' + }, + { + 'Key': 'offset', + 'ValueString': '70626' + }, + { + 'Key': 'appId', + 'ValueString': 'demisto' + }, + { + 'Key': 'eventType', + 'ValueString': 'All event type(s)' + } + ], + 'OperationName': 'streamStarted', + 'ServiceName': 'Crowdstrike Streaming API', + 'Success': True, + 'UTCTimestamp': 1592479007 + }, + 'metadata': { + 'eventCreationTime': 1592479007646, + 'eventType': 'AuthActivityAuditEvent', + 'offset': 70627, + 'version': '1.0' + } + }, + { + 'event': { + 'CommandLine': 'choice /m crowdstrike_sample_detection', + 'ComputerName': 'FALCON-CROWDSTR', + 'DetectDescription': 'For evaluation only - benign, no action needed.', + 'DetectName': 'Suspicious Activity', + 'FileName': 'choice.exe', + 'FilePath': '\\Device\\HarddiskVolume1\\Windows\\System32', + 'GrandparentCommandLine': 'C:\\Windows\\Explorer.EXE', + 'GrandparentImageFileName': '\\Device\\HarddiskVolume1\\Windows\\explorer.exe', + 'MD5String': '463b5477ff96ab86a01ba49bcc02b539', + 'MachineDomain': 'FALCON-CROWDSTR', + 'Objective': 'Falcon Detection Method', + 'ParentCommandLine': '\'C:\\Windows\\system32\\cmd.exe\' ', + 'ParentImageFileName': '\\Device\\HarddiskVolume1\\Windows\\System32\\cmd.exe', + 'ParentProcessId': 79569204402, + 'PatternDispositionDescription': 'Detection, standard detection.', + 'PatternDispositionFlags': { + 'BootupSafeguardEnabled': False, + 'CriticalProcessDisabled': False, + 'Detect': False, + 'FsOperationBlocked': False, + 'InddetMask': False, + 'Indicator': False, + 'KillParent': False, + 'KillProcess': False, + 'KillSubProcess': False, + 'OperationBlocked': False, + 'PolicyDisabled': False, + 'ProcessBlocked': False, + 'QuarantineFile': False, + 'QuarantineMachine': False, + 'RegistryOperationBlocked': False, + 'Rooting': False, + 'SensorOnly': False + }, + 'PatternDispositionValue': 0, + 'ProcessEndTime': 1592479032, + 'ProcessId': 79867150228, + 'ProcessStartTime': 1592479032, + 'SHA1String': '0000000000000000000000000000000000000000', + 'SHA256String': '90f352c1fb7b21cc0216b2f0701a236db92b786e4301904d28f4ec4cb81f2a0b', + 'SensorId': '15dbb9d8f06b45fe9f61eb46e829d986', + 'Severity': 2, + 'SeverityName': 'Low', + 'Tactic': 'Falcon Overwatch', + 'Technique': 'Malicious Activity', + 'UserName': 'admin' + }, + 'metadata': { + 'eventCreationTime': 1592479032000, + 'eventType': 'DetectionSummaryEvent', + 'offset': 70628, + 'version': '1.0' + } + } + ] + mocker.patch.object(demisto, 'getIntegrationContext', return_value={'sample_events': json.dumps(sample_events)}) + mocker.patch.object(demisto, 'results') + get_sample_events() + assert demisto.results.call_count == 1 + results = demisto.results.call_args[0][0] + assert results == sample_events + + +def test_get_sample_events_integration_param(mocker): + """ + Given: + - Samples events not stored in the integration context. + - Store events integration parameter is disabled. + + When: + - Running get sample events command. + + Then: + - Ensure the command runs successfully + - Verify output message. + """ + mocker.patch.object(demisto, 'getIntegrationContext', return_value={}) + mocker.patch.object(demisto, 'results') + get_sample_events(store_samples=False) + assert demisto.results.call_count == 1 + results = demisto.results.call_args[0][0] + assert results == 'No sample events found. The "Store sample events for mapping" integration parameter need to ' \ + 'be enabled for this command to return results.' diff --git a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/README.md b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/README.md index 8049994a0929..ac67aa14a416 100644 --- a/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/README.md +++ b/Packs/CrowdStrikeFalconStreamingV2/Integrations/CrowdStrikeFalconStreamingV2/README.md @@ -20,6 +20,7 @@ The required scope is Event streams. * __Event type to fetch__ * __Offset to fetch events from__ * __Incident type__ + * __Store sample events for mapping__ * __Trust any certificate (not secure)__ * __Use system proxy settings__ 4. Click __Test__ to validate the URLs, token, and connection. @@ -51,3 +52,71 @@ Event metadata will be fetched as the incident details, which contain the follow * Detection Name * Detection Description * Severity + +## Mapping incoming events +Because this is a push-based streaming integration, it cannot fetch sample events in the mapping wizard. + +In order to view sample events, enable events storage by selecting the checkbox of the integration parameter **Store sample events for mapping** and run the `crowdstrike-falcon-streaming-get-sample-events` command. + +The last events (maximum of 20) are fetched every 1 minute. Allow the integration to run for at least 5 minutes before running the command. +After you finish mapping, it is recommended to turn off the **Store sample events for mapping** to reduce performance overhead. +#### Usage example + +The command output is as follows: +```json +{ + "event": { + "ComputerName": "FALCON-CROWDSTR", + "DetectId": "ldt:15dbb9d8f06b45fe9f61eb46e829d986:55929758895", + "DetectName": "Suspicious Activity", + "FileName": "choice.exe", + "FilePath": "\\Device\\HarddiskVolume1\\Windows\\System32", + "GrandparentCommandLine": "C:\\Windows\\Explorer.EXE", + "GrandparentImageFileName": "\\Device\\HarddiskVolume1\\Windows\\explorer.exe", + "MD5String": "463b5477ff96ab86a01ba49bcc02b539", + "MachineDomain": "FALCON-CROWDSTR", + "Objective": "Falcon Detection Method", + "ParentCommandLine": "\"C:\\Windows\\system32\\cmd.exe\" ", + "ParentImageFileName": "\\Device\\HarddiskVolume1\\Windows\\System32\\cmd.exe", + "ParentProcessId": 79569204402, + "PatternDispositionDescription": "Detection, standard detection.", + "PatternDispositionFlags": { + "BootupSafeguardEnabled": false, + "CriticalProcessDisabled": false, + "Detect": false, + "FsOperationBlocked": false, + "InddetMask": false, + "Indicator": false, + "KillParent": false, + "KillProcess": false, + "KillSubProcess": false, + "OperationBlocked": false, + "PolicyDisabled": false, + "ProcessBlocked": false, + "QuarantineFile": false, + "QuarantineMachine": false, + "RegistryOperationBlocked": false, + "Rooting": false, + "SensorOnly": false + }, + "PatternDispositionValue": 0, + "ProcessEndTime": 1592479032, + "ProcessId": 79867150228, + "ProcessStartTime": 1592479032, + "Severity": 2, + "SeverityName": "Low", + "Tactic": "Falcon Overwatch", + "Technique": "Malicious Activity", + "UserName": "admin" + }, + "metadata": { + "customerIDString": "20874a8064904ecfbb62c118a6a19411", + "eventCreationTime": 1592479032000, + "eventType": "DetectionSummaryEvent", + "offset": 70628, + "version": "1.0" + } +} +``` + +You can now upload that JSON file to the mapping wizard and continue as usual. diff --git a/Packs/CrowdStrikeFalconStreamingV2/ReleaseNotes/1_0_3.md b/Packs/CrowdStrikeFalconStreamingV2/ReleaseNotes/1_0_3.md new file mode 100644 index 000000000000..9a8579dde36d --- /dev/null +++ b/Packs/CrowdStrikeFalconStreamingV2/ReleaseNotes/1_0_3.md @@ -0,0 +1,4 @@ + +### Integrations +- __CrowdStrike Falcon Streaming v2__ +Several bug fixes and improvements. diff --git a/Packs/CrowdStrikeFalconStreamingV2/pack_metadata.json b/Packs/CrowdStrikeFalconStreamingV2/pack_metadata.json index 2d9f5166fcfe..05317da8ac51 100644 --- a/Packs/CrowdStrikeFalconStreamingV2/pack_metadata.json +++ b/Packs/CrowdStrikeFalconStreamingV2/pack_metadata.json @@ -2,7 +2,7 @@ "name": "CrowdStrike Falcon Streaming", "description": "Use the CrowdStrike Falcon Stream v2 integration to stream detections and audit security events.", "support": "xsoar", - "currentVersion": "1.0.2", + "currentVersion": "1.0.3", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/CHANGELOG.md b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/CHANGELOG.md index cb158a56bed1..b7e75780afba 100644 --- a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/CHANGELOG.md +++ b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/CHANGELOG.md @@ -1,5 +1,7 @@ ## [Unreleased] - +Made several improvements to the ***frontline-scan-asset*** command. + - Updated the default scan name from **Demisto Scan** to **Cortex XSOAR Scan**. + - Added the *scan_name* argument, which enables you to assign a unique name to the scan. ## [20.5.0] - 2020-05-12 - diff --git a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.py b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.py index 00b96515beec..6fb965f5488b 100644 --- a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.py +++ b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.py @@ -586,7 +586,7 @@ def get_correct_ip_order(low_ip_address, high_ip_address): } -def build_scan(low_ip_address, high_ip_address, scan_policy): +def build_scan(low_ip_address, high_ip_address, scan_policy, scan_name): ''' Prepare scan data payload for POST request. ''' # check order of given ip address and assign accordingly @@ -608,10 +608,12 @@ def build_scan(low_ip_address, high_ip_address, scan_policy): scan = {} # type: Dict[str, Any] # Scan name will change if user is scanning range (low ip address not equal to high ip address) - if low_ip_address == high_ip_address: - scan['name'] = ("Demisto Scan " + " [" + str(low_ip_address) + "]") + if scan_name is not None: + scan['name'] = str(scan_name)[:100] + elif low_ip_address == high_ip_address: + scan['name'] = ("Cortex XSOAR Scan " + " [" + str(low_ip_address) + "]") else: - scan['name'] = ("Demisto Scan " + "[" + str(low_ip_address) + "-" + str(high_ip_address) + "]") + scan['name'] = ("Cortex XSOAR Scan " + "[" + str(low_ip_address) + "-" + str(high_ip_address) + "]") scan['description'] = "New network device auto scan launch from Demisto." @@ -660,7 +662,7 @@ def build_scan(low_ip_address, high_ip_address, scan_policy): return scan -def scan_asset(ip_address, scan_policy, ip_range_start, ip_range_end): +def scan_asset(ip_address, scan_policy, scan_name, ip_range_start, ip_range_end): ''' Build scan payload and make POST request to perform scan. ''' try: if ip_address: @@ -677,7 +679,7 @@ def scan_asset(ip_address, scan_policy, ip_range_start, ip_range_end): msg = "Inputting a single \'ip_address\' and a range of addresses will yield to the single ip_address to scan" demisto.debug("FrontlineVM scan_asset -- " + msg) - scan_payload = build_scan(low_ip_address, high_ip_address, scan_policy) + scan_payload = build_scan(low_ip_address, high_ip_address, scan_policy, scan_name) header = {} header['Authorization'] = 'Token ' + str(API_TOKEN) header['Content-Type'] = "application/json;charset=utf-8" @@ -727,13 +729,14 @@ def scan_asset_command(): ''' Peform scan on Frontline.Cloud ''' ip_address = demisto.args().get('ip_address') policy_name = str(demisto.args().get('scan_policy')) + scan_name = demisto.args().get('scan_name') ip_range_start = demisto.args().get('ip_range_start') ip_range_end = demisto.args().get('ip_range_end') if not scan_policy_exists(policy_name): return_error("Error: Scan Policy entered '" + policy_name + "' does not exist.") try: - scan_response = scan_asset(ip_address, policy_name, ip_range_start, ip_range_end) + scan_response = scan_asset(ip_address, policy_name, scan_name, ip_range_start, ip_range_end) # Gather IP addresses from scan response data: ip_addresses = get_ip_addresses_from_scan_data(scan_response) low_ip = ip_addresses.get('low') diff --git a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.yml b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.yml index 4da68083b795..12431cf5610b 100644 --- a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.yml +++ b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/Digital_Defense_FrontlineVM.yml @@ -2,10 +2,11 @@ commonfields: id: Digital Defense FrontlineVM version: -1 name: Digital Defense FrontlineVM -display: Digital Defense Frontline VM +display: Digital Defense FrontlineVM category: Vulnerability Management -description: Use the Digital Defense Frontline VM to identify and evaluate the security and business risks of network devices - and applications deployed as premise, cloud, or hybrid network-based implementations. +description: Use the Digital Defense FrontlineVM to identify and evaluate the security + and business risks of network devices and applications deployed as premise, cloud, + or hybrid network-based implementations. configuration: - display: Frontline VM URL name: frontlineURL @@ -59,7 +60,6 @@ configuration: script: script: '' type: python - subtype: python3 commands: - name: frontline-get-assets arguments: @@ -86,7 +86,7 @@ script: - contextPath: FrontlineVM.Hosts.MAC description: The MAC address of the host. - contextPath: FrontlineVM.Hosts.OS - description: The operating system of the host. + description: The operating system of the host. - contextPath: FrontlineVM.Hosts.OSType description: The operating system type of the host. - contextPath: FrontlineVM.Hosts.CriticalVulnCount @@ -103,8 +103,9 @@ script: - low - trivial - info - description: 'The minimum severity level for which to return vulnerabilities. This argument overrides the "severity" argument when used together. - Can be: "critical","high","medium","low","trivial", or "info".' + description: 'The minimum severity level for which to return vulnerabilities. + This argument overrides the "severity" argument when used together. Can be: + "critical","high","medium","low","trivial", or "info".' - name: severity auto: PREDEFINED predefined: @@ -114,16 +115,19 @@ script: - low - trivial - info - description: 'Returns all vulnerabilities from Frontline with the specified severity level. - Can be: "critical","high","medium","low","trivial", or "info".' + description: 'Returns all vulnerabilities from Frontline with the specified + severity level. Can be: "critical","high","medium","low","trivial", or "info".' - name: max_days_since_created - description: Retrieves vulnerabilities found prior to the specified date (in days). + description: Retrieves vulnerabilities found prior to the specified date (in + days). - name: min_days_since_created description: Retrieves vulnerabilities found after the specified date (in days). - name: host_id - description: Retrieves vulnerabilities from a specific host based on the Host ID. + description: Retrieves vulnerabilities from a specific host based on the Host + ID. - name: ip_address - description: The IP address of the host for which to retrieve the vulnerability data. + description: The IP address of the host for which to retrieve the vulnerability + data. outputs: - contextPath: FrontlineVM.Vulns description: Retrieved vulnerability data pulled from Frontline.Cloud. @@ -156,6 +160,9 @@ script: description: The IP address start range of the asset to scan. - name: ip_range_end description: The IP address end range of the asset to scan. + - name: scan_name + description: A unique name for the scan to run in FrontlineVM. Default value will + be "Cortex XSOAR Scan []. Limited to 100 characters." outputs: - contextPath: FrontlineVM.Scan.ID description: The ID number of the scan. @@ -164,8 +171,13 @@ script: - contextPath: FrontlineVM.Scan.Policy description: The policy name of the scan. - contextPath: FrontlineVM.Scan.IP - description: The IP address of the scan (can be a single IP address or a range of IP addresses). + description: The IP address of the scan (can be a single IP address or a range + of IP addresses). description: Performs a scan on the specified asset. - dockerimage: demisto/python3:3.7.4.1150 + dockerimage: demisto/python3:3.8.3.9324 isfetch: true runonce: false + subtype: python3 +fromversion: 4.1.0 +tests: +- No tests (auto formatted) diff --git a/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/README.md b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/README.md new file mode 100644 index 000000000000..a65bd4eb3304 --- /dev/null +++ b/Packs/Digital_Defense_FrontlineVM/Integrations/Digital_Defense_FrontlineVM/README.md @@ -0,0 +1,139 @@ +Use the Digital Defense Frontline VM to identify and evaluate the security and business risks of network devices and applications deployed as premise, cloud, or hybrid network-based implementations. +This integration was integrated and tested with version 6.2.4 of Digital Defense FrontlineVM +## Configure Digital Defense FrontlineVM on Cortex XSOAR + +1. Navigate to **Settings** > **Integrations** > **Servers & Services**. +2. Search for Digital Defense FrontlineVM. +3. Click **Add instance** to create and configure a new integration instance. + +| **Parameter** | **Description** | **Required** | +| --- | --- | --- | +| frontlineURL | Frontline VM URL | True | +| insecure | Trust any certificate \(not secure\) | False | +| apiToken | API Token to access Frontline VM | True | +| isFetch | Fetch incidents | False | +| incidentType | Incident type | False | +| incidentSeverity | Minimum vulnerability severity for fetching incidents | False | +| incidentFrequency | Rate at which to check vulnerability events when fetching incidents | True | + +4. Click **Test** to validate the URLs, token, and connection. +## Commands +You can execute these commands from the Demisto 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. +### frontline-get-assets +*** +Retrieves the asset's information from Frontline VM. + + +#### Base Command + +`frontline-get-assets` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| ip_address | The IP address for which to return assets. | Optional | +| label_name | The label name for which to return assets. | Optional | +| max_days_since_scan | The number of days (retroactive) since the last scan. | Optional | +| hostname | The hostname for which to return assets. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| FrontlineVM.Hosts | unknown | The host data from Frontline.Cloud. | +| FrontlineVM.Hosts.ID | unknown | The ID number of the host. | +| FrontlineVM.Hosts.Hostname | unknown | The hostname of the asset. | +| FrontlineVM.Hosts.IP | unknown | The IP address of the host. | +| FrontlineVM.Hosts.DNSHostname | unknown | The DNS hostname of the host. | +| FrontlineVM.Hosts.MAC | unknown | The MAC address of the host. | +| FrontlineVM.Hosts.OS | unknown | The operating system of the host. | +| FrontlineVM.Hosts.OSType | unknown | The operating system type of the host. | +| FrontlineVM.Hosts.CriticalVulnCount | unknown | The severity count of critical vulnerabilities. | + + +#### Command Example +``` ``` + +#### Human Readable Output + + + +### frontline-get-vulns +*** +Retrieves vulnerability information from Frontline VM. + + +#### Base Command + +`frontline-get-vulns` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| min_severity | The minimum severity level for which to return vulnerabilities. This argument overrides the "severity" argument when used together. Can be: "critical","high","medium","low","trivial", or "info". | Optional | +| severity | Returns all vulnerabilities from Frontline with the specified severity level. Can be: "critical","high","medium","low","trivial", or "info". | Optional | +| max_days_since_created | Retrieves vulnerabilities found prior to the specified date (in days). | Optional | +| min_days_since_created | Retrieves vulnerabilities found after the specified date (in days). | Optional | +| host_id | Retrieves vulnerabilities from a specific host based on the Host ID. | Optional | +| ip_address | The IP address of the host for which to retrieve the vulnerability data. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| FrontlineVM.Vulns | unknown | Retrieved vulnerability data pulled from Frontline.Cloud. | +| FrontlineVM.Stat | unknown | The statistical overview of vulnerabilities pulled. | +| FrontlineVM.Vulns.vuln-id | unknown | The ID of the vulnerability. | +| FrontlineVM.Vulns.hostname | unknown | The hostname of the asset. | +| FrontlineVM.Vulns.ip-address | unknown | The IP address of the asset. | +| FrontlineVM.Vulns.vuln-title | unknown | The title of the vulnerability. | +| FrontlineVM.Vulns.date-created | unknown | The date the vulnerability was created. | +| FrontlineVM.Vulns.ddi-severity | unknown | The severity level of the vulnerability. | +| FrontlineVM.Vulns.vuln-info | unknown | Information related to the vulnerability. | + + +#### Command Example +``` ``` + +#### Human Readable Output + + + +### frontline-scan-asset +*** +Performs a scan on the specified asset. + + +#### Base Command + +`frontline-scan-asset` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| ip_address | The IP address of the asset to scan. | Optional | +| scan_policy | The policy of the scan (case sensitive). | Optional | +| ip_range_start | The IP address start range of the asset to scan. | Optional | +| ip_range_end | The IP address end range of the asset to scan. | Optional | +| scan_name | The name of this scan to run in FrontlineVM. Default value will be "Cortex XSOAR Scan [<asset_ip_address>]" | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| FrontlineVM.Scan.ID | unknown | The ID number of the scan. | +| FrontlineVM.Scan.Name | unknown | The name of the scan. | +| FrontlineVM.Scan.Policy | unknown | The policy name of the scan. | +| FrontlineVM.Scan.IP | unknown | The IP address of the scan \(can be a single IP address or a range of IP addresses\). | + + +#### Command Example +``` ``` + +#### Human Readable Output + + diff --git a/Packs/Digital_Defense_FrontlineVM/ReleaseNotes/1_1_0.md b/Packs/Digital_Defense_FrontlineVM/ReleaseNotes/1_1_0.md new file mode 100644 index 000000000000..6c390b9d020d --- /dev/null +++ b/Packs/Digital_Defense_FrontlineVM/ReleaseNotes/1_1_0.md @@ -0,0 +1,6 @@ + +### Integrations +- __Digital Defense FrontlineVM__ + - Update to frontline-scan-asset command + - Update default scan name from 'Demisto Scan' to 'Cortex XSOAR Scan' + - scan_name argument added for users to define their own scan name \ No newline at end of file diff --git a/Packs/Digital_Defense_FrontlineVM/pack_metadata.json b/Packs/Digital_Defense_FrontlineVM/pack_metadata.json index e8ad933441fd..881c3e06514a 100644 --- a/Packs/Digital_Defense_FrontlineVM/pack_metadata.json +++ b/Packs/Digital_Defense_FrontlineVM/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Digital Defense Frontline VM", "description": "Use the Digital Defense Frontline VM to identify and evaluate the security and business risks of network devices and applications deployed as premise, cloud, or hybrid network-based implementations.", "support": "xsoar", - "currentVersion": "1.0.1", + "currentVersion": "1.1.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleKubernetesEngine/Integrations/GoogleKubernetesEngine/GoogleKubernetesEngine.py b/Packs/GoogleKubernetesEngine/Integrations/GoogleKubernetesEngine/GoogleKubernetesEngine.py index d85c15b98235..d943d0fd688b 100644 --- a/Packs/GoogleKubernetesEngine/Integrations/GoogleKubernetesEngine/GoogleKubernetesEngine.py +++ b/Packs/GoogleKubernetesEngine/Integrations/GoogleKubernetesEngine/GoogleKubernetesEngine.py @@ -877,7 +877,7 @@ def main(): LOG(f'Command being called is {command}') commands: Dict[str, Callable] = { # Clusters - f"test-module": test_module_command, + "test-module": test_module_command, f"{INTEGRATION_COMMAND_NAME}-clusters-list": gcloud_clusters_list_command, f"{INTEGRATION_COMMAND_NAME}-clusters-describe": gcloud_clusters_describe_command, f"{INTEGRATION_COMMAND_NAME}-clusters-set-muster-auth": gcloud_clusters_set_master_auth, diff --git a/Packs/GoogleKubernetesEngine/ReleaseNotes/1_0_1.md b/Packs/GoogleKubernetesEngine/ReleaseNotes/1_0_1.md new file mode 100644 index 000000000000..0a5d1e07e74c --- /dev/null +++ b/Packs/GoogleKubernetesEngine/ReleaseNotes/1_0_1.md @@ -0,0 +1,6 @@ + + diff --git a/Packs/GoogleKubernetesEngine/pack_metadata.json b/Packs/GoogleKubernetesEngine/pack_metadata.json index e1670a09dc48..ade04878316d 100644 --- a/Packs/GoogleKubernetesEngine/pack_metadata.json +++ b/Packs/GoogleKubernetesEngine/pack_metadata.json @@ -3,7 +3,7 @@ "description": "Google Kubernetes Engine managing clusters and node-pools.", "support": "demisto", "serverMinVersion": "5.0.0", - "currentVersion": "1.0.0", + "currentVersion": "1.0.1", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Kenna/Integrations/KennaV2/KennaV2.py b/Packs/Kenna/Integrations/KennaV2/KennaV2.py index 3eaf3a77ddc1..2a9a31ed26e5 100644 --- a/Packs/Kenna/Integrations/KennaV2/KennaV2.py +++ b/Packs/Kenna/Integrations/KennaV2/KennaV2.py @@ -234,10 +234,10 @@ def search_fixes(client: Client, args: dict) -> Tuple[str, Dict[str, Any], List[ 'top_priority[]': argToList(args.get('top-priority')), 'min_risk_meter_score': args.get('min-score'), 'status[]': argToList(args.get('status')), + 'per_page': limit } response = client.http_request(message='GET', suffix=url_suffix, params=params).get('fixes') if response: - fixes_list = response[:limit] wanted_keys = ['ID', 'Title', ['Assets', 'ID', 'Locator', 'PrimaryLocator', 'DisplayLocator'], ['Vulnerabilities', 'ID', 'ServiceTicketStatus', 'ScannerIDs'], 'CveID', 'LastUpdatedAt', @@ -246,10 +246,10 @@ def search_fixes(client: Client, args: dict) -> Tuple[str, Dict[str, Any], List[ ['vulnerabilities', 'id', 'service_ticket_status', 'scanner_ids'], 'cves', 'updated_at', 'category', 'vuln_count', 'max_vuln_score'] - context_list = parse_response(fixes_list, wanted_keys, actual_keys) + context_list = parse_response(response, wanted_keys, actual_keys) remove_html = re.compile(r'<[^>]+>') - for fix in fixes_list: + for fix in response: if fix: human_readable_markdown += str(fix.get('title')) + '\n' human_readable_markdown += '#### ID: ' + str(fix.get('id')) + '\n' diff --git a/Packs/Kenna/Integrations/KennaV2/KennaV2.yml b/Packs/Kenna/Integrations/KennaV2/KennaV2.yml index 45dfb34d0ccd..e602f5e27c3e 100644 --- a/Packs/Kenna/Integrations/KennaV2/KennaV2.yml +++ b/Packs/Kenna/Integrations/KennaV2/KennaV2.yml @@ -520,7 +520,7 @@ script: description: Deletes tags from the specified asset. execution: false name: kenna-delete-tag - dockerimage: demisto/python3:3.8.3.8715 + dockerimage: demisto/python3:3.8.3.9324 isfetch: false longRunning: false longRunningPort: false diff --git a/Packs/Kenna/ReleaseNotes/1_0_3.md b/Packs/Kenna/ReleaseNotes/1_0_3.md new file mode 100644 index 000000000000..775d3824d895 --- /dev/null +++ b/Packs/Kenna/ReleaseNotes/1_0_3.md @@ -0,0 +1,4 @@ + +#### Integrations +##### Kennav2 +- Fixed an issue where the **limit** argument did not work when set above 25 in the ***kenna-search-fixes*** command. diff --git a/Packs/Kenna/TestPlaybooks/playbook-Kenna_Test.yml b/Packs/Kenna/TestPlaybooks/playbook-Kenna_Test.yml index bdbad80421a8..7824e0a84711 100644 --- a/Packs/Kenna/TestPlaybooks/playbook-Kenna_Test.yml +++ b/Packs/Kenna/TestPlaybooks/playbook-Kenna_Test.yml @@ -1,16 +1,14 @@ id: Kenna Test version: -1 -contentitemfields: - propagationLabels: [] name: Kenna Test starttaskid: "0" tasks: "0": id: "0" - taskid: 92db6856-64f1-43ae-8487-3dac84e4b321 + taskid: a26517f9-2932-4597-86f9-c8586892aab0 type: start task: - id: 92db6856-64f1-43ae-8487-3dac84e4b321 + id: a26517f9-2932-4597-86f9-c8586892aab0 version: -1 name: "" iscommand: false @@ -33,10 +31,10 @@ tasks: quietmode: 0 "1": id: "1" - taskid: c111a353-42b1-47e2-84b8-a8891a7d0b11 + taskid: 5d457631-e47c-48b5-8dcb-5c3d1a4adc58 type: regular task: - id: c111a353-42b1-47e2-84b8-a8891a7d0b11 + id: 5d457631-e47c-48b5-8dcb-5c3d1a4adc58 version: -1 name: kenna-get-connectors description: Returns all of your connectors @@ -62,10 +60,10 @@ tasks: quietmode: 0 "3": id: "3" - taskid: 1360028e-d41e-4227-8353-9cc2c2834a18 + taskid: 1fcebd93-7d0b-49ee-84b9-419d5360ce57 type: regular task: - id: 1360028e-d41e-4227-8353-9cc2c2834a18 + id: 1fcebd93-7d0b-49ee-84b9-419d5360ce57 version: -1 name: kenna-search-vulnerabilities description: Filtering vulnerabilities by those that Kenna recommends. @@ -78,8 +76,10 @@ tasks: - "16" scriptarguments: id: {} + limit: {} min-score: {} status: {} + to_context: {} top-priority: {} separatecontext: false view: |- @@ -96,10 +96,10 @@ tasks: quietmode: 0 "6": id: "6" - taskid: 95784aa0-dce6-4fba-819e-6c6ddcd7ff6a + taskid: 8dedd321-e0da-4a89-8e43-8a73612797be type: regular task: - id: 95784aa0-dce6-4fba-819e-6c6ddcd7ff6a + id: 8dedd321-e0da-4a89-8e43-8a73612797be version: -1 name: kenna-update-vulnerability description: Update a single vulnerability's attributes by ID @@ -136,10 +136,10 @@ tasks: quietmode: 0 "7": id: "7" - taskid: 4c484f51-2074-4bec-8dec-be8336601659 + taskid: d12bf592-d511-4783-8082-bf214aa29a28 type: condition task: - id: 4c484f51-2074-4bec-8dec-be8336601659 + id: d12bf592-d511-4783-8082-bf214aa29a28 version: -1 name: Connectors ID List Exists? type: condition @@ -175,10 +175,10 @@ tasks: quietmode: 0 "8": id: "8" - taskid: 73cb1a02-2de5-4577-84fd-80e45c345bf0 + taskid: f27053d7-500c-404c-8438-8abaf8150b99 type: title task: - id: 73cb1a02-2de5-4577-84fd-80e45c345bf0 + id: f27053d7-500c-404c-8438-8abaf8150b99 version: -1 name: Done type: title @@ -199,10 +199,10 @@ tasks: quietmode: 0 "9": id: "9" - taskid: e8de4835-b6a6-4ce5-8378-8080a0534830 + taskid: 3152765b-6961-4e44-8abd-6b23b0f18da4 type: regular task: - id: e8de4835-b6a6-4ce5-8378-8080a0534830 + id: 3152765b-6961-4e44-8abd-6b23b0f18da4 version: -1 name: Failed description: Prints an error entry with a given message @@ -228,12 +228,12 @@ tasks: quietmode: 0 "12": id: "12" - taskid: a0c42b4d-cf9d-4040-88b3-591d1c56f65a + taskid: 3c282043-611f-402b-8fa9-29746742ee33 type: condition task: - id: a0c42b4d-cf9d-4040-88b3-591d1c56f65a + id: 3c282043-611f-402b-8fa9-29746742ee33 version: -1 - name: Fixes list contain? + name: Verify Search Fixes Outputs type: condition iscommand: false brand: "" @@ -254,6 +254,14 @@ tasks: value: simple: Kenna.Fixes.Assets.ID iscontext: true + - - operator: hasLength + left: + value: + simple: Kenna.Fixes + iscontext: true + right: + value: + simple: "30" view: |- { "position": { @@ -268,10 +276,10 @@ tasks: quietmode: 0 "13": id: "13" - taskid: 69bbf3c5-aafb-42cf-88ff-61a819b1ee57 + taskid: 87b54be9-81cf-48a3-8d61-7ef08d74f0a7 type: regular task: - id: 69bbf3c5-aafb-42cf-88ff-61a819b1ee57 + id: 87b54be9-81cf-48a3-8d61-7ef08d74f0a7 version: -1 name: kenna-search-assets-round1 description: Filtering assets by those that Kenna recommands @@ -303,10 +311,10 @@ tasks: quietmode: 0 "15": id: "15" - taskid: 9c4bdd35-a7c1-4e19-80db-7fe5f3520987 + taskid: 99bc4c92-fab7-4927-8d1c-3e6f31fcf590 type: condition task: - id: 9c4bdd35-a7c1-4e19-80db-7fe5f3520987 + id: 99bc4c92-fab7-4927-8d1c-3e6f31fcf590 version: -1 name: Check Asset List type: condition @@ -349,10 +357,10 @@ tasks: quietmode: 0 "16": id: "16" - taskid: 8095c4ee-2088-4b52-885c-5eeee8d50830 + taskid: 0eea7d49-ee32-4b0f-8db1-259eb5049ac5 type: condition task: - id: 8095c4ee-2088-4b52-885c-5eeee8d50830 + id: 0eea7d49-ee32-4b0f-8db1-259eb5049ac5 version: -1 name: Check Search Vulnerabilities type: condition @@ -397,10 +405,10 @@ tasks: quietmode: 0 "18": id: "18" - taskid: 1adcca0f-457c-4515-8b7e-daff1021d69b + taskid: db27bfff-c1a7-4a82-887e-bf29edb24774 type: regular task: - id: 1adcca0f-457c-4515-8b7e-daff1021d69b + id: db27bfff-c1a7-4a82-887e-bf29edb24774 version: -1 name: check vulnerabilities after update description: Filtering vulnerabilities by those that Kenna recommends. @@ -438,10 +446,10 @@ tasks: quietmode: 0 "19": id: "19" - taskid: 970b460a-9d51-4ab9-83c2-0b30d336a79f + taskid: cafb86b2-ceb8-4220-8249-739ef4a0f22e type: condition task: - id: 970b460a-9d51-4ab9-83c2-0b30d336a79f + id: cafb86b2-ceb8-4220-8249-739ef4a0f22e version: -1 name: check status after update type: condition @@ -478,10 +486,10 @@ tasks: quietmode: 0 "23": id: "23" - taskid: f5041d5f-bcc4-42d9-8745-992a349cede7 + taskid: 90d7c307-2816-4b6a-8f68-4f9874ac7a99 type: regular task: - id: f5041d5f-bcc4-42d9-8745-992a349cede7 + id: 90d7c307-2816-4b6a-8f68-4f9874ac7a99 version: -1 name: kenna-add-tag description: Add tag to Asset id @@ -516,10 +524,10 @@ tasks: quietmode: 0 "24": id: "24" - taskid: 82150d5f-9af5-4e97-891c-7f62d76e49b2 + taskid: f70955af-8306-4c11-8cea-62bf3c20de41 type: regular task: - id: 82150d5f-9af5-4e97-891c-7f62d76e49b2 + id: f70955af-8306-4c11-8cea-62bf3c20de41 version: -1 name: kenna-search-assets-round2 description: Filtering assets by those that Kenna recommands @@ -556,10 +564,10 @@ tasks: quietmode: 0 "25": id: "25" - taskid: 05e8e9e6-3a7f-47c6-8a12-20bf5ec2d7d5 + taskid: 5c90e2cf-f65e-4e75-8cfb-cdf00eed98ca type: condition task: - id: 05e8e9e6-3a7f-47c6-8a12-20bf5ec2d7d5 + id: 5c90e2cf-f65e-4e75-8cfb-cdf00eed98ca version: -1 name: check tag addition type: condition @@ -596,10 +604,10 @@ tasks: quietmode: 0 "26": id: "26" - taskid: c88025e1-326c-43d0-8d4b-14e5cf30bf65 + taskid: 51c0e2fa-ca9c-4635-8614-03701e2768cb type: regular task: - id: c88025e1-326c-43d0-8d4b-14e5cf30bf65 + id: 51c0e2fa-ca9c-4635-8614-03701e2768cb version: -1 name: kenna-delete-tag description: Delete tags from specific Asset @@ -634,10 +642,10 @@ tasks: quietmode: 0 "27": id: "27" - taskid: ed77ec03-8d21-480f-8a00-f951d4c0257c + taskid: a7464572-217b-48d8-84ee-177537f655b2 type: condition task: - id: ed77ec03-8d21-480f-8a00-f951d4c0257c + id: a7464572-217b-48d8-84ee-177537f655b2 version: -1 name: check tag deletion type: condition @@ -678,10 +686,10 @@ tasks: quietmode: 0 "30": id: "30" - taskid: ba1c4934-9518-4010-8854-19dd3e8c2834 + taskid: 4ba73f47-3331-46e6-86ab-91e9187318da type: regular task: - id: ba1c4934-9518-4010-8854-19dd3e8c2834 + id: 4ba73f47-3331-46e6-86ab-91e9187318da version: -1 name: Kenna-search-fixes description: Filters fixes by a given set of vulnerability and asset parameters @@ -695,7 +703,8 @@ tasks: - "12" scriptarguments: id: {} - limit: {} + limit: + simple: "30" min-score: {} status: {} to_context: {} @@ -730,4 +739,4 @@ view: |- } } inputs: [] -outputs: [] \ No newline at end of file +outputs: [] diff --git a/Packs/Kenna/pack_metadata.json b/Packs/Kenna/pack_metadata.json index f2c463156b20..17a5542519f6 100644 --- a/Packs/Kenna/pack_metadata.json +++ b/Packs/Kenna/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Kenna", "description": "Use the Kenna v2 integration to search and update vulnerabilities, schedule a run connector, and manage tags and attributes.", "support": "xsoar", - "currentVersion": "1.0.2", + "currentVersion": "1.0.3", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MailSenderNew/Integrations/MailSenderNew/MailSenderNew_test.py b/Packs/MailSenderNew/Integrations/MailSenderNew/MailSenderNew_test.py index 21d0cc25497f..fa3aea39b6f2 100644 --- a/Packs/MailSenderNew/Integrations/MailSenderNew/MailSenderNew_test.py +++ b/Packs/MailSenderNew/Integrations/MailSenderNew/MailSenderNew_test.py @@ -7,12 +7,15 @@ RETURN_ERROR_TARGET = 'MailSenderNew.return_error' -@pytest.mark.parametrize('subject,subj_include,headers', [ - (u'testbefore\ntestafter', 'testafter', 'foo=baz'), - ('testbefore\ntestafter', 'testafter', 'foo=baz'), - ('\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa', '=?utf-8?', 'foo=baz'), # non-ascii char utf-8 encoded - (u'עברית', '=?utf-8?', 'foo=baz') - ]) # noqa: E124 +@pytest.mark.parametrize('subject,subj_include,headers', + [ + (u'testbefore\ntestafter', 'testafter', 'foo=baz'), + ('testbefore\ntestafter', 'testafter', 'foo=baz'), + ('\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa', '=?utf-8?', 'foo=baz'), + # non-ascii char utf-8 encoded + (u'עברית', '=?utf-8?', 'foo=baz') + ] + ) # noqa: E124 def test_create_msg(mocker, subject, subj_include, headers): mocker.patch.object(demisto, 'args', return_value={ 'to': 'test@test.com,test1@test.com', # disable-secrets-detection diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama.py b/Packs/PAN-OS/Integrations/Panorama/Panorama.py index 0c1910a7962d..4dabc2ba71f6 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama.py +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama.py @@ -3921,6 +3921,12 @@ def prettify_traffic_logs(traffic_logs): pretty_traffic_log['ActionSource'] = traffic_log['action_source'] if 'application' in traffic_log: pretty_traffic_log['Application'] = traffic_log['application'] + if 'bytes' in traffic_log: + pretty_traffic_log['Bytes'] = traffic_log['bytes'] + if 'bytes_received' in traffic_log: + pretty_traffic_log['BytesReceived'] = traffic_log['bytes_received'] + if 'bytes_sent' in traffic_log: + pretty_traffic_log['BytesSent'] = traffic_log['bytes_sent'] if 'category' in traffic_log: pretty_traffic_log['Category'] = traffic_log['category'] if 'device_name' in traffic_log: @@ -4214,6 +4220,12 @@ def prettify_log(log): pretty_log['Action'] = log['action'] if 'app' in log: pretty_log['Application'] = log['app'] + if 'bytes' in log: + pretty_log['Bytes'] = log['bytes'] + if 'bytes_received' in log: + pretty_log['BytesReceived'] = log['bytes_received'] + if 'bytes_sent' in log: + pretty_log['BytesSent'] = log['bytes_sent'] if 'category' in log: pretty_log['CategoryOrVerdict'] = log['category'] if 'device_name' in log: diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama.yml b/Packs/PAN-OS/Integrations/Panorama/Panorama.yml index f30ce16adbab..efc557e618fa 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama.yml +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama.yml @@ -2606,6 +2606,15 @@ script: - contextPath: Panorama.TrafficLogs.Logs.ToZone description: To zone of the traffic log. type: String + - contextPath: Panorama.TrafficLogs.Logs.Bytes + description: Total log bytes. + type: String + - contextPath: Panorama.TrafficLogs.Logs.BytesReceived + description: Log bytes received. + type: String + - contextPath: Panorama.TrafficLogs.Logs.BytesSent + description: Log bytes sent. + type: String - arguments: - auto: PREDEFINED default: false @@ -2970,6 +2979,15 @@ script: A list of the URL filtering categories that the firewall used to enforce the policy. type: String + - contextPath: Panorama.Monitor.Logs.Bytes + description: Total log bytes. + type: String + - contextPath: Panorama.Monitor.Logs.BytesReceived + description: Log bytes received. + type: String + - contextPath: Panorama.Monitor.Logs.BytesSent + description: Log bytes sent. + type: String - arguments: - default: false description: The application name. diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py b/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py index e7f9199d4aa1..d62a3870f6d3 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py @@ -150,13 +150,15 @@ def test_prettify_traffic_logs(): def test_prettify_logs(): from Panorama import prettify_logs - traffic_logs = [{'action': 'my_action1', 'category': 'my_category1', 'rule': 'my_rule1', 'natdport': '100'}, - {'action': 'my_action2', 'category': 'my_category2', 'rule': 'my_rule2', 'natdport': '101'}] + traffic_logs = [{'action': 'my_action1', 'category': 'my_category1', 'rule': 'my_rule1', 'natdport': '100', + 'bytes': '12'}, + {'action': 'my_action2', 'category': 'my_category2', 'rule': 'my_rule2', 'natdport': '101', + 'bytes_sent': '11'}] response = prettify_logs(traffic_logs) expected = [{'Action': 'my_action1', 'CategoryOrVerdict': 'my_category1', 'Rule': 'my_rule1', - 'NATDestinationPort': '100'}, + 'NATDestinationPort': '100', 'Bytes': '12'}, {'Action': 'my_action2', 'CategoryOrVerdict': 'my_category2', 'Rule': 'my_rule2', - 'NATDestinationPort': '101'}] + 'NATDestinationPort': '101', 'BytesSent': '11'}] assert response == expected diff --git a/Packs/PAN-OS/Integrations/Panorama/README.md b/Packs/PAN-OS/Integrations/Panorama/README.md index 6bb1249880d9..07dad88c7f2d 100644 --- a/Packs/PAN-OS/Integrations/Panorama/README.md +++ b/Packs/PAN-OS/Integrations/Panorama/README.md @@ -4582,6 +4582,21 @@ Application associated with the session. +Panorama.Monitor.Bytes +String +Total log bytes. + + +Panorama.Monitor.BytesReceived +String +Log bytes received. + + +Panorama.Monitor.BytesSent +String +Log bytes sent. + + Panorama.Monitor.Category String The URL category of the URL subtype. For WildFire subtype, it is the verdict on the file, and can be either "malicious", "phishing", "grayware"’, or "benign". For other subtypes, the value is "any". diff --git a/Packs/PAN-OS/ReleaseNotes/1_1_0.md b/Packs/PAN-OS/ReleaseNotes/1_1_0.md new file mode 100644 index 000000000000..290a7c8aaec8 --- /dev/null +++ b/Packs/PAN-OS/ReleaseNotes/1_1_0.md @@ -0,0 +1,4 @@ + +#### Integrations +##### Panorama +- Added outputs to the `panorama-get-logs` command. diff --git a/Packs/PAN-OS/pack_metadata.json b/Packs/PAN-OS/pack_metadata.json index 1f8092d2788c..613d6a395bea 100644 --- a/Packs/PAN-OS/pack_metadata.json +++ b/Packs/PAN-OS/pack_metadata.json @@ -2,7 +2,7 @@ "name": "PAN-OS", "description": "Manage Palo Alto Networks Firewall and Panorama. For more information see Panorama documentation.", "support": "xsoar", - "currentVersion": "1.0.5", + "currentVersion": "1.1.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", @@ -13,4 +13,4 @@ "tags": [], "useCases": [], "keywords": [] -} +} \ No newline at end of file diff --git a/Packs/PcapAnalysis/Scripts/PcapMinerV2/PcapMinerV2_test.py b/Packs/PcapAnalysis/Scripts/PcapMinerV2/PcapMinerV2_test.py index 3755ab1ffb9e..a7778629f5a0 100644 --- a/Packs/PcapAnalysis/Scripts/PcapMinerV2/PcapMinerV2_test.py +++ b/Packs/PcapAnalysis/Scripts/PcapMinerV2/PcapMinerV2_test.py @@ -42,6 +42,8 @@ def test_conversations_to_md(): ({}, {'noID': 15}, None, {}), # Test that data without ID isn't added ({}, {'ID': 1, 'EntryID': 15}, None, {}) # Test that just an ID and EntryID is not added. ] + + @pytest.mark.parametrize("main_data, data_to_add, future_id, wanted_output", args_to_test) def test_add_to_data(main_data, data_to_add, future_id, wanted_output): from PcapMinerV2 import add_to_data diff --git a/Packs/Phishing/ReleaseNotes/1_6_1.md b/Packs/Phishing/ReleaseNotes/1_6_1.md new file mode 100644 index 000000000000..ffde9ae43ef4 --- /dev/null +++ b/Packs/Phishing/ReleaseNotes/1_6_1.md @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/Packs/Phishing/pack_metadata.json b/Packs/Phishing/pack_metadata.json index 6b7c1db45dd2..2fe25f63b885 100644 --- a/Packs/Phishing/pack_metadata.json +++ b/Packs/Phishing/pack_metadata.json @@ -1,8 +1,8 @@ { "name": "Phishing", - "description": "A pack used for the complete investigation of potential phishing incidents. It can retrieve emails from user inboxes, extract and analyze attachments, authenticate the email using SPF, DKIM and DMARC checks, provide reputation for links and email adresses involved, and contain and remediate the incident by blocking malicious indicators found in the process with analyst approval.", + "description": " ", "support": "xsoar", - "currentVersion": "1.6.0", + "currentVersion": "1.6.1", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/QuestKace/Integrations/QuestKace/QuestKace.py b/Packs/QuestKace/Integrations/QuestKace/QuestKace.py index 1617fed05959..9858d111d6e9 100644 --- a/Packs/QuestKace/Integrations/QuestKace/QuestKace.py +++ b/Packs/QuestKace/Integrations/QuestKace/QuestKace.py @@ -473,7 +473,7 @@ def get_tickets_list_command(client, args) -> Tuple[str, dict, dict]: context = parse_response(raw_response) for response in context: response['IsDeleted'] = False - human_readable_markdown = tableToMarkdown(f'Quest Kace Tickets', context, removeNull=True, + human_readable_markdown = tableToMarkdown('Quest Kace Tickets', context, removeNull=True, headers=['ID', 'Title', 'Created', 'Modified', 'HdQueueID', 'DueDate']) context = { 'QuestKace.Ticket(val.ID === obj.ID)': context @@ -530,7 +530,7 @@ def create_ticket_command(client, args) -> Tuple[str, dict, dict]: data = json.dumps(temp_data) response = client.create_ticket_request(data) if response.get('Result') != 'Success': - raise DemistoException(f'Error while adding a new ticket.') + raise DemistoException('Error while adding a new ticket.') try: id = response.get('IDs')[0] except Exception as e: @@ -621,7 +621,7 @@ def update_ticket_command(client, args) -> Tuple[str, dict, dict]: response = client.update_ticket_request(ticket_id, data) if response.get('Result') != 'Success': - raise DemistoException(f'Error while updating the ticket.') + raise DemistoException('Error while updating the ticket.') client.update_token() res = client.ticket_by_id_request(ticket_id) ticket = res.get('Tickets') @@ -650,11 +650,11 @@ def delete_ticket_command(client, args) -> Tuple[str, dict, dict]: old_context = old_context[0] old_context['IsDeleted'] = True context = { - f'QuestKace.Ticket(val.ID === obj.ID)': old_context + 'QuestKace.Ticket(val.ID === obj.ID)': old_context } return f'Ticket was deleted successfully. Ticket number {ticket_id}', context, {} else: - raise DemistoException(f'Error while deleting the ticket.') + raise DemistoException('Error while deleting the ticket.') def fetch_incidents(client: Client, fetch_time: str, fetch_shaping: str, last_run: Dict, fetch_limit: str, diff --git a/Packs/QuestKace/ReleaseNotes/1_0_1.md b/Packs/QuestKace/ReleaseNotes/1_0_1.md new file mode 100644 index 000000000000..4b8b4cdd5da7 --- /dev/null +++ b/Packs/QuestKace/ReleaseNotes/1_0_1.md @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/Packs/QuestKace/pack_metadata.json b/Packs/QuestKace/pack_metadata.json index 69ac7183b032..a2ca26dd338e 100644 --- a/Packs/QuestKace/pack_metadata.json +++ b/Packs/QuestKace/pack_metadata.json @@ -3,7 +3,7 @@ "description": "Comprehensive systems management for any network-connected device", "support": "Cortex XSOAR", "serverMinVersion": "5.0.0", - "currentVersion": "1.0.0", + "currentVersion": "1.0.1", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/ThreatConnect/.secrets-ignore b/Packs/ThreatConnect/.secrets-ignore index 0ff66f02b23e..b517f0b62f49 100644 --- a/Packs/ThreatConnect/.secrets-ignore +++ b/Packs/ThreatConnect/.secrets-ignore @@ -6,3 +6,7 @@ https://api.threatconnect.com https://raw.githubusercontent.com 46.148.22.18 https://a.co.il +82.28.82.28 +88.88.88.88 +111.222.111.222 +99.99.99.99 diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect/ThreatConnect.yml b/Packs/ThreatConnect/Integrations/ThreatConnect/ThreatConnect.yml index 9883f984bb75..2495d90f5a2e 100644 --- a/Packs/ThreatConnect/Integrations/ThreatConnect/ThreatConnect.yml +++ b/Packs/ThreatConnect/Integrations/ThreatConnect/ThreatConnect.yml @@ -2,6 +2,7 @@ category: Data Enrichment & Threat Intelligence commonfields: id: ThreatConnect version: -1 +deprecated: true configuration: - display: Access ID name: accessId diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile new file mode 100644 index 000000000000..3523d3b6b93b --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile @@ -0,0 +1,18 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] +pylint = "*" +pytest = "==5.0.1" +pytest-mock = "*" +requests-mock = "*" +pytest-asyncio = "*" + +[packages] +pytest = "*" +requests = "*" + +[requires] +python_version = "3.7" diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile.lock b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile.lock new file mode 100644 index 000000000000..6bdb9313414e --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/Pipfile.lock @@ -0,0 +1,369 @@ +{ + "_meta": { + "hash": { + "sha256": "278db815bec49c11262633d34305f9b33f09432a223bedd5329a04f758f78b55" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "atomicwrites": { + "hashes": [ + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + ], + "version": "==1.3.0" + }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, + "certifi": { + "hashes": [ + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + ], + "version": "==2019.9.11" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "importlib-metadata": { + "hashes": [ + "sha256:652234b6ab8f2506ae58e528b6fbcc668831d3cc758e1bc01ef438d328b68cdb", + "sha256:6f264986fb88042bc1f0535fa9a557e6a376cfe5679dc77caac7fe8b5d43d05f" + ], + "markers": "python_version < '3.8'", + "version": "==0.22" + }, + "more-itertools": { + "hashes": [ + "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", + "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + ], + "version": "==7.2.0" + }, + "packaging": { + "hashes": [ + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" + ], + "version": "==19.1" + }, + "pluggy": { + "hashes": [ + "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", + "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" + ], + "version": "==0.13.0" + }, + "py": { + "hashes": [ + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + ], + "version": "==1.8.0" + }, + "pyparsing": { + "hashes": [ + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + ], + "version": "==2.4.2" + }, + "pytest": { + "hashes": [ + "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", + "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" + ], + "index": "pypi", + "version": "==5.1.2" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "index": "pypi", + "version": "==2.22.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "urllib3": { + "hashes": [ + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + ], + "version": "==1.25.3" + }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + }, + "zipp": { + "hashes": [ + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + ], + "version": "==0.6.0" + } + }, + "develop": { + "astroid": { + "hashes": [ + "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", + "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" + ], + "version": "==2.2.5" + }, + "atomicwrites": { + "hashes": [ + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + ], + "version": "==1.3.0" + }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, + "certifi": { + "hashes": [ + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + ], + "version": "==2019.9.11" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "importlib-metadata": { + "hashes": [ + "sha256:652234b6ab8f2506ae58e528b6fbcc668831d3cc758e1bc01ef438d328b68cdb", + "sha256:6f264986fb88042bc1f0535fa9a557e6a376cfe5679dc77caac7fe8b5d43d05f" + ], + "markers": "python_version < '3.8'", + "version": "==0.22" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:02b260c8deb80db09325b99edf62ae344ce9bc64d68b7a634410b8e9a568edbf", + "sha256:18f9c401083a4ba6e162355873f906315332ea7035803d0fd8166051e3d402e3", + "sha256:1f2c6209a8917c525c1e2b55a716135ca4658a3042b5122d4e3413a4030c26ce", + "sha256:2f06d97f0ca0f414f6b707c974aaf8829c2292c1c497642f63824119d770226f", + "sha256:616c94f8176808f4018b39f9638080ed86f96b55370b5a9463b2ee5c926f6c5f", + "sha256:63b91e30ef47ef68a30f0c3c278fbfe9822319c15f34b7538a829515b84ca2a0", + "sha256:77b454f03860b844f758c5d5c6e5f18d27de899a3db367f4af06bec2e6013a8e", + "sha256:83fe27ba321e4cfac466178606147d3c0aa18e8087507caec78ed5a966a64905", + "sha256:84742532d39f72df959d237912344d8a1764c2d03fe58beba96a87bfa11a76d8", + "sha256:874ebf3caaf55a020aeb08acead813baf5a305927a71ce88c9377970fe7ad3c2", + "sha256:9f5caf2c7436d44f3cec97c2fa7791f8a675170badbfa86e1992ca1b84c37009", + "sha256:a0c8758d01fcdfe7ae8e4b4017b13552efa7f1197dd7358dc9da0576f9d0328a", + "sha256:a4def978d9d28cda2d960c279318d46b327632686d82b4917516c36d4c274512", + "sha256:ad4f4be843dace866af5fc142509e9b9817ca0c59342fdb176ab6ad552c927f5", + "sha256:ae33dd198f772f714420c5ab698ff05ff900150486c648d29951e9c70694338e", + "sha256:b4a2b782b8a8c5522ad35c93e04d60e2ba7f7dcb9271ec8e8c3e08239be6c7b4", + "sha256:c462eb33f6abca3b34cdedbe84d761f31a60b814e173b98ede3c81bb48967c4f", + "sha256:fd135b8d35dfdcdb984828c84d695937e58cc5f49e1c854eb311c4d6aa03f4f1" + ], + "version": "==1.4.2" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", + "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + ], + "version": "==7.2.0" + }, + "packaging": { + "hashes": [ + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" + ], + "version": "==19.1" + }, + "pluggy": { + "hashes": [ + "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", + "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" + ], + "version": "==0.13.0" + }, + "py": { + "hashes": [ + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + ], + "version": "==1.8.0" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "pyparsing": { + "hashes": [ + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + ], + "version": "==2.4.2" + }, + "pytest": { + "hashes": [ + "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", + "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" + ], + "index": "pypi", + "version": "==5.1.2" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:9fac5100fd716cbecf6ef89233e8590a4ad61d729d1732e0a96b84182df1daaf", + "sha256:d734718e25cfc32d2bf78d346e99d33724deeba774cc4afdf491530c6184b63b" + ], + "index": "pypi", + "version": "==0.10.0" + }, + "pytest-mock": { + "hashes": [ + "sha256:43ce4e9dd5074993e7c021bb1c22cbb5363e612a2b5a76bc6d956775b10758b7", + "sha256:5bf5771b1db93beac965a7347dc81c675ec4090cb841e49d9d34637a25c30568" + ], + "index": "pypi", + "version": "==1.10.4" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "index": "pypi", + "version": "==2.22.0" + }, + "requests-mock": { + "hashes": [ + "sha256:510df890afe08d36eca5bb16b4aa6308a6f85e3159ad3013bac8b9de7bd5a010", + "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646" + ], + "index": "pypi", + "version": "==1.7.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "typed-ast": { + "hashes": [ + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "markers": "implementation_name == 'cpython'", + "version": "==1.4.0" + }, + "urllib3": { + "hashes": [ + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + ], + "version": "==1.25.3" + }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + }, + "zipp": { + "hashes": [ + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + ], + "version": "==0.6.0" + } + } +} diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/README.md b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/README.md new file mode 100644 index 000000000000..c55605a4d6a2 --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/README.md @@ -0,0 +1,2434 @@ +Threat intelligence platform. + +## Configure ThreatConnect v2 on Cortex XSOAR + +1. Navigate to **Settings** > **Integrations** > **Servers & Services**. +2. Search for ThreatConnect v2. +3. Click **Add instance** to create and configure a new integration instance. + +| **Parameter** | **Description** | **Required** | +| --- | --- | --- | +| baseUrl | baseUrl | True | +| accessId | Access ID | True | +| secretKey | Secret Key | True | +| defaultOrg | Default Organization | False | +| rating | Rating threshold for Malicious Indicators | False | +| confidence | Confidence threshold for Malicious Indicators | False | +| freshness | Indicator Reputation Freshness \(in days\) | False | +| proxyIp | ProxyIP \(or http://\) | False | +| proxyPort | ProxyPort | False | + +4. Click **Test** to validate the URLs, token, and connection. +## Commands +You can execute these commands from the Demisto 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. +### ip +*** +Searches for an indicator of type IP address. + + +#### Base Command + +`ip` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| ip | The IPv4 or IPv6 address. | Required | +| owners | A comma-separated list of a client's organizations, sources, or communities to which a user has permissions. For example, users with admin permissions can search for indicators belonging to all owners. | Optional | +| ratingThreshold | A list of results filtered by indicators whose threat rating is greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidenceThreshold | A list of results filtered by indicators whose confidence rating is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | + + +#### Command Example +```!ip ip=88.88.88.88``` + +#### Context Example +``` +{ "TC.Indicator": + [ { + "Rating": 0, + "Confidence": 0, + "Name": "88.88.88.88", + "LastModified": "2020-04-27T04:57:20Z", + "CreateDate": "2020-04-27T04:57:20Z", + "Owner": "Demisto Inc.", + Type": "Address", + "ID": 112677927 + } ], + "DBotScore": [ { + "Vendor": "ThreatConnect", + "Indicator": "88.88.88.88", + "Score": 1, + "Type": "ip" } ] +} +``` + +#### Human Readable Output + +>### ThreatConnect IP Reputation for: 88.88.88.88 +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 0 | 2020-04-27T04:57:20Z | 112677927 | 2020-04-27T04:57:20Z | 88.88.88.88 | Demisto Inc. | 0 | Address | + + +### url +*** +Searches for an indicator of type URL. + + +#### Base Command + +`url` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| url | The URL for which to search. For example, "www.demisto.com". | Required | +| owners | A comma-separated list of a client's organizations, sources, or communities to which a client’s API user has been granted permission. For example, "owner1", "owner2", or "owner3". | Optional | +| ratingThreshold | A list of results filtered by indicators whose threat rating is greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidenceThreshold | A list of results filtered by indicators whose confidence rating is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The date on which the indicator was last modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| URL.Data | string | The data of the URL indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | + + +#### Command Example +```!url url=https://www.domain.com``` + +#### Context Example +``` +{ + "DBotScore": [ + { + "Indicator": "https://www.domain.com", + "Score": 2, + "Type": "url", + "Vendor": "ThreatConnect" + } + ], + "TC": { + "Indicator": { + "Confidence": 50, + "CreateDate": "2020-04-23T14:41:16Z", + "ID": 112618313, + "LastModified": "2020-04-27T10:03:38Z", + "Name": "https://www.domain.com", + "Owner": "Demisto Inc.", + "Rating": 3, + "Type": "URL" + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect URL Reputation for: https://www.domain.com +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 50 | 2020-04-23T14:41:16Z | 112618313 | 2020-04-27T10:03:38Z | https://www.domain.com | Demisto Inc. | 3 | URL | +>### ThreatConnect URL Reputation for: https://www.domain.com +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 50 | 2020-04-23T14:41:16Z | 112618313 | 2020-04-27T10:03:38Z | https://www.domain.com | Demisto Inc. | 3 | URL | + + + +### file +*** +Searches for an indicator of type file. + + +#### Base Command + +`file` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| file | The hash of the file. Can be "MD5", "SHA-1", or "SHA-256". | Required | +| owners | A comma-separated list of a client's organizations, sources, or communities to which a user has permissions. For example, users with admin permissions can search for indicators belonging to all owners. | Optional | +| ratingThreshold | A list of results filtered by indicators whose threat rating is greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidenceThreshold | A list of results filtered by indicators whose confidence rating is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| File.MD5 | string | The MD5 hash of the indicator. | +| File.SHA1 | string | The SHA1 hash of the indicator. | +| File.SHA256 | string | The SHA256 hash of the indicator. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!file file=4a4a4e885f7189bbaa2fcc2f2403b128f79e951826c57c0e1ab50e085ae390e7``` + +#### Context Example +``` +{ + "TC.Indicator": [ { + "Rating": 0, + "Confidence": 0, + "LastModified": "2020-04-23T14:40:26Z", + "CreateDate": "2020-04-23T14:40:26Z", + "File": { + "SHA256": "4A4A4E885F7189BBAA2FCC2F2403B128F79E951826C57C0E1AB50E085AE390E7" + }, + "Owner": "Demisto Inc.", + "Type": "File", + "ID": 112618312 + } ], + "DBotScore": [{ + "Vendor": "ThreatConnect", + "Score": 1, + "Type": "file" + }] +} +``` + +#### Human Readable Output + +>### ThreatConnect File Report for: 4a4a4e885f7189bbaa2fcc2f2403b128f79e951826c57c0e1ab50e085ae390e7 +>|Confidence|Create Date|File|ID|Last Modified|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 0 | 2020-04-23T14:40:26Z | SHA256: 4A4A4E885F7189BBAA2FCC2F2403B128F79E951826C57C0E1AB50E085AE390E7 | 112618312 | 2020-04-23T14:40:26Z | Demisto Inc. | 0 | File | + + +### tc-owners +*** +Retrieves all owners for the current account. + + +#### Base Command + +`tc-owners` +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Owner.Name | string | The name of the owner. | +| TC.Owner.ID | string | The ID of the owner. | +| TC.Owner.Type | string | The type of the owner. | + + +#### Command Example +```!tc-owners``` + +#### Context Example +``` +{ + "TC": { + "Owner": [ + { + "ID": 737, + "Name": "Demisto Inc.", + "Type": "Organization" + }, + { + "ID": 646, + "Name": "Blocklist.de Strong IPs", + "Type": "Source" + }, + { + "ID": 716, + "Name": "BotScout Bot List", + "Type": "Source" + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Owners: +>|ID|Name|Type| +>|---|---|---| +>| 737 | Demisto Inc. | Organization | +>| 646 | Blocklist.de Strong IPs | Source | +>| 716 | BotScout Bot List | Source | + + +### tc-indicators +*** +Retrieves a list of all indicators. + + +#### Base Command + +`tc-indicators` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| owner | A list of results filtered by the owner of the indicator. | Optional | +| limit | The maximum number of results that can be returned. The default is 500. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The name of the domain. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-indicators limit=3 owner="Demisto Inc."``` + +#### Context Example +``` +{ + "DBotScore": [ + { + "Indicator": "88.88.88.88", + "Score": 1, + "Type": "ip", + "Vendor": "ThreatConnect" + }, + { + "Indicator": "domain.info", + "Score": 1, + "Type": "domain", + "Vendor": "ThreatConnect" + }, + { + "Indicator": "https://www.domain.com", + "Score": 2, + "Type": "url", + "Vendor": "ThreatConnect" + } + ], + "TC": { + "Indicator": [ + { + "Confidence": 0, + "CreateDate": "2020-05-10T09:45:19Z", + "ID": 112951652, + "LastModified": "2020-05-10T09:45:19Z", + "Name": "88.88.88.88", + "Owner": "Demisto Inc.", + "Rating": 0, + "Type": "Address" + }, + { + "Confidence": 0, + "CreateDate": "2020-04-23T14:42:21Z", + "ID": 112618314, + "LastModified": "2020-04-23T14:42:21Z", + "Name": "domain.info", + "Owner": "Demisto Inc.", + "Rating": 0, + "Type": "Host" + }, + { + "Confidence": 50, + "CreateDate": "2020-04-23T14:41:16Z", + "ID": 112618313, + "LastModified": "2020-04-27T10:03:38Z", + "Name": "https://www.domain.com", + "Owner": "Demisto Inc.", + "Rating": 3, + "Type": "URL" + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Indicators: +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 0 | 2020-05-10T09:45:19Z | 112951652 | 2020-05-10T09:45:19Z | 88.88.88.88 | Demisto Inc. | 0 | Address | +>| 0 | 2020-04-23T14:42:21Z | 112618314 | 2020-04-23T14:42:21Z | domain.info | Demisto Inc. | 0 | Host | +>| 50 | 2020-04-23T14:41:16Z | 112618313 | 2020-04-27T10:03:38Z | https://www.domain.com | Demisto Inc. | 3 | URL | + + +### tc-get-tags +*** +Returns a list of all ThreatConnect tags. + + +#### Base Command + +`tc-get-tags` +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Tags | Unknown | A list of tags. | + + +#### Command Example +```!tc-get-tags``` + +#### Context Example +``` +{ + "TC": { + "Tags": [ + "malicious file", + "malicious ip", + "malicious url", + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Tags: +>|Name| +>|---| +>| malicious file | +>| malicious ip | +>| malicious url | + + +### tc-tag-indicator +*** +Adds a tag to an existing indicator. + + +#### Base Command + +`tc-tag-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| tag | The name of the tag. | Required | +| indicator | The indicator to tag. For example, for an IP indicator, "8.8.8.8". | Required | +| owner | A list of indicators filtered by the owner. | Optional | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-tag-indicator indicator=99.99.99.99 tag="malicious ip"``` + +#### Context Example +``` +{} +``` + +#### Human Readable Output + +>Indicator 99.99.99.99 with ID 112951655, was tagged with: malicious ip + +### tc-get-indicator +*** +Retrieves information about an indicator. + + +#### Base Command + +`tc-get-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | The name of the indicator by which to search. The command retrieves information from all owners. Can be an IP address, a URL, or a file hash. | Required | +| indicator_type | Only for custom. Leave empty for standard ones | Optional | +| owners | Indicator Owner(s) | Optional | +| ratingThreshold | A list of results filtered by indicators whose threat rating is greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidenceThreshold | A list of results filtered by indicators whose confidence rating is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | +| group_associations | Retrieve Indicator Group Associations | Required | +| indicator_associations | Retrieve Indicator Associations | Optional | +| indicator_observations | Retrieve Indicator Observations | Optional | +| indicator_tags | Retrieve Indicator Tags | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the indicator of the URL. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The domain name of the indicator. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-get-indicator indicator=99.99.99.99 group_associations=false``` + +#### Context Example +``` +{ + "DBotScore": [ + { + "Indicator": "99.99.99.99", + "Score": 2, + "Type": "ip", + "Vendor": "ThreatConnect" + } + ], + "TC": { + "Indicator": { + "Confidence": 70, + "CreateDate": "2020-05-10T09:57:18Z", + "ID": 112951655, + "LastModified": "2020-05-10T09:57:27Z", + "Name": "99.99.99.99", + "Owner": "Demisto Inc.", + "Rating": 1, + "Type": "Address" + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect indicator for: 99.99.99.99 +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 70 | 2020-05-10T09:57:18Z | 112951655 | 2020-05-10T09:57:27Z | 99.99.99.99 | Demisto Inc. | 1 | Address | + + +### tc-get-indicators-by-tag +*** +Fetches all indicators that have a tag. + + +#### Base Command + +`tc-get-indicators-by-tag` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| tag | The name of the tag by which to filter. | Required | +| owner | A list of indicators filtered by the owner. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the tagged indicator. | +| TC.Indicator.Type | string | The type of the tagged indicator. | +| TC.Indicator.ID | string | The ID of the tagged indicator. | +| TC.Indicator.Description | string | The description of the tagged indicator. | +| TC.Indicator.Owner | string | The owner of the tagged indicator. | +| TC.Indicator.CreateDate | date | The date on which the tagged indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the tagged indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the tagged indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the tagged indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| DBotScore.Indicator | string | The value assigned by DBot for the tagged indicator. | +| DBotScore.Type | string | The type assigned by DBot for the tagged indicator. | +| DBotScore.Score | number | The score assigned by DBot for the tagged indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| IP.Address | string | The IP address of the tagged indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the tagged indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The domain name of the tagged indicator. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-get-indicators-by-tag tag="malicious ip"``` + +#### Context Example +``` +{ + "DBotScore": [ + { + "Indicator": "99.99.99.99", + "Score": 2, + "Type": "ip", + "Vendor": "ThreatConnect" + }, + { + "Indicator": "82.28.82.28", + "Score": 1, + "Type": "ip", + "Vendor": "ThreatConnect" + }, + { + "Indicator": "111.222.111.222", + "Score": 2, + "Type": "ip", + "Vendor": "ThreatConnect" + } + ], + "TC": { + "Indicator": [ + { + "Confidence": 70, + "CreateDate": "2020-05-10T09:57:18Z", + "ID": 112951655, + "LastModified": "2020-05-10T09:57:18Z", + "Name": "99.99.99.99", + "Owner": "Demisto Inc.", + "Rating": 2, + "Type": "Address" + }, + { + "Confidence": 0, + "CreateDate": "2018-10-18T11:12:20Z", + "ID": 59227820, + "LastModified": "2018-10-18T11:12:36Z", + "Name": "82.28.82.28", + "Owner": "Demisto Inc.", + "Rating": 0, + "Type": "Address" + }, + { + "Confidence": 20, + "CreateDate": "2018-10-22T19:03:29Z", + "Description": "Added critical rating", + "ID": 59253542, + "LastModified": "2018-12-19T15:55:57Z", + "Name": "111.222.111.222", + "Owner": "Demisto Inc.", + "Rating": 1, + "Type": "Address" + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Indicators with tag: malicious ip +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 70 | 2020-05-10T09:57:18Z | 112951655 | 2020-05-10T09:57:18Z | 99.99.99.99 | Demisto Inc. | 2 | Address | +>| 0 | 2018-10-18T11:12:20Z | 59227820 | 2018-10-18T11:12:36Z | 82.28.82.28 | Demisto Inc. | 0 | Address | +>| 20 | 2018-10-22T19:03:29Z | 59253542 | 2018-12-19T15:55:57Z | 111.222.111.222 | Demisto Inc. | 1 | Address | + + +### tc-add-indicator +*** +Adds a new indicator to ThreatConnect. + + +#### Base Command + +`tc-add-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | The indicator to add. | Required | +| rating | The threat rating of the indicator. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidence | The confidence rating of the indicator. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | +| owner | The owner of the new indicator. The default is the "defaultOrg" parameter. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name the indicator. | +| TC.Indicator.Type | string | The type of indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the added indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the added indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The name of the added indicator of the domain. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-add-indicator indicator=99.99.99.99 confidence=70 rating=2``` + +#### Context Example +``` +{ + "TC": { + "Indicator": { + "Confidence": 70, + "CreateDate": "2020-05-10T09:57:18Z", + "ID": 112951655, + "LastModified": "2020-05-10T09:57:18Z", + "Name": "99.99.99.99", + "Owner": "Demisto Inc.", + "Rating": 2, + "Type": "Address" + } + } +} +``` + +#### Human Readable Output + +>### Created new indicator successfully: +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 70 | 2020-05-10T09:57:18Z | 112951655 | 2020-05-10T09:57:18Z | 99.99.99.99 | Demisto Inc. | 2 | Address | + + +### tc-create-incident +*** +Creates a new incident group. + + +#### Base Command + +`tc-create-incident` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| owner | The owner of the new incident. The default is the "defaultOrg" parameter. | Optional | +| incidentName | The name of the incident group. | Required | +| eventDate | The creation time of an incident in the "2017-03-21T00:00:00Z" format. | Optional | +| tag | The tag applied to the incident. | Optional | +| securityLabel | The security label applied to the incident. Can be "TLP:RED", "TLP:GREEN", "TLP:AMBER", or "TLP:WHITE". | Optional | +| description | The description of the incident. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Incident.Name | string | The name of the new incident group. | +| TC.Incident.Owner | string | The owner of the new incident. | +| TC.Incident.EventDate | date | The date on which the event that indicates an incident occurred. | +| TC.Incident.Tag | string | The name of the tag of the new incident. | +| TC.Incident.SecurityLabel | string | The security label of the new incident. | +| TC.Incident.ID | Unknown | The ID of the new incident. | + + +#### Command Example +```!tc-create-incident incidentName=test_incident``` + +#### Context Example +``` +{ + "TC": { + "Incident": { + "EventDate": "2020-05-10T09:56:52Z", + "ID": 5156603, + "Name": "test_incident", + "Owner": "Demisto Inc." + } + } +} +``` + +#### Human Readable Output + +>Incident test_incident Created Successfully + +### tc-fetch-incidents +*** +Fetches incidents from ThreatConnect. + + +#### Base Command + +`tc-fetch-incidents` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| incidentId | The fetched incidents filtered by ID. | Optional | +| owner | The fetched incidents filtered by owner. | Optional | +| incidentName | The fetched incidents filtered by incident name. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Incident | string | The name of the group of fetched incidents. | +| TC.Incident.ID | string | The ID of the fetched incidents. | +| TC.Incident.Owner | string | The owner of the fetched incidents. | + + +#### Command Example +```!tc-fetch-incidents incidentId=5101576``` + +#### Context Example +``` +{ + "TC": { + "Incident": { + "dateAdded": "2020-04-21T06:54:46Z", + "eventDate": "2020-04-21T00:00:00Z", + "id": 5101576, + "name": "try", + "ownerName": "Demisto Inc.", + "weblink": "https://sandbox.threatconnect.com/auth/incident/incident.xhtml?incident=5101576" + } + }, + "ThreatConnect": { + "incidents": [ + { + "dateAdded": "2020-04-21T06:54:46Z", + "eventDate": "2020-04-21T00:00:00Z", + "id": 5101576, + "name": "try", + "ownerName": "Demisto Inc.", + "type": null, + "weblink": "https://sandbox.threatconnect.com/auth/incident/incident.xhtml?incident=5101576" + } + ] + } +} +``` + +#### Human Readable Output + +>### Incidents: +>|Date Added|Event Date|Id|Name|Owner Name|Type|Weblink| +>|---|---|---|---|---|---|---| +>| 2020-04-21T06:54:46Z | 2020-04-21T00:00:00Z | 5101576 | try | Demisto Inc. | | https://sandbox.threatconnect.com/auth/incident/incident.xhtml?incident=5101576 | + + +### tc-incident-associate-indicator +*** +Associates an indicator with an existing incident. The indicator must exist before running this command. To add an indicator, run the tc-add-indicator command. + + +#### Base Command + +`tc-incident-associate-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicatorType | The type of the indicator. Can be "ADDRESSES", "EMAIL_ADDRESSES", "URLS", "HOSTS", "FILES", or "CUSTOM_INDICATORS". | Required | +| incidentId | The ID of the incident to which the indicator is associated. | Required | +| indicator | The name of the indicator. | Required | +| owner | A list of indicators filtered by the owner. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator associated was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator associated was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| IP.Address | string | IP address of the associated indicator of the file. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the associated indicator of the file. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The name of the indicator of the domain. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-incident-associate-indicator indicator=99.99.99.99 indicatorType=ADDRESSES incidentId=5101577``` + +#### Context Example +``` +{ + "TC": { + "Incident": { + "dateAdded": "2020-04-21T07:03:56Z", + "eventDate": "2020-04-21T00:00:00Z", + "id": 5101577, + "name": "for_try", + "ownerName": "Demisto Inc.", + "weblink": "https://sandbox.threatconnect.com/auth/incident/incident.xhtml?incident=5101577" + } + } +} +``` + +#### Human Readable Output + +>Incident for_try with ID 5101577, was tagged with: 99.99.99.99 + +### domain +*** +Searches for an indicator of type domain. + + +#### Base Command + +`domain` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain | The name of the domain. | Required | +| owners | A comma-separated list of a client's organizations, sources, or communities to which a user has permissions. For example, users with admin permissions can search for indicators belonging to all owners. | Optional | +| ratingThreshold | A list of results filtered by indicators whose threat rating is greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". | Optional | +| confidenceThreshold | A list of results filtered by indicators whose confidence rating is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the of the indicator. | +| TC.Indicator.Type | string | The type of the domain. | +| TC.Indicator.ID | string | The ID of the domain. | +| TC.Indicator.Description | string | The description of the domain. | +| TC.Indicator.Owner | string | The owner of the domain. | +| TC.Indicator.CreateDate | date | The date on which the indicator of the domain was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator of the domain was modified. | +| TC.Indicator.Rating | number | The threat rating of the domain. | +| TC.Indicator.Confidence | number | The confidence rating of the domain. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| Domain.Name | string | The name of the domain. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | + + +#### Command Example +```!domain domain=domain.info``` + +#### Context Example +``` +{ + "TC.Indicator": [ { + "Rating": 0, + "Confidence": 0, + "Name": "domain.info" + "LastModified": "2020-04-23T14:42:21Z", + "CreateDate": "2020-04-23T14:42:21Z", + "Owner": "Demisto Inc.", + "Active": "false", + "Type": "Host", + "ID": 112618314 + } ], + "DBotScore": [{ + "Vendor": "ThreatConnect", + "Indicator": "domain.info", + "Score": 1, + "Type": "domain" + }] +} +``` + +#### Human Readable Output + +>### ThreatConnect Domain Reputation for: domain.info +>|Active|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---|---| +>| false | 0 | 2020-04-23T14:42:21Z | 112618314 | 2020-04-23T14:42:21Z | domain.info | Demisto Inc. | 0 | Host | + + +### tc-get-incident-associate-indicators +*** +Returns indicators that are related to a specific incident. + + +#### Base Command + +`tc-get-incident-associate-indicators` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| incidentId | The ID of the incident. | Required | +| owner | A list of indicators filtered by the owner. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the returned indicator. | +| TC.Indicator.Type | string | The type of the returned indicator. | +| TC.Indicator.ID | string | The ID of the returned indicator. | +| TC.Indicator.Description | string | The description of the returned indicator. | +| TC.Indicator.Owner | string | The owner of the returned indicator. | +| TC.Indicator.CreateDate | date | The date on which the returned indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the returned indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the returned indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the returned indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| DBotScore.Indicator | string | The value assigned by DBot for the indicator. | +| DBotScore.Type | string | The type assigned by DBot for the indicator. | +| DBotScore.Score | number | The score assigned by DBot for the indicator. | +| DBotScore.Vendor | string | The vendor used to calculate the score. | +| IP.Address | string | The IP address of the returned indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the returned indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The name of the domain. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-get-incident-associate-indicators incidentId=5101576 owner="Demisto Inc."``` + +#### Context Example +``` +{"TC.Indicator": [{ + "Rating": 0, + "Confidence": 0, + "Name": "88.88.88.88", + "LastModified": "2020-04-27T04:57:20Z", + "CreateDate": "2020-04-27T04:57:20Z", + "Owner": "Demisto Inc.", + "Type": "Address", + "ID": 112677927 } ], +"DBotScore": [ { + "Vendor": "ThreatConnect", + "Indicator": "88.88.88.88", + "Score": 1, + "Type": "ip" } ] +} +``` + +#### Human Readable Output + +>### Incident Associated Indicators: +>|Confidence|Create Date|ID|Last Modified|Name|Owner|Rating|Type| +>|---|---|---|---|---|---|---|---| +>| 0 | 2020-04-27T04:57:20Z | 112677927 | 2020-04-27T04:57:20Z | 88.88.88.88 | Demisto Inc. | 0 | Address | + + +### tc-update-indicator +*** +Updates the indicator in ThreatConnect. + + +#### Base Command + +`tc-update-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | The name of the updated indicator. | Required | +| rating | The threat rating of the updated indicator. | Optional | +| confidence | The confidence rating of the updated indicator. | Optional | +| size | The size of the file of the updated indicator. | Optional | +| dnsActive | The active DNS indicator (only for hosts). | Optional | +| whoisActive | The active indicator (only for hosts). | Optional | +| updatedValues | A comma-separated list of field:value pairs to update. For example, "rating=3", "confidence=42", and "description=helloWorld". | Optional | +| falsePositive | The updated indicator set as a false positive. Can be "True" or "False". | Optional | +| observations | The number observations on the updated indicator. | Optional | +| securityLabel | The security label applied to the incident. Can be "TLP:RED", "TLP:GREEN", "TLP:AMBER", or "TLP:WHITE". | Optional | +| threatAssessConfidence | Assesses the confidence rating of the indicator. | Optional | +| threatAssessRating | Assesses the threat rating of the indicator. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The domain name of the indicator. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-update-indicator indicator=99.99.99.99 rating=1``` + +#### Context Example +``` +{ + "TC": { + "Indicator": { + "Confidence": 70, + "CreateDate": "2020-05-10T09:57:18Z", + "ID": 112951655, + "LastModified": "2020-05-10T09:57:25Z", + "Name": "99.99.99.99", + "Owner": "Demisto Inc.", + "Rating": 1, + "Type": "Address" + } + } +} +``` + +#### Human Readable Output + +>Indicator 112951655 Updated Successfully + +### tc-delete-indicator-tag +*** +Removes a tag from a specified indicator. + + +#### Base Command + +`tc-delete-indicator-tag` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | The name of the indicator from which to remove a tag. | Required | +| tag | The name of the tag to remove from the indicator. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Indicator.Name | string | The name of the indicator. | +| TC.Indicator.Type | string | The type of the indicator. | +| TC.Indicator.ID | string | The ID of the indicator. | +| TC.Indicator.Description | string | The description of the indicator. | +| TC.Indicator.Owner | string | The owner of the indicator. | +| TC.Indicator.CreateDate | date | The date on which the indicator was created. | +| TC.Indicator.LastModified | date | The last date on which the indicator was modified. | +| TC.Indicator.Rating | number | The threat rating of the indicator. | +| TC.Indicator.Confidence | number | The confidence rating of the indicator. | +| TC.Indicator.WhoisActive | string | The active indicator \(for domains only\). | +| TC.Indicator.File.MD5 | string | The MD5 hash of the indicator of the file. | +| TC.Indicator.File.SHA1 | string | The SHA1 hash of the indicator of the file. | +| TC.Indicator.File.SHA256 | string | The SHA256 hash of the indicator of the file. | +| IP.Address | string | The IP address of the indicator. | +| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that made the decision. | +| IP.Malicious.Description | string | For malicious IP addresses, the full description. | +| URL.Data | string | The data of the URL of the indicator. | +| URL.Malicious.Vendor | string | For malicious URLs, the vendor that made the decision. | +| URL.Malicious.Description | string | For malicious URLs, the full description. | +| Domain.Name | string | The domain name of the indicator. | +| Domain.Malicious.Vendor | string | For malicious domains, the vendor that made the decision. | +| Domain.Malicious.Description | string | For malicious domains, the full description. | +| File.MD5 | string | The MD5 hash of the file. | +| File.SHA1 | string | The SHA1 hash of the file. | +| File.SHA256 | string | The SHA256 hash of the file. | +| File.Malicious.Vendor | string | For malicious files, the vendor that made the decision. | +| File.Malicious.Description | string | For malicious files, the full description. | + + +#### Command Example +```!tc-delete-indicator-tag indicator=99.99.99.99 tag="malicious ip"``` + +#### Context Example +``` +{ + "TC": { + "Indicator": { + "Confidence": 70, + "CreateDate": "2020-05-10T09:57:18Z", + "ID": 112951655, + "LastModified": "2020-05-10T09:57:18Z", + "Name": "99.99.99.99", + "Owner": "Demisto Inc.", + "Rating": 2, + "Type": "Address" + } + } +} +``` + +#### Human Readable Output + +>Removed tag malicious ip from indicator 99.99.99.99. + +### tc-delete-indicator +*** +Deletes an indicator from ThreatConnect. + + +#### Base Command + +`tc-delete-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | The name of the indicator to delete. | Required | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-delete-indicator indicator=99.99.99.99``` + +#### Context Example +``` +{} +``` + +#### Human Readable Output + +>Indicator 99.99.99.99 removed Successfully + +### tc-create-campaign +*** +Creates a group based on the "Campaign" type. + + +#### Base Command + +`tc-create-campaign` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The name of the campaign group. | Required | +| firstSeen | The earliest date on which the campaign was seen. | Optional | +| owner | The owner of the new incident. The default is the "defaultOrg" parameter. | Optional | +| description | The description of the campaign. | Optional | +| tag | The name of the tag to apply to the campaign. | Optional | +| securityLabel | The security label of the campaign. For example, "TLP:Green". | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Campaign.Name | string | The name of the campaign. | +| TC.Campaign.Owner | string | The owner of the campaign. | +| TC.Campaign.FirstSeen | date | The earliest date on which the campaign was seen. | +| TC.Campaign.Tag | string | The tag of the campaign. | +| TC.Campaign.SecurityLevel | string | The security label of the campaign. | +| TC.Campaign.ID | string | The ID of the campaign. | + + +#### Command Example +```!tc-create-campaign name=test_campaign description="test campaign"``` + +#### Context Example +``` +{ + "TC": { + "Campaign": { + "FirstSeen": "2020-05-10T00:00:00Z", + "ID": 5156601, + "Name": "test_campaign", + "Owner": "Demisto Inc." + } + } +} +``` + +#### Human Readable Output + +>Campaign test_campaign Created Successfully + +### tc-create-event +*** +Creates a group based on the "Event" type. + + +#### Base Command + +`tc-create-event` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The name of the event group. | Required | +| eventDate | The date on which the event occurred. If the date is not specified, the current date is used. | Optional | +| status | The status of the event. Can be "Needs Review", "False Positive", "No Further Action", or "Escalated". | Optional | +| owner | The owner of the event. | Optional | +| description | The description of the event. | Optional | +| tag | The tag of the event. | Optional | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Event.Name | string | The name of the event. | +| TC.Event.Date | date | The date of the event. | +| TC.Event.Status | string | The status of the event. | +| TC.Event.Owner | string | The owner of the event. | +| TC.Event.Tag | string | The tag of the event. | +| TC.Event.ID | string | The ID of the event. | + + +#### Command Example +```!tc-create-event name=test_event``` + +#### Context Example +``` +{ + "TC": { + "Event": { + "Date": "2020-05-10T09:56:50Z", + "ID": 5156602, + "Name": "test_event", + "Owner": "Demisto Inc." + } + } +} +``` + +#### Human Readable Output + +>Incident test_event Created Successfully + +### tc-create-threat +*** +Creates a group based on the "Threats" type. + + +#### Base Command + +`tc-create-threat` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The name of the threat group. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Threat.Name | string | The name of the threat. | +| TC.Threat.ID | string | The ID of the threat. | + + +#### Command Example +```!tc-create-threat name=test_threat``` + +#### Context Example +``` +{ + "TC": { + "Threat": { + "ID": 5156604, + "Name": "test_threat" + } + } +} +``` + +#### Human Readable Output + +>Threat test_threat Created Successfully + +### tc-delete-group +*** +Deletes a group. + + +#### Base Command + +`tc-delete-group` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| groupID | The ID of the group to delete. | Required | +| type | The type of the group to delete. Can be "Incidents", "Events", "Campaigns", or "Threats". | Required | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-delete-group groupID=5101578 type=Campaigns``` + +#### Human Readable Output +>campaigns 5101578 deleted Successfully + + +### tc-add-group-attribute +*** +Adds an attribute to a specified group. + + +#### Base Command + +`tc-add-group-attribute` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | The ID of the group to which to add attributes. To get the ID of the group, run the tc-get-groups command. | Required | +| attribute_type | The type of attribute to add to the group. The type is located in the UI in a specific group or under Org Config. | Required | +| attribute_value | The value of the attribute. | Required | +| group_type | The type of the group. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.DateAdded | Date | The date on which the attribute was added. | +| TC.Group.LastModified | Date | The date on which the added attribute was last modified. | +| TC.Group.Type | String | The type of the group to which the attribute was added. | +| TC.Group.Value | String | The value of the attribute added to the group. | +| TC.Group.ID | Number | The group ID to which the attribute was added. | + + +#### Command Example +```!tc-add-group-attribute group_id=5101576 group_type=incidents attribute_type=description attribute_value="test add group attribute"``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "DateAdded": "2020-05-10T09:57:00Z", + "ID": 23379726, + "LastModified": "2020-05-10T09:57:00Z", + "Type": "Description", + "Value": "test add group attribute" + } + } +} +``` + +#### Human Readable Output + +>### The attribute was added successfully to group 5101576 +>|Type|Value|ID|DateAdded|LastModified| +>|---|---|---|---|---| +>| Description | test add group attribute | 23379726 | 2020-05-10T09:57:00Z | 2020-05-10T09:57:00Z | + + +### tc-get-events +*** +Returns a list of events. + + +#### Base Command + +`tc-get-events` +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Event.DateAdded | Date | The date on which the event was added. | +| TC.Event.EventDate | Date | The date on which the event occurred. | +| TC.Event.ID | Number | The ID of the event. | +| TC.Event.OwnerName | String | The name of the owner of the event. | +| TC.Event.Status | String | The status of the event. | + + +#### Command Example +```!tc-get-events``` + +#### Context Example +``` +{ + "TC": { + "Event": [ + { + "DateAdded": "2020-05-10T09:56:51Z", + "EventDate": "2020-05-10T09:56:50Z", + "ID": 5156602, + "Name": "test_event", + "OwnerName": "Demisto Inc.", + "Status": "Needs Review" + }, + { + "DateAdded": "2020-05-10T05:07:52Z", + "EventDate": "2020-05-10T05:07:51Z", + "ID": 5156545, + "Name": "MyTest", + "OwnerName": "Demisto Inc.", + "Status": "Needs Review" + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Events +>|ID|Name|OwnerName|EventDate|DateAdded|Status| +>|---|---|---|---|---|---| +>| 5156602 | test_event | Demisto Inc. | 2020-05-10T09:56:50Z | 2020-05-10T09:56:51Z | Needs Review | +>| 5156545 | MyTest | Demisto Inc. | 2020-05-10T05:07:51Z | 2020-05-10T05:07:52Z | Needs Review | + + +### tc-get-groups +*** +Returns all groups, filtered by the group type. + + +#### Base Command + +`tc-get-groups` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of the group. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.DateAdded | Date | The date on which the group was added. | +| TC.Group.EventDate | Date | The date on which the event occurred. | +| TC.Group.Name | String | The name of the group. | +| TC.Group.OwnerName | String | The name of the owner of the group. | +| TC.Group.Status | String | The status of the group. | +| TC.Group.ID | Number | The ID of the group. | + + +#### Command Example +```!tc-get-groups group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": [ + { + "DateAdded": "2020-05-10T09:56:52Z", + "EventDate": "2020-05-10T00:00:00Z", + "ID": 5156603, + "Name": "test_incident", + "OwnerName": "Demisto Inc.", + "Status": null + }, + { + "DateAdded": "2020-05-10T09:54:44Z", + "EventDate": "2020-05-10T00:00:00Z", + "ID": 5156599, + "Name": "test_incident", + "OwnerName": "Demisto Inc.", + "Status": null + }, + { + "DateAdded": "2020-05-10T09:47:58Z", + "EventDate": "2020-05-10T00:00:00Z", + "ID": 5156595, + "Name": "test_incident", + "OwnerName": "Demisto Inc.", + "Status": null + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect incidents +>|ID|Name|OwnerName|EventDate|DateAdded| +>|---|---|---|---|---| +>| 5156603 | test_incident | Demisto Inc. | 2020-05-10T00:00:00Z | 2020-05-10T09:56:52Z | +>| 5156599 | test_incident | Demisto Inc. | 2020-05-10T00:00:00Z | 2020-05-10T09:54:44Z | +>| 5156595 | test_incident | Demisto Inc. | 2020-05-10T00:00:00Z | 2020-05-10T09:47:58Z | + + +### tc-add-group-security-label +*** +Adds a security label to a group. + + +#### Base Command + +`tc-add-group-security-label` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | The ID of the group to which to add the security label. To get the ID, run the tc-get-groups command. | Required | +| group_type | The type of the group to which to add the security label. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| security_label_name | The name of the security label to add to the group. For example, "TLP:GREEN". | Required | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-add-group-security-label group_id=5101576 group_type=incidents security_label_name=TLP:GREEN``` + +#### Context Example +``` +{} +``` + +#### Human Readable Output + +>The security label TLP:GREEN was added successfully to incidents 5101576 + +### tc-add-group-tag +*** +Adds tags to a specified group. + + +#### Base Command + +`tc-add-group-tag` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | The ID of the group to which to add the tag. To get the ID, run the tc-get-groups command. | Required | +| group_type | The type of the group to which to add the tag. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| tag_name | The name of the tag to add to the group. | Required | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-add-group-tag group_id=5101576 group_type=incidents tag_name="malicious ip"``` + +#### Context Example +``` +{} +``` + +#### Human Readable Output + +>The tag malicious ip was added successfully to group incidents 5101576 + +### tc-get-indicator-types +*** +Returns all indicator types available. + + +#### Base Command + +`tc-get-indicator-types` +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.IndicatorType.ApiBranch | String | The branch of the API. | +| TC.IndicatorType.ApiEntity | String | The entity of the API. | +| TC.IndicatorType.CasePreference | String | The case preference of the indicator. For example, "sensitive", "upper", or "lower". | +| TC.IndicatorType.Custom | Boolean | Whether the indicator is a custom indicator. | +| TC.IndicatorType.Parsable | Boolean | Whether the indicator can be parsed. | +| TC.IndicatorType.Value1Type | String | The name of the indicator. | +| TC.IndicatorType.Value1Label | String | The value label of the indicator. | + + +#### Command Example +```!tc-get-indicator-types``` + +#### Context Example +``` +{ + "TC": { + "IndicatorType": [ + { + "ApiBranch": "addresses", + "ApiEntity": "address", + "CasePreference": null, + "Custom": "false", + "Name": "Address", + "Parsable": "true", + "Value1Label": null, + "Value1Type": null + }, + { + "ApiBranch": "files", + "ApiEntity": "file", + "CasePreference": null, + "Custom": "false", + "Name": "File", + "Parsable": "true", + "Value1Label": "MD5", + "Value1Type": "text" + }, + { + "ApiBranch": "hosts", + "ApiEntity": "host", + "CasePreference": null, + "Custom": "false", + "Name": "Host", + "Parsable": "true", + "Value1Label": null, + "Value1Type": null + }, + { + "ApiBranch": "urls", + "ApiEntity": "url", + "CasePreference": null, + "Custom": "false", + "Name": "URL", + "Parsable": "true", + "Value1Label": null, + "Value1Type": null + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect indicator types +>|Name|Custom|Parsable|ApiBranch|CasePreference|Value1Type| +>|---|---|---|---|---|---| +>| Address | false | true | addresses | | | +>| File | false | true | files | | text | +>| Host | false | true | hosts | | | +>| URL | false | true | urls | | | + + +### tc-group-associate-indicator +*** +Associates an indicator with a group. + + +#### Base Command + +`tc-group-associate-indicator` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator_type | The type of the indicator. To get the available types, run the tc-get-indicator-types command. The indicator must be spelled as displayed in the ApiBranch column of the UI. | Required | +| indicator | The name of the indicator. For example, "indicator_type=emailAddresses" where "indicator=a@a.co.il". | Required | +| group_type | The type of the group. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group. To get the ID of the group, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.GroupID | Number | The ID of the group. | +| TC.Group.GroupType | String | The type of the group. | +| TC.Group.Indicator | String | The name of the indicator. | +| TC.Group.IndicatorType | String | The type of the indicator. | + + +#### Command Example +```tc-group-associate-indicator indicator_type=addresses group_id=5101576 group_type=incidents indicator=99.99.99.99``` + +#### Human Readable Output + + + +### tc-create-document-group +*** +Creates a document group. + + +#### Base Command + +`tc-create-document-group` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| file_name | The name of the file to display in the UI. | Required | +| name | The name of the file. | Required | +| malware | Whether the file is malware. If "true", ThreatConnect creates a password-protected ZIP file on your local machine that contains the sample and uploads the ZIP file. | Optional | +| password | The password of the ZIP file. | Optional | +| security_label | The security label of the group. | Optional | +| description | A description of the group. | Optional | +| entry_id | The file of the ID of the entry, as displayed in the War Room. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.Name | String | The name of the group. | +| TC.Group.Owner | String | The owner of the group. | +| TC.Group.EventDate | Date | The date on which the group was created. | +| TC.Group.Description | String | The description of the group. | +| TC.Group.SecurityLabel | String | The security label of the group. | +| TC.Group.ID | Number | The ID of the group to which the attribute was added. | + + +#### Command Example +```!tc-create-document-group entry_id=11@11 file_name=test.txt name=test_document``` + +#### Human Readable Output + + + +### tc-get-group +*** +Retrieves a single group. + + +#### Base Command + +`tc-get-group` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of group for which to return the ID. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group to retrieve. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.DateAdded | Date | The date on which the group was added. | +| TC.Group.EventDate | Date | The date on which the event occurred. | +| TC.Group.Name | String | The name of the group. | +| TC.Group.Owner.ID | Number | The ID of the group owner. | +| TC.Group.Owner.Name | String | The name of the group owner. | +| TC.Group.Owner.Type | String | The type of the owner. | +| TC.Group.Status | String | The status of the group. | + + +#### Command Example +```!tc-get-group group_id=5101576 group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "DateAdded": "2020-04-21T06:54:46Z", + "EventDate": "2020-04-21T00:00:00Z", + "ID": 5101576, + "Name": "try", + "Owner": { + "ID": 737, + "Name": "Demisto Inc.", + "Type": "Organization" + }, + "Status": null + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Group information +>|DateAdded|EventDate|ID|Name|Owner| +>|---|---|---|---|---| +>| 2020-04-21T06:54:46Z | 2020-04-21T00:00:00Z | 5101576 | try | Name: Demisto Inc.
ID: 737
Type: Organization | + + +### tc-get-group-attributes +*** +Retrieves the attribute of a group. + + +#### Base Command + +`tc-get-group-attributes` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of group for which to return the attribute. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group for which to return the attribute. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.Attribute.DateAdded | Date | The date on which the group was added. | +| TC.Group.Attribute.Displayed | Boolean | Whether the attribute is displayed on the UI. | +| TC.Group.Attribute.AttributeID | Number | The ID of the attribute. | +| TC.Group.Attribute.LastModified | Date | The date on which the attribute was last modified. | +| TC.Group.Attribute.Type | String | The type of the attribute. | +| TC.Group.Attribute.Value | String | The value of the attribute. | + + +#### Command Example +```!tc-get-group-attributes group_id=5101576 group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "Attribute": [ + { + "AttributeID": 23379726, + "DateAdded": "2020-05-10T09:57:00Z", + "Displayed": true, + "GroupID": 5101576, + "LastModified": "2020-05-10T09:57:00Z", + "Type": "Description", + "Value": "test add group attribute" + }, + { + "AttributeID": 23379725, + "DateAdded": "2020-05-10T09:54:51Z", + "Displayed": false, + "GroupID": 5101576, + "LastModified": "2020-05-10T09:54:51Z", + "Type": "Description", + "Value": "test add group attribute" + } + ] + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Group Attributes +>|AttributeID|Type|Value|DateAdded|LastModified|Displayed| +>|---|---|---|---|---|---| +>| 23379726 | Description | test add group attribute | 2020-05-10T09:57:00Z | 2020-05-10T09:57:00Z | true | +>| 23379725 | Description | test add group attribute | 2020-05-10T09:54:51Z | 2020-05-10T09:54:51Z | false | + + +### tc-get-group-security-labels +*** +Retrieves the security labels of a group. + + +#### Base Command + +`tc-get-group-security-labels` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of group for which to return the security labels. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group for which to return the security labels. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.SecurityLabel.Name | String | The name of the security label. | +| TC.Group.SecurityLabel.Description | String | The description of the security label. | +| TC.Group.SecurityLabel.DateAdded | Date | The date on which the security label was added. | + + +#### Command Example +```!tc-get-group-security-labels group_id=5101576 group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "SecurityLabel": { + "DateAdded": "2016-08-31T00:00:00Z", + "Description": "This security label is used for information that is useful for the awareness of all participating organizations as well as with peers within the broader community or sector.", + "GroupID": 5101576, + "Name": "TLP:GREEN" + } + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Group Security Labels +>|Name|Description|DateAdded| +>|---|---|---| +>| TLP:GREEN | This security label is used for information that is useful for the awareness of all participating organizations as well as with peers within the broader community or sector. | 2016-08-31T00:00:00Z | + + +### tc-get-group-tags +*** +Retrieves the tags of a group. + + +#### Base Command + +`tc-get-group-tags` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of group for which to return the tags. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group for which to return the tags. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.Tag.Name | String | The name of the tag. | + + +#### Command Example +```!tc-get-group-tags group_id=5101576 group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "Tag": { + "GroupID": 5101576, + "Name": "malicious ip" + } + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Group Tags +>|Name| +>|---| +>| malicious ip | + + +### tc-download-document +*** +Downloads the contents of a document. + + +#### Base Command + +`tc-download-document` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| document_id | The ID of the document. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| File.Size | Number | The size of the file. | +| File.SHA1 | String | The SHA1 hash of the file. | +| File.SHA256 | String | The SHA256 hash of the file. | +| File.Name | String | The name of the file. | +| File.SSDeep | String | The ssdeep hash of the file \(same as displayed in file entries\). | +| File.EntryID | String | The entry ID of the file. | +| File.Info | String | The information of the file. | +| File.Type | String | The type of the file. | +| File.MD5 | String | The MD5 hash of the file. | +| File.Extension | String | The extension of the file. | + + +#### Command Example +```!tc-download-document document_id=12345``` + +#### Human Readable Output + + + +### tc-get-group-indicators +*** +Returns indicators associated with a group. + + +#### Base Command + +`tc-get-group-indicators` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of the group for which to return the indicators. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group for which to return the indicators. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.Indicator.Summary | String | The summary of the indicator. | +| TC.Group.Indicator.ThreatAssessConfidence | String | The confidence rating of the indicator. | +| TC.Group.Indicator.IndicatorID | Number | The ID of the indicator. | +| TC.Group.Indicator.DateAdded | Date | The date on which the indicator was added. | +| TC.Group.Indicator.Type | String | The type of the indicator. | +| TC.Group.Indicator.Rating | Number | The threat rating of the indicator. | +| TC.Group.Indicator.ThreatAssertRating | Number | The rating of the threat assert. | +| TC.Group.Indicator.OwnerName | String | The name of the owner of the indicator. | +| TC.Group.Indicator.LastModified | Date | The date that the indicator was last modified. | + + +#### Command Example +```!tc-get-group-indicators group_type="incidents" group_id="5110299"``` + +#### Context Example +``` +{ + "TC.Group.Indicator": [ { + "Rating": 0, + "Confidence": 0, + "DateAdded": "2020-04-27T04:57:20Z", + "ThreatAssessConfidence": 53, + "LastModified": "2020-04-27T04:57:20Z", + "ThreatAssertRating": 3, + "Summary": "88.88.88.88", + "OwnerName": "Demisto Inc.", + "IndicatorID": 112677927, + "Type": "Address", + "GroupID": 5110299 } ] +} +``` + +#### Human Readable Output + +>### ThreatConnect Group Indicators +>|Confidence|DateAdded|GroupID|IndicatorID|LastModified|OwnerName|Rating|Summary|ThreatAssertRating|ThreatAssessConfidence|Type| +>|---|---|---|---|---|---|---|---|---|---|---| +>| 0 | 2020-04-27T04:57:20Z | 5110299 | 112677927 | 2020-04-27T04:57:20Z | Demisto Inc. | 0.0 | 88.88.88.88 | 3.0 | 53.0 | Address | + + +### tc-get-associated-groups +*** +Returns indicators associated with a specified group. + + +#### Base Command + +`tc-get-associated-groups` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of group. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group. To get the ID, run the tc-get-groups command. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.AssociatedGroup.DateAdded | Date | The date on which group was added. | +| TC.Group.AssociatedGroup.GroupID | Number | The ID of the group. | +| TC.Group.AssociatedGroup.Name | String | The name of the group. | +| TC.Group.AssociatedGroup.OwnerName | String | The name of the owner of the group. | +| TC.Group.AssociatedGroup.Type | String | The type of the group. | + + +#### Command Example +```!tc-get-associated-groups group_id=5101576 group_type=incidents``` + +#### Context Example +``` +{ + "TC": { + "Group": { + "AssociatedGroup": { + "DateAdded": "2020-04-27T05:03:28Z", + "GroupID": 5110299, + "Name": "test_as", + "OwnerName": "Demisto Inc.", + "Type": "Incident" + } + } + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Associated Groups +>|GroupID|Name|Type|OwnerName|DateAdded| +>|---|---|---|---|---| +>| 5110299 | test_as | Incident | Demisto Inc. | 2020-04-27T05:03:28Z | + + +### tc-associate-group-to-group +*** +Associates one group with another group. + + +#### Base Command + +`tc-associate-group-to-group` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_type | The type of the group. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| group_id | The ID of the group. To get the ID of the group, run the tc-get-groups command. | Required | +| associated_group_type | The type of group to associate. Can be "adversaries", "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", "reports", "signatures", or "threats". | Required | +| associated_group_id | The ID of the group to associate. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| TC.Group.AssociatedGroup.AssociatedGroupID | Number | The ID of the associated group. | +| TC.Group.AssociatedGroup.AssociatedGroupType | String | The type of the associated group. | +| TC.Group.AssociatedGroup.GroupID | Number | The ID of the group to associate to. | +| TC.Group.AssociatedGroup.GroupType | String | The type of the group to associate to. | + + +#### Command Example +```!tc-associate-group-to-group group_id=5101576 group_type=incidents associated_group_id=5101578 associated_group_type=campaigns``` + +##### Context Example +``` +{ + "TC.Group.AssociatedGroup": { + "GroupType": "incidents", + "AssociatedGroupID": 5101578, + "AssociatedGroupType": "campaigns", + "GroupID": 5101576 + } +} +``` + +>##### Human Readable Output +>The group 5101578 was associated successfully. + + + +### tc-get-indicator-owners +*** +Get Owner for Indicator + + +#### Base Command + +`tc-get-indicator-owners` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| indicator | Indicator Value | Required | + + +#### Context Output + +There is no context output for this command. + +#### Command Example +```!tc-get-indicator-owners indicator=99.99.99.99``` + +#### Context Example +``` +{ + "TC": { + "Owners": [ + { + "id": 737, + "name": "Demisto Inc.", + "type": "Organization" + } + ] + } +} +``` + +#### Human Readable Output + +>### ThreatConnect Owners for Indicator:99.99.99.99 +>|id|name|type| +>|---|---|---| +>| 737 | Demisto Inc. | Organization | + diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.py b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.py new file mode 100644 index 000000000000..d29a081d8209 --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.py @@ -0,0 +1,2130 @@ +''' IMPORTS ''' +import demistomock as demisto +from CommonServerPython import * + + +from urllib.parse import urlparse, quote +from datetime import timedelta +from distutils.util import strtobool +from threatconnect import ThreatConnect +from threatconnect.RequestObject import RequestObject +from threatconnect.Config.ResourceType import ResourceType +import copy + +'''GLOBAL VARS''' +FRESHNESS = int(demisto.params().get('freshness', 0)) +MAX_CONTEXT = 100 +''' HELPER FUNCTIONS ''' + + +def get_client(): + params = demisto.params() + access = params['accessId'] + secret = params['secretKey'] + default_org = params.get('defaultOrg') + url = params['baseUrl'] + proxy_ip = params.get('proxyIp') + proxy_port = params.get('proxyPort') + + tc = ThreatConnect(access, secret, default_org, url) + if proxy_ip and proxy_port and len(proxy_ip) > 0 and len(proxy_port) > 0: + tc.set_proxies(proxy_ip, int(proxy_port)) + + return tc + + +def calculate_freshness_time(freshness): + t = datetime.now() - timedelta(days=freshness) + return t.strftime('%Y-%m-%dT00:00:00Z') + + +def create_context(indicators, include_dbot_score=False): + context = { + 'DBotScore': [], + outputPaths['ip']: [], + outputPaths['url']: [], + outputPaths['domain']: [], + outputPaths['file']: [], + 'TC.Indicator(val.ID && val.ID === obj.ID)': [], + } # type: dict + tc_type_to_demisto_type = { + 'Address': 'ip', + 'URL': 'url', + 'Host': 'domain', + 'File': 'file' + } + type_to_value_field = { + 'Address': 'ip', + 'URL': 'text', + 'Host': 'hostName', + 'File': 'md5' + } + + for ind in indicators: + indicator_type = tc_type_to_demisto_type.get(ind['type'], ind['type']) + value_field = type_to_value_field.get(ind['type'], 'summary') + value = ind.get(value_field, ind.get('summary', '')) + + if ind.get('confidence') is not None: # returned in specific indicator request - SDK + confidence = int(ind['confidence']) + else: + # returned in general indicator request - REST API + confidence = int(ind.get('threatAssessConfidence', 0)) + + if ind.get('rating') is not None: # returned in specific indicator request - SDK + rating = int(ind['rating']) + else: + # returned in general indicator request - REST API + rating = int(ind.get('threatAssessRating', 0)) + + if confidence >= int(demisto.params()['rating']) and rating >= int(demisto.params()['confidence']): + dbot_score = 3 + desc = '' + if hasattr(ind, 'description'): + desc = ind.description + mal = { + 'Malicious': { + 'Vendor': 'ThreatConnect', + 'Description': desc, + } + } + if indicator_type == 'ip': + mal['Address'] = value + + elif indicator_type == 'file': + mal['MD5'] = value + mal['SHA1'] = ind.get('sha1') + mal['SHA256'] = ind.get('sha256') + + elif indicator_type == 'url': + mal['Data'] = value + + elif indicator_type == 'domain': + mal['Name'] = value + + context_path = outputPaths.get(indicator_type) + if context_path is not None: + context[context_path].append(mal) + + elif int(rating) >= 1: + dbot_score = 2 + else: + dbot_score = 1 + + if include_dbot_score: + context['DBotScore'].append({ + 'Indicator': value, + 'Score': dbot_score, + 'Type': indicator_type, + 'Vendor': 'ThreatConnect' + }) + + context['TC.Indicator(val.ID && val.ID === obj.ID)'].append({ + 'ID': ind['id'], + 'Name': value, + 'Type': ind['type'], + 'Owner': ind.get('ownerName', ind.get('owner')), + 'Description': ind.get('description'), + 'CreateDate': ind['dateAdded'], + 'LastModified': ind['lastModified'], + 'Rating': rating, + 'Confidence': confidence, + + # relevant for domain + 'Active': ind.get('whoisActive'), + + # relevant for file + 'File.MD5': ind.get('md5'), + 'File.SHA1': ind.get('sha1'), + 'File.SHA256': ind.get('sha256'), + }) + + if 'group_associations' in ind: + if ind['group_associations']: + context['TC.Indicator(val.ID && val.ID === obj.ID)'][0]['IndicatorGroups'] = ind['group_associations'] + + if 'indicator_associations' in ind: + if ind['indicator_associations']: + context['TC.Indicator(val.ID && val.ID === obj.ID)'][0]['IndicatorAssociations'] = ind[ + 'indicator_associations'] + + if 'indicator_tags' in ind: + if ind['indicator_tags']: + context['TC.Indicator(val.ID && val.ID === obj.ID)'][0]['IndicatorTags'] = ind['indicator_tags'] + + if 'indicator_observations' in ind: + if ind['indicator_observations']: + context['TC.Indicator(val.ID && val.ID === obj.ID)'][0]['IndicatorsObservations'] = ind[ + 'indicator_observations'] + + context = {k: createContext(v, removeNull=True)[:MAX_CONTEXT] for k, v in context.items() if v} + return context, context.get('TC.Indicator(val.ID && val.ID === obj.ID)', []) + + +def get_xindapi(tc, indicator_value, indicator_type, owner): + """ + :param tc: tc object + :param indicator_value: the indicator e.g. domain.com 8.8.8.8 ... + :param indicator_type: the indicator type e.g. URL, IP ... + :param owner: indicator owner e.g. Demisto Inc. + :return: the data of the indicator + """ + stdout = [] + types = tc_get_indicator_types_request()['data']['indicatorType'] + if indicator_type: + for item in types: + if item['apiEntity'] == indicator_type.lower(): + api_branch = item['apiBranch'] + ro = RequestObject() + ro.set_http_method('GET') + ro.set_owner(owner) + ro.set_request_uri('/v2/indicators/' + str(api_branch) + "/" + quote(indicator_value).replace("/", "%2F")) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if results.json()['status'] == 'Success': + res = results.json()['data'][item['apiEntity']] + res['owner'] = res['owner']['name'] + res['type'] = item['name'] + stdout.append(res) + break + else: + for item in types: + api_branch = item['apiBranch'] + ro = RequestObject() + ro.set_http_method('GET') + ro.set_owner(owner) + ro.set_request_uri('/v2/indicators/' + str(api_branch) + "/" + quote(indicator_value).replace("/", "%2F")) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if results.json()['status'] == 'Success': + res = results.json()['data'][item['apiEntity']] + res['ownerName'] = res['owner']['name'] + res['type'] = item['name'] + stdout.append(res) + break + + return stdout + + +def get_indicator_owner(indicator_value, owner=None): + tc = get_client() + owner = demisto.params()['defaultOrg'] if not owner else owner + indsowners = {} + types = tc_get_indicator_types_request()['data']['indicatorType'] + for item in types: + apiBranch = item['apiBranch'] + ro = RequestObject() + ro.set_http_method('GET') + ro.set_owner(owner) + ro.set_request_uri('/v2/indicators/{}/{}/owners'.format(apiBranch, quote(indicator_value).replace("/", "%2F"))) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + ownersRaw = results.json() + if 'status' in ownersRaw: + if ownersRaw['status'] == 'Success': + if len(ownersRaw['data']['owner']) > 0: + indsowners = results.json() + break + return indsowners + + +# pylint: disable=E1101 +def get_indicators(indicator_value=None, indicator_type=None, owners=None, rating_threshold=-1, confidence_threshold=-1, + freshness=None, associated_groups=False, associated_indicators=False, include_observations=False, + include_tags=False, loopowners=False): + tc = get_client() + raw_indicators = [] + if owners and owners.find(",") > -1: + owners = owners.split(",") + for owner in owners: + raw_indicators = get_xindapi(tc, indicator_value, indicator_type, owner) + if raw_indicators: + owners = owner + break + else: + raw_indicators = get_xindapi(tc, indicator_value, indicator_type, owners) + if raw_indicators and loopowners is True: + owners = get_indicator_owner(indicator_value) + if 'owner' in owners.get('data', {}): + for owner in owners['data']['owner']: + raw_indicators = get_xindapi(tc, indicator_value, indicator_type, owner['name']) + if raw_indicators: + owners = owner['name'] + break + else: + demisto.results("Unable to indentify the owner for the given indicator") + else: + demisto.results("Unable to indentify the owner for the given indicator") + + indicators = raw_indicators + associatedIndicators = [] + indicator_observations = [] + + if raw_indicators: + if associated_groups: + indicators[0]['group_associations'] = tc_associated_groups(tc, owners, indicator_value, raw_indicators[0]['type']) + + if include_tags: + indicators[0]['indicator_tags'] = tc_indicator_get_tags(tc, owners, indicator_value, raw_indicators[0]['type']) + + if include_observations: + try: + for indicator in raw_indicators: + for observation in indicator.observations: + indicator_observations.append({"count": observation.count, "date_observed": observation.date_observed}) + indicators[0]['indicator_observations'] = indicator_observations + except Exception as error: + demisto.error(str(error)) + indicators[0]['indicator_observations'] = indicator_observations + + if associated_indicators: + try: + for indicator in raw_indicators: + for associated_indicator in indicator.indicator_associations: + associatedIndicators.append({"id": associated_indicator.id, + "indicator": associated_indicator.indicator, + "type": associated_indicator.type, + "description": associated_indicator.description, + "owner_name": associated_indicator.owner_name, + "rating": associated_indicator.rating, + "confidence": associated_indicator.confidence, + "date_added": associated_indicator.date_added, + "last_modified": associated_indicator.last_modified, + "weblink": associated_indicator.weblink}) + indicators[0]['indicator_associations'] = associatedIndicators + except Exception as error: + demisto.error(str(error)) + indicators[0]['indicator_associations'] = associatedIndicators + + return indicators + + +''' FUNCTIONS ''' + + +def ip_command(): + args = demisto.args() + owners = args.get('owners', demisto.params().get('defaultOrg')) + if not owners: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + rating_threshold = int(args.get('ratingThreshold', -1)) + confidence_threshold = int(args.get('confidenceThreshold', -1)) + ip_addr = args['ip'] + + ec, indicators = ip(ip_addr, owners, rating_threshold, confidence_threshold) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect IP Reputation for: {}'.format(ip_addr), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +@logger +def ip(ip_addr, owners, rating_threshold, confidence_threshold): + indicators = get_indicators(ip_addr, 'Address', owners, rating_threshold, confidence_threshold) + + if not indicators: + demisto.results('Make sure that the indicator exists in your ThreatConnect environment') + ec, indicators = create_context(indicators, include_dbot_score=True) + + return ec, indicators + + +def url_command(): + args = demisto.args() + owners = args.get('owners', demisto.params().get('defaultOrg')) + if not owners: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + url_addr = args['url'] + parsed_url = urlparse(url_addr) + if not parsed_url.scheme: + return_error('Please provide a valid URL including a protocol (http/https)') + rating_threshold = int(args.get('ratingThreshold', -1)) + confidence_threshold = int(args.get('confidenceThreshold', -1)) + + ec, indicators = url(url_addr, owners, rating_threshold, confidence_threshold) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect URL Reputation for: {}'.format(url_addr), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +@logger +def url(url_addr, owners, rating_threshold, confidence_threshold): + indicators = get_indicators(url_addr, 'URL', owners, rating_threshold, confidence_threshold) + if not indicators: + demisto.results('Make sure that the indicator exists in your ThreatConnect environment') + ec, indicators = create_context(indicators, include_dbot_score=True) + + return ec, indicators + + +def file_command(): + args = demisto.args() + owners = args.get('owners', demisto.params().get('defaultOrg')) + if not owners: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + file_name = args['file'] + rating_threshold = int(args.get('ratingThreshold', -1)) + confidence_threshold = int(args.get('confidenceThreshold', -1)) + + ec, indicators = _file(file_name, owners, rating_threshold, confidence_threshold) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect File Report for: {}'.format(file_name), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +@logger +def _file(url_addr, owners, rating_threshold, confidence_threshold): + indicators = get_indicators(url_addr, 'File', owners, rating_threshold, confidence_threshold) + if not indicators: + demisto.results('Make sure that the indicator exists in your ThreatConnect environment') + ec, indicators = create_context(indicators, include_dbot_score=True) + + return ec, indicators + + +def domain_command(): + args = demisto.args() + owners = args.get('owners', demisto.params().get('defaultOrg')) + if not owners: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + rating_threshold = int(args.get('ratingThreshold', -1)) + confidence_threshold = int(args.get('confidenceThreshold', -1)) + domain_addr = args['domain'] + + ec, indicators = domain(domain_addr, owners, rating_threshold, confidence_threshold) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Domain Reputation for: {}'.format(domain_addr), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +@logger +def domain(domain_addr, owners, rating_threshold, confidence_threshold): + indicators = get_indicators(domain_addr, 'Host', owners, rating_threshold, confidence_threshold) + ec, indicators = create_context(indicators, include_dbot_score=True) + + return ec, indicators + + +def tc_owners_command(): + raw_owners = tc_owners() + owners = [] + for owner in raw_owners['data']['owner']: + owners.append({ + 'ID': owner['id'], + 'Type': owner['type'], + 'Name': owner['name'] + }) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_owners, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Owners:', owners), + 'EntryContext': {'TC.Owner(val.ID && val.ID === obj.ID)': owners} + }) + + +def tc_owners(): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/owners') + results = tc.api_request(ro) + + return results.json() + + +def tc_get_indicator_owners(): + owners = [] + ownersRaw = get_indicator_owner(demisto.args()['indicator']) + if 'status' in ownersRaw: + if ownersRaw['status'] == 'Success': + if len(ownersRaw['data']['owner']) > 0: + owners = ownersRaw['data']['owner'] + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': ownersRaw, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Owners for Indicator:' + demisto.args()['indicator'], owners), + 'EntryContext': {'TC.Owners': owners} + }) + + +def tc_associated_groups(tc, owners, indicator_value, indicator_type): + group_associations = [] + types = tc_get_indicator_types_request()['data']['indicatorType'] + for item in types: + if indicator_type is not None: + if item['name'] == indicator_type: + apiBranch = item['apiBranch'] + else: + # meaning we got an indicator but SDK returned a null type + apiBranch = None + + ro = RequestObject() + ro.set_http_method('GET') + ro.set_owner(owners) + if apiBranch is not None: + ro.set_request_uri("/v2/indicators/{}/{}/groups".format(apiBranch, indicator_value)) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if 'data' in results.json(): + if 'group' in results.json()['data']: + group_associations = results.json()['data']['group'] + else: + group_associations = [] + else: + try: + for item in types: + ro.set_request_uri( + "/v2/indicators/{}/{}/groups".format(item['apiBranch'], quote(indicator_value, safe=''))) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if 'data' in results.json(): + if 'group' in results.json()['data']: + group_associations = results.json()['data']['group'] + break + else: + group_associations = [] + except Exception as error: + demisto.error(str(error)) + + return group_associations + + +def tc_indicator_get_tags(tc, owners, indicator_value, indicator_type): + tags = [] + types = tc_get_indicator_types_request()['data']['indicatorType'] + for item in types: + if indicator_type is not None: + if item['name'] == indicator_type: + apiBranch = item['apiBranch'] + else: + # meaning we got an indicator but SDK returned a null type + apiBranch = None + + ro = RequestObject() + ro.set_http_method('GET') + ro.set_owner(owners) + if apiBranch is not None: + ro.set_request_uri("/v2/indicators/{}/{}/tags".format(apiBranch, indicator_value)) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if 'data' in results.json(): + if 'tag' in results.json()['data']: + tags = results.json()['data']['tag'] + else: + tags = [] + else: + try: + for item in types: + ro.set_request_uri( + "/v2/indicators/{}/{}/tags".format(item['apiBranch'], quote(indicator_value, safe=''))) + results = tc.api_request(ro) + if results.headers['content-type'] == 'application/json': + if 'data' in results.json(): + if 'tag' in results.json()['data']: + tags = results.json()['data']['tag'] + break + else: + tags = [] + except Exception as error: + demisto.error(str(error)) + + return tags + + +def tc_indicators_command(): + args = demisto.args() + limit = int(args.get('limit', 500)) + owners = args.get('owners') + ec, indicators, raw_response = tc_indicators(owners, limit) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_response, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Indicators:', indicators, headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +# @loger +def tc_indicators(owners, limit): + tc = get_client() + tc.set_api_result_limit(limit) + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/indicators?resultLimit={}'.format(limit)) + + if owners is not None: + ro.set_owner(owners) + ro.set_owner_allowed(True) + + response = tc.api_request(ro).json() + indicators = response['data']['indicator'] + ec, indicators = create_context(indicators, include_dbot_score=True) + + return ec, indicators, response + + +def tc_get_tags_command(): + raw_response = tc_get_tags() + tags = [t['name'] for t in raw_response['data']['tag']] + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_response, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Tags:', tags, headers='Name'), + 'EntryContext': {'TC.Tags': tags} + }) + + +def tc_get_tags(): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/tags') + + return tc.api_request(ro).json() + + +def tc_tag_indicator_command(): + args = demisto.args() + indicator = args['indicator'] + tag = args['tag'] + owners = args.get('owner') + indicators = tc_tag_indicator(indicator, tag, owners) + + md = [] + for ind in indicators: + md.append('Indicator {} with ID {}, was tagged with: {}'.format(indicator, ind.id, tag)) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['text'], + 'Contents': '\n'.join(md) + }) + + +def tc_tag_indicator(indicator, tag, owners=None): + tc = get_client() + indicators = tc.indicators() + filter1 = indicators.add_filter() + filter1.add_indicator(indicator) + + if owners is not None: + owners = owners.split(",") + filter1.add_owner(owners) + + indicators = indicators.retrieve() + for indicator in indicators: + indicator.add_tag(tag) + indicator.commit() + + return indicators + + +def tc_get_indicator_command(): + args = demisto.args() + owners = args.get('owners') + if not owners: + if 'defaultOrg' in demisto.params(): + owners = demisto.params().get('defaultOrg') + else: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + rating_threshold = int(args.get('ratingThreshold', -1)) + confidence_threshold = int(args.get('confidenceThreshold', -1)) + indicator = args['indicator'] + associated_groups = json.loads(args['group_associations'].lower()) + associated_indicators = json.loads(args['indicator_associations'].lower()) + include_tags = json.loads(args['indicator_tags'].lower()) + include_observations = json.loads(args['indicator_observations'].lower()) + if 'indicator_type' in args: + indicator_type = args['indicator_type'] + else: + indicator_type = None + + ec, indicators, raw_indicators, indicators_associations, indicator_groups, indicator_observations, indicator_tags \ + = tc_get_indicator(indicator, owners, rating_threshold, confidence_threshold, associated_groups, + associated_indicators, include_observations, include_tags, indicator_type) + # remove extra items from the indicator markdown + if ec == []: + ec = {} + if ec: + indicators = copy.deepcopy(ec) + indicators = indicators['TC.Indicator(val.ID && val.ID === obj.ID)'] + + if associated_groups: + if 'IndicatorGroups' in indicators[0]: + del indicators[0]['IndicatorGroups'] + if associated_indicators: + if 'IndicatorAssociations' in indicators[0]: + del indicators[0]['IndicatorAssociations'] + if include_tags: + if 'IndicatorTags' in indicators[0]: + del indicators[0]['IndicatorTags'] + if include_observations: + if 'IndicatorsObservations' in indicators[0]: + del indicators[0]['IndicatorsObservations'] + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect indicator for: {}'.format(indicator), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + if associated_groups: + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicator_groups, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Associated Groups for indicator: {}'.format(indicator), + indicator_groups, + headerTransform=pascalToSpace) + }) + + if associated_indicators: + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicators_associations, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Associated Indicators for indicator: {}'.format(indicator), + indicators_associations, + headerTransform=pascalToSpace) + }) + + if include_tags: + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicator_tags, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Tags for indicator: {}'.format(indicator), indicator_tags, + headerTransform=pascalToSpace) + }) + + if include_observations: + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': indicator_observations, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Observations for indicator: {}'.format(indicator), + indicator_observations, + headerTransform=pascalToSpace) + }) + + +# @loger +def tc_get_indicator(indicator, owners, rating_threshold, confidence_threshold, associated_groups, associated_indicators, + include_observations, include_tags, indicator_type, loopowners=False): + raw_indicators = get_indicators(indicator, indicator_type=indicator_type, owners=owners, rating_threshold=rating_threshold, + confidence_threshold=confidence_threshold, associated_groups=associated_groups, + associated_indicators=associated_indicators, include_observations=include_observations, + include_tags=include_tags, loopowners=loopowners) + ec = [] + indicators = [] + indicator_groups = [] + indicators_associations = [] + indicator_tags = [] + indicator_observations = [] + + if len(raw_indicators) > 0: + ec, indicators = create_context(raw_indicators, include_dbot_score=True) + if 'group_associations' in raw_indicators[0]: + indicator_groups = raw_indicators[0]['group_associations'] + + if 'indicator_associations' in raw_indicators[0]: + indicators_associations = raw_indicators[0]['indicator_associations'] + + if 'indicator_tags' in raw_indicators[0]: + indicator_tags = raw_indicators[0]['indicator_tags'] + + if 'indicator_observations' in raw_indicators[0]: + indicator_observations = raw_indicators[0]['indicator_observations'] + + return ec, indicators, raw_indicators, indicators_associations, indicator_groups, indicator_observations, indicator_tags + + +def tc_get_indicators_by_tag_command(): + args = demisto.args() + tag = args['tag'] + owner = args.get('owner') + response = tc_get_indicators_by_tag(tag, owner) + raw_indicators = response['data']['indicator'] + ec, indicators = create_context(raw_indicators, include_dbot_score=True) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': response, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('ThreatConnect Indicators with tag: {}'.format(tag), indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +# @loger +def tc_get_indicators_by_tag(tag, owner): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + cmd = '/v2/tags/{}/indicators'.format(tag) + if owner is not None: + cmd += '?owner={}'.format(owner) + + ro.set_request_uri(cmd) + + return tc.api_request(ro).json() + + +def tc_add_indicator_command(): + args = demisto.args() + indicator = args['indicator'] + owner = args.get('owner', demisto.params().get('defaultOrg')) + if not owner: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + rating = int(args.get('rating', 0)) + confidence = int(args.get('confidence', 0)) + + tc_add_indicator(indicator, owner, rating, confidence) + # get the indicator for full object data + raw_indicators = get_indicators(indicator, owners=owner) + ec, indicators = create_context(raw_indicators) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('Created new indicator successfully:', indicators, + headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +# @loger +def tc_add_indicator(indicator, organization, rating=0, confidence=0): + tc = get_client() + indicators = tc.indicators() + indicator = indicators.add(indicator, organization) + indicator.set_rating(rating) + indicator.set_confidence(confidence) + + return indicator.commit().json + + +def tc_create_incident_command(): + args = demisto.args() + incident_name = args['incidentName'] + owner = args.get('owner', demisto.params()['defaultOrg']) + if not owner: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + event_date = args.get('eventDate', datetime.utcnow().isoformat().split('.')[0] + 'Z') + tag = args.get('tag') + security_label = args.get('securityLabel') + description = args.get('description') + raw_incident = tc_create_incident(incident_name, owner, event_date, tag, security_label, description) + ec = { + 'ID': raw_incident['id'], + 'Name': raw_incident['name'], + 'Owner': raw_incident['ownerName'], + 'EventDate': raw_incident['eventDate'], + 'Tag': tag, + 'SecurityLabel': security_label + } + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_incident, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': 'Incident {} Created Successfully'.format(incident_name), + 'EntryContext': { + 'TC.Incident(val.ID && val.ID === obj.ID)': createContext([ec], removeNull=True) + } + }) + + +# @loger +def tc_create_incident(incident_name, owner, event_date, tag=None, security_label=None, description=None): + tc = get_client() + incidents = tc.incidents() + incident = incidents.add(incident_name, owner) + incident.set_event_date(event_date) + if tag is not None: + incident.add_tag(tag) + if security_label is not None: + incident.set_security_label(security_label) + if description is not None: + incident.add_attribute('Description', description) + + return json.loads(incident.commit().json) + + +def tc_fetch_incidents_command(): + args = demisto.args() + incident_id = args.get('incidentId') + incident_name = args.get('incidentName') + owner = args.get('owner') + + raw_incidents = tc_fetch_incidents(incident_id, incident_name, owner) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_incidents, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('Incidents:', raw_incidents, headerTransform=pascalToSpace), + 'EntryContext': { + 'TC.Incident(val.ID && val.ID === obj.ID)': createContext(raw_incidents, removeNull=True), + 'ThreatConnect.incidents': raw_incidents # backward compatible + } + }) + + +# @loger +def tc_fetch_incidents(incident_id, incident_name, owner): + tc = get_client() + incidents = tc.incidents() + if any((incident_id, owner, incident_name)): + filter1 = incidents.add_filter() + if incident_id is not None: + filter1.add_id(int(incident_id)) + if owner is not None: + filter1.add_owner(owner) + if incident_name is not None: + filter1.add_pf_name(incident_name) + + incidents.retrieve() + return [json.loads(incident.json) for incident in incidents] + + +def tc_get_incident_associate_indicators_command(): + args = demisto.args() + incident_id = int(args['incidentId']) + owners = args.get('owner') + if owners is not None: + owners = owners.split(",") + + raw_indicators = tc_get_incident_associate_indicators(incident_id, owners) + ec, indicators = create_context(raw_indicators, include_dbot_score=True) + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': tableToMarkdown('Incident Associated Indicators:', indicators, headerTransform=pascalToSpace), + 'EntryContext': ec + }) + + +# @loger +def tc_get_incident_associate_indicators(incident_id, owners): + tc = get_client() + incidents = tc.incidents() + _filter = incidents.add_filter() + _filter.add_id(incident_id) + + incidents = incidents.retrieve() + indicators = [] + for incident in incidents: + for ind in incident.indicator_associations: + if ind.type == 'File': + indicators.append(ind.indicator['md5']) + else: + indicators.append(ind.indicator) + if len(indicators) == 0: + return [] + + indicators_obj = tc.indicators() + _filter = indicators_obj.add_filter() + if owners is not None: + _filter.add_owner(owners) + for ind in indicators: + _filter.add_indicator(ind) + + raw_indicators = indicators_obj.retrieve() + return [indicator.json for indicator in raw_indicators] + + +def tc_incident_associate_indicator_command(): + args = demisto.args() + incident_id = int(args['incidentId']) + indicator = args['indicator'] + types = { + 'ADDRESSES': ResourceType.ADDRESSES, + 'EMAIL_ADDRESSES': ResourceType.EMAIL_ADDRESSES, + 'FILES': ResourceType.FILES, + 'HOSTS': ResourceType.HOSTS, + 'URLS': ResourceType.URLS, + } + indicator_type = types.get(args['indicatorType'], args['indicatorType']) + owners = args.get('owner') + if owners is not None: + owners = owners.split(",") + + incidents = tc_incident_associate_indicator(incident_id, indicator_type, indicator, owners) + md = [] + for inc in incidents: + md.append('Incident {} with ID {}, was tagged with: {}'.format(inc['name'], inc['id'], indicator)) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['text'], + 'Contents': incidents, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': '\n'.join(md), + 'EntryContext': {'TC.Incident(val.ID && val.ID === obj.ID)': createContext(incidents, removeNull=True)} + }) + + +# @loger +def tc_incident_associate_indicator(incident_id, indicator_type, indicator, owners): + tc = get_client() + incidents = tc.incidents() + filter1 = incidents.add_filter() + filter1.add_id(incident_id) + if owners is not None: + filter1.add_owner(owners) + raw_incidents = incidents.retrieve() + + incidents = [] + for incident in raw_incidents: + incident.associate_indicator(indicator_type, indicator) + incidents.append(json.loads(incident.commit().json)) + + return incidents + + +def tc_update_indicator_command(): + args = demisto.args() + indicator = args['indicator'] + rating = args.get('rating') + confidence = args.get('confidence') + size = args.get('size') + dns_active = args.get('dnsActive') + whois_active = args.get('whoisActive') + false_positive = args.get('falsePositive', 'False') == 'True' + observations = int(args.get('observations', 0)) + security_label = args.get('securityLabel') + threat_assess_confidence = int(args.get('threatAssessConfidence', -1)) + threat_assess_rating = int(args.get('threatAssessRating', -1)) + + raw_indicators = tc_update_indicator(indicator, rating=rating, confidence=confidence, size=size, + dns_active=dns_active, whois_active=whois_active, + false_positive=false_positive, observations=observations, + security_label=security_label, + threat_assess_confidence=threat_assess_confidence, + threat_assess_rating=threat_assess_rating) + ec, indicators = create_context(raw_indicators) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': '\n'.join('Indicator {} Updated Successfully'.format(ind['ID']) for ind in indicators), + 'EntryContext': ec + }) + + +# @loger +def tc_update_indicator(indicator, rating=None, confidence=None, size=None, dns_active=None, whois_active=None, + false_positive=False, observations=0, security_label=None, threat_assess_confidence=-1, + threat_assess_rating=-1): + tc = get_client() + indicators = tc.indicators() + filter1 = indicators.add_filter() + filter1.add_indicator(indicator) + + raw_indicators = [] + for ind in indicators.retrieve(): + if rating is not None: + ind.set_rating(rating) + if confidence is not None: + ind.set_confidence(int(confidence)) + if false_positive: + ind.add_false_positive() + if observations != 0: + ind.add_observation(observations) + if security_label is not None: + ind.add_security_label(security_label) + if threat_assess_confidence != -1: + ind.set_threat_assess_confidence(threat_assess_confidence) + if threat_assess_rating != -1: + ind.set_threat_assess_rating(threat_assess_rating) + + if ind.type == 'File' and size is not None: + ind.add_size(size) + if ind.type == 'Host' and dns_active is not None: + ind.set_dns_active(dns_active) + if ind.type == 'Host' and whois_active is not None: + ind.set_whois_active(whois_active) + + raw_indicators.append(ind.commit().json) + + return raw_indicators + + +def tc_delete_indicator_command(): + args = demisto.args() + indicator = args['indicator'] + + tc_delete_indicator(indicator) + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['text'], + 'Contents': 'Indicator {} removed Successfully'.format(indicator) + }) + + +# @loger +def tc_delete_indicator(indicator): + tc = get_client() + indicators = tc.indicators() + filter1 = indicators.add_filter() + filter1.add_indicator(indicator) + indicators = indicators.retrieve() + for ind in indicators: + ind.delete() + + +def tc_delete_indicator_tag_command(): + args = demisto.args() + indicator = args['indicator'] + tag = args['tag'] + + indicators = tc_delete_indicator_tag(indicator, tag) + raw_indicators = [ind.json for ind in indicators] + ec, _ = create_context(raw_indicators) + + md = [] + for ind in indicators: + md.append('Removed tag {} from indicator {}.'.format(tag, ind.indicator)) + if len(md) == 0: + md.append('No indicators found') + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['text'], + 'Contents': raw_indicators, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': '\n'.join(md), + 'EntryContext': ec + }) + + +# @loger +def tc_delete_indicator_tag(indicator, tag, owners=None): + tc = get_client() + indicators = tc.indicators() + filter1 = indicators.add_filter() + filter1.add_indicator(indicator) + + if owners is not None: + owners = owners.split(",") + filter1.add_owner(owners) + + indicators = indicators.retrieve() + for indicator in indicators: + indicator.delete_tag(tag) + indicator.commit() + + return indicators + + +def tc_create_campaign_command(): + args = demisto.args() + name = args['name'] + owner = args.get('owner', demisto.params()['defaultOrg']) + if owner == '': + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + first_seen = args.get('firstSeen', datetime.utcnow().isoformat().split('.')[0] + 'Z') + tag = args.get('tag') + security_label = args.get('securityLabel') + description = args.get('description') + + raw_campaign = tc_create_campaign(name, owner, first_seen, tag, security_label, description) + ec = { + 'ID': raw_campaign['id'], + 'Name': raw_campaign['name'], + 'Owner': raw_campaign['owner']['name'], + 'FirstSeen': raw_campaign['firstSeen'], + 'Tag': tag, + 'SecurityLabel': security_label + } + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_campaign, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': 'Campaign {} Created Successfully'.format(name), + 'EntryContext': { + 'TC.Campaign(val.ID && val.ID === obj.ID)': createContext([ec], removeNull=True) + } + }) + + +# @loger +def tc_create_campaign(name, owner, first_seen, tag=None, security_label=None, description=None): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/campaigns') + body = { + 'name': name, + 'firstSeen': first_seen, + } + ro.set_body(json.dumps(body)) + response = tc.api_request(ro).json() + + if response.get('status') == 'Success': + output = response.get('data', {}).get('campaign', {}) + event_id = output['id'] + if description is not None: + # Associate Attribute description + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/events/{}/attributes'.format(event_id)) + body = { + 'type': 'Description', + 'value': description, + 'displayed': 'true' + } + ro.set_body(json.dumps(body)) + tc.api_request(ro).json() + + return output + else: + return_error('Failed to create event') + + +def tc_create_event_command(): + args = demisto.args() + name = args['name'] + event_date = args.get('EventDate', datetime.utcnow().isoformat().split('.')[0] + 'Z') + status = args.get('status') + owner = args.get('owner', demisto.params()['defaultOrg']) + if owner == '': + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + description = args.get('description') + tag = args.get('tag') + + raw_event = tc_create_event(name, owner, event_date, tag, status, description) + ec = { + 'ID': raw_event['id'], + 'Name': raw_event['name'], + 'Owner': raw_event['owner']['name'], + 'Date': raw_event['eventDate'], + 'Tag': tag, + 'Status': status + } + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_event, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': 'Incident {} Created Successfully'.format(name), + 'EntryContext': { + 'TC.Event(val.ID && val.ID === obj.ID)': createContext([ec], removeNull=True) + } + }) + + +def tc_create_event(name, owner, event_date, tag=None, status=None, description=None): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/events') + body = { + 'name': name, + 'eventDate': event_date, + 'status': status + } + ro.set_body(json.dumps(body)) + response = tc.api_request(ro).json() + + if response.get('status') == 'Success': + output = response.get('data', {}).get('event', {}) + event_id = output['id'] + if description is not None: + # Associate Attribute description + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/events/{}/attributes'.format(event_id)) + body = { + 'type': 'Description', + 'value': description, + 'displayed': 'true' + } + ro.set_body(json.dumps(body)) + tc.api_request(ro).json() + + return output + else: + return_error('Failed to create event') + + +def tc_create_threat_command(): + args = demisto.args() + name = args['name'] + date = args.get('dateAdded', datetime.utcnow().isoformat().split('.')[0] + 'Z') + owner = args.get('owner', demisto.params()['defaultOrg']) + if owner == '': + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + raw_threat = tc_create_threat(name, owner, date) + ec = { + 'ID': raw_threat['id'], + 'Name': raw_threat['name'] + } + + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['json'], + 'Contents': raw_threat, + 'ReadableContentsFormat': formats['markdown'], + 'HumanReadable': 'Threat {} Created Successfully'.format(name), + 'EntryContext': { + 'TC.Threat(val.ID && val.ID === obj.ID)': createContext([ec], removeNull=True) + } + }) + + +def tc_create_threat(name, owner, date): + tc = get_client() + threats = tc.threats() + threat = threats.add(name, owner) + threat.set_date_added(date) + + return json.loads(threat.commit().json) + + +def tc_delete_group_command(): + args = demisto.args() + group_id = int(args['groupID']) + group_type = args['type'] + + success = tc_delete_group(group_id, group_type.lower()) + if success: + demisto.results({ + 'Type': entryTypes['note'], + 'ContentsFormat': formats['text'], + 'Contents': '{} {} deleted Successfully'.format(group_type.lower(), group_id) + }) + else: + return_error('Failed to delete {} {}'.format(group_type, group_id)) + + +def tc_delete_group(group_id, group_type): + tc = get_client() + ro = RequestObject() + ro.set_http_method('DELETE') + ro.set_request_uri('/v2/groups/{}/{}'.format(group_type, group_id)) + response = tc.api_request(ro).json() + + return response['status'] == 'Success' + + +def tc_add_group_attribute_request(group_type, group_id, attribute_type, attribute_value): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/{}/{}/attributes'.format(group_type, group_id)) + body = { + 'type': attribute_type, + 'value': attribute_value, + 'displayed': 'true' + } + ro.set_body(json.dumps(body)) + response = tc.api_request(ro).json() + + return response + + +def tc_add_group_attribute(): + group_id = int(demisto.args().get('group_id')) + group_type = demisto.args().get('group_type') + attribute_type = demisto.args().get('attribute_type') + attribute_value = demisto.args().get('attribute_value') + headers = ['Type', 'Value', 'ID', 'DateAdded', 'LastModified'] + attribute = tc_add_group_attribute_request(group_type, group_id, attribute_type, attribute_value) + data = attribute.get('data').get('attribute') + contents = { + 'Type': data.get('type'), + 'Value': data.get('value'), + 'ID': data.get('id'), + 'DateAdded': data.get('dateAdded'), + 'LastModified': data.get('lastModified') + } + context = { + 'TC.Group(val.ID && val.ID === obj.ID)': contents + } + + return_outputs( + tableToMarkdown('The attribute was added successfully to group {}'.format(group_id), contents, headers, + removeNull=True), + context, + attribute + ) + + +def add_group_security_label_request(group_type, group_id, security_label): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/{}/{}/securityLabels/{}'.format(group_type, group_id, security_label)) + + response = tc.api_request(ro).json() + + return response.get('status') == 'Success' + + +def add_group_security_label(): + group_id = int(demisto.args().get('group_id')) + group_type = demisto.args().get('group_type') + security_label = demisto.args().get('security_label_name') + + add_group_security_label_request(group_type, group_id, security_label) + + demisto.results('The security label {} was added successfully to {} {}'.format(security_label, group_type, + group_id)) + + +def add_group_tags_request(group_type, group_id, tag_name): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/{}/{}/tags/{}'.format(group_type, group_id, tag_name)) + + response = tc.api_request(ro).json() + + return response.get('status') == 'Success' + + +def add_group_tag(): + group_id = int(demisto.args().get('group_id')) + group_type = demisto.args().get('group_type') + tag_name = demisto.args().get('tag_name') + + add_group_tags_request(group_type, group_id, tag_name) + + demisto.results('The tag {} was added successfully to group {} {}'.format(tag_name, group_type, group_id)) + + +def get_events_request(): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/events') + + return tc.api_request(ro).json() + + +def tc_get_events(): + raw_response = get_events_request() + data = raw_response.get('data', {}).get('event', []) + content = [] + headers = ['ID', 'Name', 'OwnerName', 'EventDate', 'DateAdded', 'Status'] + + for event in data: + content.append({ + 'ID': event.get('id'), + 'Name': event.get('name'), + 'OwnerName': event.get('ownerName'), + 'DateAdded': event.get('dateAdded'), + 'EventDate': event.get('eventDate'), + 'Status': event.get('status') + }) + context = { + 'TC.Event(val.ID && val.ID === obj.ID)': content + } + + return_outputs( + tableToMarkdown('ThreatConnect Events', content, headers, removeNull=True), + context, + raw_response + ) + + +def tc_get_indicator_types_request(): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/types/indicatorTypes') + + return tc.api_request(ro).json() + + +def tc_get_indicator_types(): + raw_response = tc_get_indicator_types_request() + data = raw_response.get('data', {}).get('indicatorType', []) + content = [] + headers = ['Name', 'Custom', 'Parsable', 'ApiBranch', 'CasePreference', 'value1Label', 'Value1Type'] + + for type_ in data: + content.append({ + 'Custom': type_.get('custom'), + 'Name': type_.get('name'), + 'Parsable': type_.get('parsable'), + 'ApiBranch': type_.get('apiBranch'), + 'ApiEntity': type_.get('apiEntity'), + 'CasePreference': type_.get('casePreference'), + 'Value1Label': type_.get('value1Label'), + 'Value1Type': type_.get('value1Type') + }) + context = { + 'TC.IndicatorType(val.Name && val.Name === obj.Name)': content + } + + return_outputs( + tableToMarkdown('ThreatConnect indicator types', content, headers, removeNull=True), + context, + raw_response + ) + + +def associate_indicator_request(indicator_type, indicator, group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/indicators/{}/{}/groups/{}/{}'.format(indicator_type, indicator, group_type, group_id)) + response = tc.api_request(ro).json() + + return response + + +def associate_indicator(): + group_id = int(demisto.args().get('group_id')) + group_type = demisto.args().get('group_type') + indicator_type = demisto.args().get('indicator_type') + indicator = demisto.args().get('indicator') + + response = associate_indicator_request(indicator_type, indicator, group_type, group_id) + + if response.get('status') == 'Success': + contents = { + 'IndicatorType': indicator_type, + 'Indicator': indicator, + 'GroupType': group_type, + 'GroupID': group_id + } + else: + return_error(response.get('message')) + + context = { + 'TC.Group(val.Indicator && val.Indicator === obj.Indicator)': contents + } + + return_outputs( + tableToMarkdown('The indicator was associated successfully', contents, removeNull=True), + context + ) + + +def get_groups_request(group_type): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}'.format(group_type)) + + return tc.api_request(ro).json() + + +def tc_get_groups(): + group_type = demisto.args().get('group_type') + raw_response = get_groups_request(group_type) + headers = ['ID', 'Name', 'OwnerName', 'EventDate', 'DateAdded', 'Status'] + if group_type == 'adversaries': + data = raw_response.get('data', {}).get('adversarie', {}) + if group_type == 'campaigns': + data = raw_response.get('data', {}).get('campaign', {}) + if group_type == 'documents': + data = raw_response.get('data', {}).get('document', {}) + if group_type == 'emails': + data = raw_response.get('data', {}).get('email', {}) + if group_type == 'events': + data = raw_response.get('data', {}).get('event', {}) + if group_type == 'incidents': + data = raw_response.get('data', {}).get('incident', {}) + if group_type == 'intrusionSets': + data = raw_response.get('data', {}).get('intrusionSet', {}) + if group_type == 'reports': + data = raw_response.get('data', {}).get('report', {}) + if group_type == 'signatures': + data = raw_response.get('data', {}).get('signature', {}) + if group_type == 'threats': + data = raw_response.get('data', {}).get('threat', {}) + + content = [] + + for group in data: + content.append({ + 'ID': group.get('id'), + 'Name': group.get('name'), + 'OwnerName': group.get('ownerName'), + 'DateAdded': group.get('dateAdded'), + 'EventDate': group.get('eventDate'), + 'Status': group.get('status') + }) + context = { + 'TC.Group(val.ID && val.ID === obj.ID)': content + } + + return_outputs( + tableToMarkdown('ThreatConnect {}'.format(group_type), content, headers, removeNull=True), + context, + raw_response + ) + + +def get_group_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group(): + """ + Retrieve a single Group + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + response = get_group_request(group_type, group_id) + response = response.get('data', {}) + if group_type == 'adversaries': + data = response.get('adversarie', {}) + if group_type == 'campaigns': + data = response.get('campaign', {}) + if group_type == 'documents': + data = response.get('document', {}) + if group_type == 'emails': + data = response.get('email', {}) + if group_type == 'events': + data = response.get('event', {}) + if group_type == 'incidents': + data = response.get('incident', {}) + if group_type == 'intrusionSets': + data = response.get('intrusionSet', {}) + if group_type == 'reports': + data = response.get('report', {}) + if group_type == 'signatures': + data = response.get('signature', {}) + if group_type == 'threats': + data = response.get('threat', {}) + + owner = { + 'Name': data.get('owner', {}).get('name'), + 'ID': data.get('owner', {}).get('id'), + 'Type': data.get('owner', {}).get('type') + } + contents = { + 'ID': data.get('id'), + 'Name': data.get('name'), + 'Owner': owner, + 'DateAdded': data.get('dateAdded'), + 'EventDate': data.get('eventDate'), + 'Status': data.get('status') + } + + context = { + 'TC.Group(val.ID && val.ID === obj.ID)': contents + } + + return_outputs( + tableToMarkdown('ThreatConnect Group information', contents, removeNull=True), + context, + response + ) + + +def get_group_attributes_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}/attributes'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group_attributes(): + """ + Retrieve a Group's Attributes + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + contents = [] + headers = ['AttributeID', 'Type', 'Value', 'DateAdded', 'LastModified', 'Displayed'] + response = get_group_attributes_request(group_type, group_id) + data = response.get('data', {}).get('attribute', []) + + if response.get('status') == 'Success': + for attribute in data: + contents.append({ + 'GroupID': group_id, + 'AttributeID': attribute.get('id'), + 'Type': attribute.get('type'), + 'Value': attribute.get('value'), + 'DateAdded': attribute.get('dateAdded'), + 'LastModified': attribute.get('lastModified'), + 'Displayed': attribute.get('displayed') + }) + + else: + return_error(response.get('message')) + + context = { + 'TC.Group.Attribute(val.GroupID && val.GroupID === obj.GroupID && val.AttributeID && val.AttributeID ===' + ' obj.AttributeID)': contents + } + + return_outputs( + tableToMarkdown('ThreatConnect Group Attributes', contents, headers, removeNull=True), + context, + response + ) + + +def get_group_security_labels_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}/securityLabels'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group_security_labels(): + """ + Retrieve a Group's Security Labels + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + contents = [] + headers = ['Name', 'Description', 'DateAdded'] + response = get_group_security_labels_request(group_type, group_id) + data = response.get('data', {}).get('securityLabel', []) + + if response.get('status') == 'Success': + for security_label in data: + contents.append({ + 'GroupID': group_id, + 'Name': security_label.get('name'), + 'Description': security_label.get('description'), + 'DateAdded': security_label.get('dateAdded') + }) + + else: + return_error(response.get('message')) + + context = { + 'TC.Group.SecurityLabel(val.GroupID && val.GroupID === obj.GroupID && val.Name && val.Name === ' + 'obj.Name)': contents + } + + return_outputs( + tableToMarkdown('ThreatConnect Group Security Labels', contents, headers, removeNull=True), + context + ) + + +def get_group_tags_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}/tags'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group_tags(): + """ + Retrieve the Tags for a Group + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + contents = [] + context_entries = [] + response = get_group_tags_request(group_type, group_id) + data = response.get('data', {}).get('tag', []) + + if response.get('status') == 'Success': + for tags in data: + contents.append({ + 'Name': tags.get('name') + }) + + context_entries.append({ + 'GroupID': group_id, + 'Name': tags.get('name') + }) + else: + return_error(response.get('message')) + + context = { + 'TC.Group.Tag(val.GroupID && val.GroupID === obj.GroupID && val.Name && val.Name === obj.Name)': context_entries + } + + return_outputs( + tableToMarkdown('ThreatConnect Group Tags', contents, removeNull=True), + context, + response + ) + + +def get_group_indicator_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}/indicators'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group_indicator(): + """ + View Indicators associated with a given Group + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + contents = [] + response = get_group_indicator_request(group_type, group_id) + data = response.get('data', {}).get('indicator', []) + + if response.get('status') == 'Success': + for indicator in data: + contents.append({ + 'GroupID': group_id, + 'IndicatorID': indicator.get('id'), + 'OwnerName': indicator.get('ownerName'), + 'Type': indicator.get('type'), + 'DateAdded': indicator.get('dateAdded'), + 'LastModified': indicator.get('lastModified'), + 'Rating': indicator.get('rating'), + 'Confidence': indicator.get('confidence'), + 'ThreatAssertRating': indicator.get('threatAssessRating'), + 'ThreatAssessConfidence': indicator.get('threatAssessConfidence'), + 'Summary': indicator.get('summary') + }) + + else: + return_error(response.get('message')) + + context = { + 'TC.Group.Indicator(val.GroupID && val.GroupID === obj.GroupID && val.IndicatorID && val.IndicatorID === ' + 'obj.IndicatorID)': contents + } + + return_outputs( + tableToMarkdown('ThreatConnect Group Indicators', contents, removeNull=True), + context, + response + ) + + +def get_group_associated_request(group_type, group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('GET') + ro.set_request_uri('/v2/groups/{}/{}/groups'.format(group_type, group_id)) + + return tc.api_request(ro).json() + + +def get_group_associated(): + """ + View Indicators associated with a given Group + """ + group_type = demisto.args().get('group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + contents = [] + headers = ['GroupID', 'Name', 'Type', 'OwnerName', 'DateAdded'] + response = get_group_associated_request(group_type, group_id) + data = response.get('data', {}).get('group', []) + + if response.get('status') == 'Success': + for group in data: + contents.append({ + 'GroupID': group.get('id'), + 'Name': group.get('name'), + 'Type': group.get('type'), + 'DateAdded': group.get('dateAdded'), + 'OwnerName': group.get('ownerName') + }) + + else: + return_error(response.get('message')) + + context = { + 'TC.Group.AssociatedGroup(val.GroupID && val.GroupID === obj.GroupID)': contents + } + + return_outputs( + tableToMarkdown('ThreatConnect Associated Groups', contents, headers, removeNull=True), + context, + response + ) + + +def associate_group_to_group_request(group_type, group_id, associated_group_type, associated_group_id): + tc = get_client() + ro = RequestObject() + ro.set_http_method('POST') + ro.set_request_uri('/v2/groups/{}/{}/groups/{}/{}'.format(group_type, group_id, associated_group_type, + associated_group_id)) + + return tc.api_request(ro).json() + + +def associate_group_to_group(): + """ + Associate one Group with another + """ + + group_type = demisto.args().get('group_type') + associated_group_type = demisto.args().get('associated_group_type') + try: + group_id = int(demisto.args().get('group_id')) + except TypeError as t: + return_error('group_id must be a number', t) + try: + associated_group_id = int(demisto.args().get('associated_group_id')) + except TypeError as t: + return_error('associated_group_id must be a number', t) + + response = associate_group_to_group_request(group_type, group_id, associated_group_type, associated_group_id) + + if response.get('status') == 'Success': + context_entries = { + 'GroupID': group_id, + 'GroupType': group_type, + 'AssociatedGroupID': associated_group_id, + 'AssociatedGroupType': associated_group_type + } + context = { + 'TC.Group.AssociatedGroup(val.GroupID && val.GroupID === obj.GroupID)': context_entries + } + return_outputs('The group {} was associated successfully.'.format(associated_group_id), + context, + response) + else: + return_error(response.get('message')) + + +def create_document_group_request(contents, file_name, name, owner, res, malware, password, security_label, + description): + tc = get_client() + documents = tc.documents() + document = documents.add(name, owner) + document.set_file_name(file_name) + + # upload the contents of the file into the Document + document.upload(contents) + if malware: + document.set_malware(True) + document.set_password(password) + if security_label: + document.set_security_label(security_label) + if description: + document.add_attribute('Description', description) + + return document.commit().json + + +def create_document_group(): + file_name = demisto.args().get('file_name') + name = demisto.args().get('name') + malware = bool(strtobool(demisto.args().get('malware', 'False'))) + password = demisto.args().get('password') + res = demisto.getFilePath(demisto.args()['entry_id']) + owner = demisto.args().get('owner', demisto.params().get('defaultOrg')) + if not owner: + return_error('You must specify an owner in the command, or by using the Organization parameter.') + + security_label = demisto.args().get('securityLabel') + description = demisto.args().get('description') + + # open a file handle for a local file and read the contents thereof + f = open(res['path'], 'rb') + contents = f.read() + + raw_document = create_document_group_request(contents, file_name, name, owner, res, malware, password, + security_label, description) + content = { + 'ID': raw_document.get('id'), + 'Name': raw_document.get('name'), + 'Owner': raw_document.get('ownerName'), + 'EventDate': raw_document.get('eventDate'), + 'Description': description, + 'SecurityLabel': security_label + } + context = { + 'TC.Group(val.ID && val.ID === obj.ID)': content + } + return_outputs(tableToMarkdown('ThreatConnect document group was created successfully', content, removeNull=True), + context, + raw_document) + + +def get_document_request(document_id): + tc = get_client() + documents = tc.documents() + # set a filter to retrieve only the Document with ID: 123456 + filter1 = documents.add_filter() + filter1.add_id(document_id) + try: + # retrieve the Document + documents.retrieve() + except RuntimeError as e: + return_error('Error: {0}'.format(str(e))) + + # iterate through the retrieved Documents (in this case there should only be one) and print its properties + for document in documents: + document.download() + if document.contents is not None: + return document + else: + return_error('No document was found.') + + +def download_document(): + """ + Download the contents of a Document + """ + try: + document_id = int(demisto.args().get('document_id')) + except TypeError as t: + return_error('document_id must be a number', t) + document = get_document_request(document_id) + + file_name = document.file_name + file_content = document.contents + demisto.results(fileResult(file_name, file_content)) + + +def test_integration(): + tc = get_client() + owners = tc.owners() + owners.retrieve() + demisto.results('ok') + + +''' EXECUTION CODE ''' +COMMANDS = { + 'test-module': test_integration, + 'ip': ip_command, + 'url': url_command, + 'file': file_command, + 'domain': domain_command, + + 'tc-owners': tc_owners_command, + 'tc-indicators': tc_indicators_command, + 'tc-get-tags': tc_get_tags_command, + 'tc-tag-indicator': tc_tag_indicator_command, + 'tc-get-indicator': tc_get_indicator_command, + 'tc-get-indicators-by-tag': tc_get_indicators_by_tag_command, + 'tc-add-indicator': tc_add_indicator_command, + + 'tc-create-incident': tc_create_incident_command, + 'tc-fetch-incidents': tc_fetch_incidents_command, + 'tc-get-incident-associate-indicators': tc_get_incident_associate_indicators_command, + 'tc-incident-associate-indicator': tc_incident_associate_indicator_command, + 'tc-update-indicator': tc_update_indicator_command, + 'tc-delete-indicator': tc_delete_indicator_command, + 'tc-delete-indicator-tag': tc_delete_indicator_tag_command, + 'tc-create-campaign': tc_create_campaign_command, + 'tc-create-event': tc_create_event_command, + 'tc-get-events': tc_get_events, + 'tc-add-group-attribute': tc_add_group_attribute, + 'tc-create-threat': tc_create_threat_command, + 'tc-delete-group': tc_delete_group_command, + 'tc-get-groups': tc_get_groups, + 'tc-add-group-security-label': add_group_security_label, + 'tc-add-group-tag': add_group_tag, + 'tc-get-indicator-types': tc_get_indicator_types, + 'tc-group-associate-indicator': associate_indicator, + 'tc-create-document-group': create_document_group, + 'tc-get-group': get_group, + 'tc-get-group-attributes': get_group_attributes, + 'tc-get-group-security-labels': get_group_security_labels, + 'tc-get-group-tags': get_group_tags, + 'tc-download-document': download_document, + 'tc-get-group-indicators': get_group_indicator, + 'tc-get-associated-groups': get_group_associated, + 'tc-associate-group-to-group': associate_group_to_group, + 'tc-get-indicator-owners': tc_get_indicator_owners, +} + + +if __name__ in ('__main__', '__builtin__', 'builtins'): + try: + command_func = demisto.command() + LOG('command is %s' % (demisto.command(),)) + if command_func in COMMANDS.keys(): + COMMANDS[command_func]() + + except Exception as e: + return_error(f'error has occurred: {str(e)}', error=e) diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.yml b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.yml new file mode 100644 index 000000000000..d22e1d65e9e0 --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2.yml @@ -0,0 +1,2058 @@ +commonfields: + id: ThreatConnect v2 + version: -1 +name: ThreatConnect v2 +display: ThreatConnect v2 +category: Data Enrichment & Threat Intelligence +description: Threat intelligence platform. +configuration: +- display: baseUrl + name: baseUrl + defaultvalue: https://api.threatconnect.com + type: 0 + required: true +- display: Access ID + name: accessId + defaultvalue: "" + type: 0 + required: true +- display: Secret Key + name: secretKey + defaultvalue: "" + type: 4 + required: true +- display: Default Organization + name: defaultOrg + defaultvalue: "" + type: 0 + required: false +- display: Rating threshold for Malicious Indicators + name: rating + defaultvalue: "3" + type: 0 + required: false +- display: Confidence threshold for Malicious Indicators + name: confidence + defaultvalue: "50" + type: 0 + required: false +- display: Indicator Reputation Freshness (in days) + name: freshness + defaultvalue: "7" + type: 0 + required: false +- display: ProxyIP (or http://${ip} ) + name: proxyIp + defaultvalue: "" + type: 0 + required: false +- display: ProxyPort + name: proxyPort + defaultvalue: "" + type: 0 + required: false +script: + script: '-' + type: python + commands: + - name: ip + arguments: + - name: ip + required: true + default: true + description: The IPv4 or IPv6 address. + - name: owners + description: A comma-separated list of a client's organizations, sources, or communities + to which a user has permissions. For example, users with admin permissions + can search for indicators belonging to all owners. + - name: ratingThreshold + description: A list of results filtered by indicators whose threat rating is + greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", + "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidenceThreshold + description: A list of results filtered by indicators whose confidence rating + is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", + "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" + - "Probable," or "90-100%" - "Confirmed". + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + description: Searches for an indicator of type IP address. + - name: url + arguments: + - name: url + required: true + default: true + description: The URL for which to search. For example, "www.demisto.com". + - name: owners + description: A comma-separated list of a client's organizations, sources, or communities + to which a client’s API user has been granted permission. For example, "owner1", + "owner2", or "owner3". + - name: ratingThreshold + description: A list of results filtered by indicators whose threat rating is + greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", + "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidenceThreshold + description: A list of results filtered by indicators whose confidence rating + is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", + "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" + - "Probable," or "90-100%" - "Confirmed". + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The date on which the indicator was last modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: URL.Data + description: The data of the URL indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + description: Searches for an indicator of type URL. + - name: file + arguments: + - name: file + required: true + default: true + description: The hash of the file. Can be "MD5", "SHA-1", or "SHA-256". + - name: owners + description: A comma-separated list of a client's organizations, sources, or communities + to which a user has permissions. For example, users with admin permissions + can search for indicators belonging to all owners. + - name: ratingThreshold + description: A list of results filtered by indicators whose threat rating is + greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", + "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidenceThreshold + description: A list of results filtered by indicators whose confidence rating + is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", + "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" + - "Probable," or "90-100%" - "Confirmed". + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator. + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the indicator. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the indicator. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the indicator. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Searches for an indicator of type file. + - name: tc-owners + arguments: [] + outputs: + - contextPath: TC.Owner.Name + description: The name of the owner. + type: string + - contextPath: TC.Owner.ID + description: The ID of the owner. + type: string + - contextPath: TC.Owner.Type + description: The type of the owner. + type: string + description: Retrieves all owners for the current account. + - name: tc-indicators + arguments: + - name: owner + description: A list of results filtered by the owner of the indicator. + - name: limit + description: The maximum number of results that can be returned. The default + is 500. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The name of the domain. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Retrieves a list of all indicators. + - name: tc-get-tags + arguments: [] + outputs: + - contextPath: TC.Tags + description: A list of tags. + type: Unknown + description: Returns a list of all ThreatConnect tags. + - name: tc-tag-indicator + arguments: + - name: tag + required: true + description: The name of the tag. + - name: indicator + required: true + description: The indicator to tag. For example, for an IP indicator, "8.8.8.8". + - name: owner + description: A list of indicators filtered by the owner. + description: Adds a tag to an existing indicator. + - name: tc-get-indicator + arguments: + - name: indicator + required: true + default: true + description: The name of the indicator by which to search. The command retrieves + information from all owners. Can be an IP address, a URL, or a file hash. + - name: indicator_type + description: Only for custom. Leave empty for standard ones + - name: owners + description: Indicator Owner(s) + - name: ratingThreshold + description: A list of results filtered by indicators whose threat rating is + greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", + "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidenceThreshold + description: A list of results filtered by indicators whose confidence rating + is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", + "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" + - "Probable," or "90-100%" - "Confirmed". + - name: group_associations + required: true + auto: PREDEFINED + predefined: + - "true" + - "false" + description: Retrieve Indicator Group Associations + defaultValue: "false" + - name: indicator_associations + auto: PREDEFINED + predefined: + - "true" + - "false" + description: Retrieve Indicator Associations + defaultValue: "false" + - name: indicator_observations + auto: PREDEFINED + predefined: + - "true" + - "false" + description: Retrieve Indicator Observations + defaultValue: "false" + - name: indicator_tags + auto: PREDEFINED + predefined: + - "true" + - "false" + description: Retrieve Indicator Tags + defaultValue: "false" + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the indicator of the URL. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The domain name of the indicator. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Retrieves information about an indicator. + - name: tc-get-indicators-by-tag + arguments: + - name: tag + required: true + default: true + description: The name of the tag by which to filter. + - name: owner + description: A list of indicators filtered by the owner. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the tagged indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the tagged indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the tagged indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the tagged indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the tagged indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the tagged indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the tagged indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the tagged indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the tagged indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the tagged indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the tagged indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the tagged indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: IP.Address + description: The IP address of the tagged indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the tagged indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The domain name of the tagged indicator. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Fetches all indicators that have a tag. + - name: tc-add-indicator + arguments: + - name: indicator + required: true + description: The indicator to add. + - name: rating + description: The threat rating of the indicator. Can be "0" - "Unknown", "1" + - "Suspicious", "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidence + description: The confidence rating of the indicator. Can be "0%" - "Unknown," + "1% " - "Discredited", "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" + - "Possible", "70-89%" - "Probable," or "90-100%" - "Confirmed". + - name: owner + description: The owner of the new indicator. The default is the "defaultOrg" + parameter. + outputs: + - contextPath: TC.Indicator.Name + description: The name the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the added indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the added indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The name of the added indicator of the domain. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Adds a new indicator to ThreatConnect. + - name: tc-create-incident + arguments: + - name: owner + description: The owner of the new incident. The default is the "defaultOrg" + parameter. + - name: incidentName + required: true + default: true + description: The name of the incident group. + - name: eventDate + description: The creation time of an incident in the "2017-03-21T00:00:00Z" + format. + - name: tag + description: The tag applied to the incident. + - name: securityLabel + auto: PREDEFINED + predefined: + - TLP:RED + - TLP:GREEN + - TLP:AMBER + - TLP:WHITE + description: The security label applied to the incident. Can be "TLP:RED", "TLP:GREEN", + "TLP:AMBER", or "TLP:WHITE". + - name: description + description: The description of the incident. + outputs: + - contextPath: TC.Incident.Name + description: The name of the new incident group. + type: string + - contextPath: TC.Incident.Owner + description: The owner of the new incident. + type: string + - contextPath: TC.Incident.EventDate + description: The date on which the event that indicates an incident occurred. + type: date + - contextPath: TC.Incident.Tag + description: The name of the tag of the new incident. + type: string + - contextPath: TC.Incident.SecurityLabel + description: The security label of the new incident. + type: string + - contextPath: TC.Incident.ID + description: The ID of the new incident. + type: Unknown + description: Creates a new incident group. + - name: tc-fetch-incidents + arguments: + - name: incidentId + default: true + description: The fetched incidents filtered by ID. + - name: owner + description: The fetched incidents filtered by owner. + - name: incidentName + description: The fetched incidents filtered by incident name. + outputs: + - contextPath: TC.Incident + description: The name of the group of fetched incidents. + type: string + - contextPath: TC.Incident.ID + description: The ID of the fetched incidents. + type: string + - contextPath: TC.Incident.Owner + description: The owner of the fetched incidents. + type: string + description: Fetches incidents from ThreatConnect. + - name: tc-incident-associate-indicator + arguments: + - name: indicatorType + required: true + auto: PREDEFINED + predefined: + - ADDRESSES + - EMAIL_ADDRESSES + - URLS + - HOSTS + - FILES + - CUSTOM_INDICATORS + description: The type of the indicator. Can be "ADDRESSES", "EMAIL_ADDRESSES", + "URLS", "HOSTS", "FILES", or "CUSTOM_INDICATORS". + - name: incidentId + required: true + description: The ID of the incident to which the indicator is associated. + - name: indicator + required: true + default: true + description: The name of the indicator. + - name: owner + description: A list of indicators filtered by the owner. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator associated was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator associated was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: IP.Address + description: IP address of the associated indicator of the file. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the associated indicator of the file. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The name of the indicator of the domain. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Associates an indicator with an existing incident. The indicator + must exist before running this command. To add an indicator, run the tc-add-indicator + command. + - name: domain + arguments: + - name: domain + required: true + default: true + description: The name of the domain. + - name: owners + description: A comma-separated list of a client's organizations, sources, or communities + to which a user has permissions. For example, users with admin permissions + can search for indicators belonging to all owners. + - name: ratingThreshold + description: A list of results filtered by indicators whose threat rating is + greater than the specified value. Can be "0" - "Unknown", "1" - "Suspicious", + "2" - "Low", "3" - Moderate, "4" - High, or "5" - "Critical". + - name: confidenceThreshold + description: A list of results filtered by indicators whose confidence rating + is greater than the specified value. Can be "0%" - "Unknown," "1% " - "Discredited", + "2-29%" - "Improbable," "30-49%" - "Doubtful," "50-69%" - "Possible", "70-89%" + - "Probable," or "90-100%" - "Confirmed". + outputs: + - contextPath: TC.Indicator.Name + description: The name of the of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the domain. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the domain. + type: string + - contextPath: TC.Indicator.Description + description: The description of the domain. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the domain. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator of the domain was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator of the domain was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the domain. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the domain. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: Domain.Name + description: The name of the domain. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + description: Searches for an indicator of type domain. + - name: tc-get-incident-associate-indicators + arguments: + - name: incidentId + required: true + default: true + description: The ID of the incident. + - name: owner + description: A list of indicators filtered by the owner. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the returned indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the returned indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the returned indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the returned indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the returned indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the returned indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the returned indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the returned indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the returned indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: DBotScore.Indicator + description: The value assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Type + description: The type assigned by DBot for the indicator. + type: string + - contextPath: DBotScore.Score + description: The score assigned by DBot for the indicator. + type: number + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: string + - contextPath: IP.Address + description: The IP address of the returned indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the returned indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The name of the domain. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Returns indicators that are related to a specific incident. + - name: tc-update-indicator + arguments: + - name: indicator + required: true + description: The name of the updated indicator. + - name: rating + description: The threat rating of the updated indicator. + - name: confidence + description: The confidence rating of the updated indicator. + - name: size + description: The size of the file of the updated indicator. + - name: dnsActive + description: The active DNS indicator (only for hosts). + - name: whoisActive + description: The active indicator (only for hosts). + - name: updatedValues + description: A comma-separated list of field:value pairs to update. For example, "rating=3", + "confidence=42", and "description=helloWorld". + - name: falsePositive + auto: PREDEFINED + predefined: + - "True" + - "False" + description: The updated indicator set as a false positive. Can be "True" or + "False". + - name: observations + description: The number observations on the updated indicator. + - name: securityLabel + auto: PREDEFINED + predefined: + - TLP:RED + - TLP:GREEN + - TLP:AMBER + - TLP:WHITE + description: The security label applied to the incident. Can be "TLP:RED", "TLP:GREEN", + "TLP:AMBER", or "TLP:WHITE". + - name: threatAssessConfidence + description: Assesses the confidence rating of the indicator. + - name: threatAssessRating + description: Assesses the threat rating of the indicator. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The domain name of the indicator. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Updates the indicator in ThreatConnect. + - name: tc-delete-indicator-tag + arguments: + - name: indicator + required: true + description: The name of the indicator from which to remove a tag. + - name: tag + required: true + description: The name of the tag to remove from the indicator. + outputs: + - contextPath: TC.Indicator.Name + description: The name of the indicator. + type: string + - contextPath: TC.Indicator.Type + description: The type of the indicator. + type: string + - contextPath: TC.Indicator.ID + description: The ID of the indicator. + type: string + - contextPath: TC.Indicator.Description + description: The description of the indicator. + type: string + - contextPath: TC.Indicator.Owner + description: The owner of the indicator. + type: string + - contextPath: TC.Indicator.CreateDate + description: The date on which the indicator was created. + type: date + - contextPath: TC.Indicator.LastModified + description: The last date on which the indicator was modified. + type: date + - contextPath: TC.Indicator.Rating + description: The threat rating of the indicator. + type: number + - contextPath: TC.Indicator.Confidence + description: The confidence rating of the indicator. + type: number + - contextPath: TC.Indicator.WhoisActive + description: The active indicator (for domains only). + type: string + - contextPath: TC.Indicator.File.MD5 + description: The MD5 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA1 + description: The SHA1 hash of the indicator of the file. + type: string + - contextPath: TC.Indicator.File.SHA256 + description: The SHA256 hash of the indicator of the file. + type: string + - contextPath: IP.Address + description: The IP address of the indicator. + type: string + - contextPath: IP.Malicious.Vendor + description: For malicious IP addresses, the vendor that made the decision. + type: string + - contextPath: IP.Malicious.Description + description: For malicious IP addresses, the full description. + type: string + - contextPath: URL.Data + description: The data of the URL of the indicator. + type: string + - contextPath: URL.Malicious.Vendor + description: For malicious URLs, the vendor that made the decision. + type: string + - contextPath: URL.Malicious.Description + description: For malicious URLs, the full description. + type: string + - contextPath: Domain.Name + description: The domain name of the indicator. + type: string + - contextPath: Domain.Malicious.Vendor + description: For malicious domains, the vendor that made the decision. + type: string + - contextPath: Domain.Malicious.Description + description: For malicious domains, the full description. + type: string + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: string + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: string + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: string + - contextPath: File.Malicious.Vendor + description: For malicious files, the vendor that made the decision. + type: string + - contextPath: File.Malicious.Description + description: For malicious files, the full description. + type: string + description: Removes a tag from a specified indicator. + - name: tc-delete-indicator + arguments: + - name: indicator + required: true + description: The name of the indicator to delete. + description: Deletes an indicator from ThreatConnect. + - name: tc-create-campaign + arguments: + - name: name + required: true + description: The name of the campaign group. + - name: firstSeen + description: The earliest date on which the campaign was seen. + - name: owner + description: The owner of the new incident. The default is the "defaultOrg" + parameter. + - name: description + description: The description of the campaign. + - name: tag + description: The name of the tag to apply to the campaign. + - name: securityLabel + description: The security label of the campaign. For example, "TLP:Green". + outputs: + - contextPath: TC.Campaign.Name + description: The name of the campaign. + type: string + - contextPath: TC.Campaign.Owner + description: The owner of the campaign. + type: string + - contextPath: TC.Campaign.FirstSeen + description: The earliest date on which the campaign was seen. + type: date + - contextPath: TC.Campaign.Tag + description: The tag of the campaign. + type: string + - contextPath: TC.Campaign.SecurityLevel + description: The security label of the campaign. + type: string + - contextPath: TC.Campaign.ID + description: The ID of the campaign. + type: string + description: Creates a group based on the "Campaign" type. + - name: tc-create-event + arguments: + - name: name + required: true + description: The name of the event group. + - name: eventDate + description: The date on which the event occurred. If the date is not specified, + the current date is used. + - name: status + auto: PREDEFINED + predefined: + - Needs Review + - False Positive + - No Further Action + - Escalated + description: The status of the event. Can be "Needs Review", "False Positive", + "No Further Action", or "Escalated". + - name: owner + description: The owner of the event. + - name: description + description: The description of the event. + - name: tag + description: The tag of the event. + outputs: + - contextPath: TC.Event.Name + description: The name of the event. + type: string + - contextPath: TC.Event.Date + description: The date of the event. + type: date + - contextPath: TC.Event.Status + description: The status of the event. + type: string + - contextPath: TC.Event.Owner + description: The owner of the event. + type: string + - contextPath: TC.Event.Tag + description: The tag of the event. + type: string + - contextPath: TC.Event.ID + description: The ID of the event. + type: string + description: Creates a group based on the "Event" type. + - name: tc-create-threat + arguments: + - name: name + required: true + description: The name of the threat group. + outputs: + - contextPath: TC.Threat.Name + description: The name of the threat. + type: string + - contextPath: TC.Threat.ID + description: The ID of the threat. + type: string + description: Creates a group based on the "Threats" type. + - name: tc-delete-group + arguments: + - name: groupID + required: true + description: The ID of the group to delete. + - name: type + required: true + auto: PREDEFINED + predefined: + - Incidents + - Events + - Campaigns + - Threats + description: The type of the group to delete. Can be "Incidents", "Events", + "Campaigns", or "Threats". + description: Deletes a group. + - name: tc-add-group-attribute + arguments: + - name: group_id + required: true + description: The ID of the group to which to add attributes. To get the ID of + the group, run the tc-get-groups command. + - name: attribute_type + required: true + description: The type of attribute to add to the group. The type is located + in the UI in a specific group or under Org Config. + - name: attribute_value + required: true + description: The value of the attribute. + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group. Can be "adversaries", "campaigns", "documents", + "emails", "events", "incidents", "intrusionSets", "reports", "signatures", + or "threats". + outputs: + - contextPath: TC.Group.DateAdded + description: The date on which the attribute was added. + type: Date + - contextPath: TC.Group.LastModified + description: The date on which the added attribute was last modified. + type: Date + - contextPath: TC.Group.Type + description: The type of the group to which the attribute was added. + type: String + - contextPath: TC.Group.Value + description: The value of the attribute added to the group. + type: String + - contextPath: TC.Group.ID + description: The group ID to which the attribute was added. + type: Number + description: Adds an attribute to a specified group. + - name: tc-get-events + arguments: [] + outputs: + - contextPath: TC.Event.DateAdded + description: The date on which the event was added. + type: Date + - contextPath: TC.Event.EventDate + description: The date on which the event occurred. + type: Date + - contextPath: TC.Event.ID + description: The ID of the event. + type: Number + - contextPath: TC.Event.OwnerName + description: The name of the owner of the event. + type: String + - contextPath: TC.Event.Status + description: The status of the event. + type: String + description: Returns a list of events. + - name: tc-get-groups + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group. Can be "adversaries", "campaigns", "documents", + "emails", "events", "incidents", "intrusionSets", "reports", "signatures", + or "threats". + outputs: + - contextPath: TC.Group.DateAdded + description: The date on which the group was added. + type: Date + - contextPath: TC.Group.EventDate + description: The date on which the event occurred. + type: Date + - contextPath: TC.Group.Name + description: The name of the group. + type: String + - contextPath: TC.Group.OwnerName + description: The name of the owner of the group. + type: String + - contextPath: TC.Group.Status + description: The status of the group. + type: String + - contextPath: TC.Group.ID + description: The ID of the group. + type: Number + description: Returns all groups, filtered by the group type. + - name: tc-add-group-security-label + arguments: + - name: group_id + required: true + description: The ID of the group to which to add the security label. To get + the ID, run the tc-get-groups command. + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group to which to add the security label. Can be + "adversaries", "campaigns", "documents", "emails", "events", "incidents", + "intrusionSets", "reports", "signatures", or "threats". + - name: security_label_name + required: true + description: The name of the security label to add to the group. For example, + "TLP:GREEN". + description: Adds a security label to a group. + - name: tc-add-group-tag + arguments: + - name: group_id + required: true + description: The ID of the group to which to add the tag. To get the ID, run + the tc-get-groups command. + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group to which to add the tag. Can be "adversaries", + "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", + "reports", "signatures", or "threats". + - name: tag_name + required: true + description: The name of the tag to add to the group. + description: Adds tags to a specified group. + - name: tc-get-indicator-types + arguments: [] + outputs: + - contextPath: TC.IndicatorType.ApiBranch + description: The branch of the API. + type: String + - contextPath: TC.IndicatorType.ApiEntity + description: The entity of the API. + type: String + - contextPath: TC.IndicatorType.CasePreference + description: The case preference of the indicator. For example, "sensitive", + "upper", or "lower". + type: String + - contextPath: TC.IndicatorType.Custom + description: Whether the indicator is a custom indicator. + type: Boolean + - contextPath: TC.IndicatorType.Parsable + description: Whether the indicator can be parsed. + type: Boolean + - contextPath: TC.IndicatorType.Value1Type + description: The name of the indicator. + type: String + - contextPath: TC.IndicatorType.Value1Label + description: The value label of the indicator. + type: String + description: Returns all indicator types available. + - name: tc-group-associate-indicator + arguments: + - name: indicator_type + required: true + description: The type of the indicator. To get the available types, run the + tc-get-indicator-types command. The indicator must be spelled as displayed + in the ApiBranch column of the UI. + - name: indicator + required: true + description: The name of the indicator. For example, "indicator_type=emailAddresses" + where "indicator=a@a.co.il". + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group. Can be "adversaries", "campaigns", "documents", + "emails", "events", "incidents", "intrusionSets", "reports", "signatures", + or "threats". + - name: group_id + required: true + description: The ID of the group. To get the ID of the group, run the tc-get-groups + command. + outputs: + - contextPath: TC.Group.GroupID + description: The ID of the group. + type: Number + - contextPath: TC.Group.GroupType + description: The type of the group. + type: String + - contextPath: TC.Group.Indicator + description: The name of the indicator. + type: String + - contextPath: TC.Group.IndicatorType + description: The type of the indicator. + type: String + description: Associates an indicator with a group. + - name: tc-create-document-group + arguments: + - name: file_name + required: true + description: The name of the file to display in the UI. + - name: name + required: true + description: The name of the file. + - name: malware + auto: PREDEFINED + predefined: + - "true" + - "false" + description: Whether the file is malware. If "true", ThreatConnect creates a + password-protected ZIP file on your local machine that contains the sample + and uploads the ZIP file. + - name: password + description: The password of the ZIP file. + - name: security_label + description: The security label of the group. + - name: description + description: A description of the group. + - name: entry_id + required: true + description: The file of the ID of the entry, as displayed in the War Room. + outputs: + - contextPath: TC.Group.Name + description: The name of the group. + type: String + - contextPath: TC.Group.Owner + description: The owner of the group. + type: String + - contextPath: TC.Group.EventDate + description: The date on which the group was created. + type: Date + - contextPath: TC.Group.Description + description: The description of the group. + type: String + - contextPath: TC.Group.SecurityLabel + description: The security label of the group. + type: String + - contextPath: TC.Group.ID + description: The ID of the group to which the attribute was added. + type: Number + description: Creates a document group. + - name: tc-get-group + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group for which to return the ID. Can be "adversaries", + "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", + "reports", "signatures", or "threats". + - name: group_id + required: true + description: The ID of the group to retrieve. To get the ID, run the tc-get-groups + command. + outputs: + - contextPath: TC.Group.DateAdded + description: The date on which the group was added. + type: Date + - contextPath: TC.Group.EventDate + description: The date on which the event occurred. + type: Date + - contextPath: TC.Group.Name + description: The name of the group. + type: String + - contextPath: TC.Group.Owner.ID + description: The ID of the group owner. + type: Number + - contextPath: TC.Group.Owner.Name + description: The name of the group owner. + type: String + - contextPath: TC.Group.Owner.Type + description: The type of the owner. + type: String + - contextPath: TC.Group.Status + description: The status of the group. + type: String + description: Retrieves a single group. + - name: tc-get-group-attributes + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group for which to return the attribute. Can be "adversaries", + "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", + "reports", "signatures", or "threats". + - name: group_id + required: true + description: The ID of the group for which to return the attribute. To get the + ID, run the tc-get-groups command. + outputs: + - contextPath: TC.Group.Attribute.DateAdded + description: The date on which the group was added. + type: Date + - contextPath: TC.Group.Attribute.Displayed + description: Whether the attribute is displayed on the UI. + type: Boolean + - contextPath: TC.Group.Attribute.AttributeID + description: The ID of the attribute. + type: Number + - contextPath: TC.Group.Attribute.LastModified + description: The date on which the attribute was last modified. + type: Date + - contextPath: TC.Group.Attribute.Type + description: The type of the attribute. + type: String + - contextPath: TC.Group.Attribute.Value + description: The value of the attribute. + type: String + description: Retrieves the attribute of a group. + - name: tc-get-group-security-labels + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group for which to return the security labels. Can + be "adversaries", "campaigns", "documents", "emails", "events", "incidents", + "intrusionSets", "reports", "signatures", or "threats". + - name: group_id + required: true + description: The ID of the group for which to return the security labels. To + get the ID, run the tc-get-groups command. + outputs: + - contextPath: TC.Group.SecurityLabel.Name + description: The name of the security label. + type: String + - contextPath: TC.Group.SecurityLabel.Description + description: The description of the security label. + type: String + - contextPath: TC.Group.SecurityLabel.DateAdded + description: The date on which the security label was added. + type: Date + description: Retrieves the security labels of a group. + - name: tc-get-group-tags + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group for which to return the tags. Can be "adversaries", + "campaigns", "documents", "emails", "events", "incidents", "intrusionSets", + "reports", "signatures", or "threats". + - name: group_id + required: true + description: The ID of the group for which to return the tags. To get the ID, + run the tc-get-groups command. + outputs: + - contextPath: TC.Group.Tag.Name + description: The name of the tag. + type: String + description: Retrieves the tags of a group. + - name: tc-download-document + arguments: + - name: document_id + required: true + description: The ID of the document. + outputs: + - contextPath: File.Size + description: The size of the file. + type: Number + - contextPath: File.SHA1 + description: The SHA1 hash of the file. + type: String + - contextPath: File.SHA256 + description: The SHA256 hash of the file. + type: String + - contextPath: File.Name + description: The name of the file. + type: String + - contextPath: File.SSDeep + description: The ssdeep hash of the file (same as displayed in file entries). + type: String + - contextPath: File.EntryID + description: The entry ID of the file. + type: String + - contextPath: File.Info + description: The information of the file. + type: String + - contextPath: File.Type + description: The type of the file. + type: String + - contextPath: File.MD5 + description: The MD5 hash of the file. + type: String + - contextPath: File.Extension + description: The extension of the file. + type: String + description: Downloads the contents of a document. + - name: tc-get-group-indicators + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group for which to return the indicators. Can be + "adversaries", "campaigns", "documents", "emails", "events", "incidents", + "intrusionSets", "reports", "signatures", or "threats". + - name: group_id + required: true + description: The ID of the group for which to return the indicators. To get + the ID, run the tc-get-groups command. + outputs: + - contextPath: TC.Group.Indicator.Summary + description: The summary of the indicator. + type: String + - contextPath: TC.Group.Indicator.ThreatAssessConfidence + description: The confidence rating of the indicator. + type: String + - contextPath: TC.Group.Indicator.IndicatorID + description: The ID of the indicator. + type: Number + - contextPath: TC.Group.Indicator.DateAdded + description: The date on which the indicator was added. + type: Date + - contextPath: TC.Group.Indicator.Type + description: The type of the indicator. + type: String + - contextPath: TC.Group.Indicator.Rating + description: The threat rating of the indicator. + type: Number + - contextPath: TC.Group.Indicator.ThreatAssertRating + description: The rating of the threat assert. + type: Number + - contextPath: TC.Group.Indicator.OwnerName + description: The name of the owner of the indicator. + type: String + - contextPath: TC.Group.Indicator.LastModified + description: The date that the indicator was last modified. + type: Date + description: Returns indicators associated with a group. + - name: tc-get-associated-groups + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group. Can be "adversaries", "campaigns", "documents", + "emails", "events", "incidents", "intrusionSets", "reports", "signatures", + or "threats". + - name: group_id + required: true + description: The ID of the group. To get the ID, run the tc-get-groups command. + outputs: + - contextPath: TC.Group.AssociatedGroup.DateAdded + description: The date on which group was added. + type: Date + - contextPath: TC.Group.AssociatedGroup.GroupID + description: The ID of the group. + type: Number + - contextPath: TC.Group.AssociatedGroup.Name + description: The name of the group. + type: String + - contextPath: TC.Group.AssociatedGroup.OwnerName + description: The name of the owner of the group. + type: String + - contextPath: TC.Group.AssociatedGroup.Type + description: The type of the group. + type: String + description: Returns indicators associated with a specified group. + - name: tc-associate-group-to-group + arguments: + - name: group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of the group. Can be "adversaries", "campaigns", "documents", + "emails", "events", "incidents", "intrusionSets", "reports", "signatures", + or "threats". + - name: group_id + required: true + description: The ID of the group. To get the ID of the group, run the tc-get-groups + command. + - name: associated_group_type + required: true + auto: PREDEFINED + predefined: + - adversaries + - campaigns + - documents + - emails + - events + - incidents + - intrusionSets + - reports + - signatures + - threats + description: The type of group to associate. Can be "adversaries", "campaigns", + "documents", "emails", "events", "incidents", "intrusionSets", "reports", + "signatures", or "threats". + - name: associated_group_id + required: true + description: The ID of the group to associate. + outputs: + - contextPath: TC.Group.AssociatedGroup.AssociatedGroupID + description: The ID of the associated group. + type: Number + - contextPath: TC.Group.AssociatedGroup.AssociatedGroupType + description: The type of the associated group. + type: String + - contextPath: TC.Group.AssociatedGroup.GroupID + description: The ID of the group to associate to. + type: Number + - contextPath: TC.Group.AssociatedGroup.GroupType + description: The type of the group to associate to. + type: String + description: Associates one group with another group. + - name: tc-get-indicator-owners + arguments: + - name: indicator + required: true + description: Indicator Value + description: Get Owner for Indicator + dockerimage: demisto/threatconnect-py3-sdk:1.0.0.8854 + runonce: false + subtype: python3 +fromversion: '5.0.0' +tests: +- ThreatConnect v2 - Test diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_description.md b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_description.md new file mode 100644 index 000000000000..9507da20536a --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_description.md @@ -0,0 +1,4 @@ +## ThreatConnect v2 +1. In **ThreatConnect** UI go to **settings** -> **Org settings**. +2. Go to **Membership** and click **Create API User** to add a new API user. +3. Finish the configuration as as you can see [here](https://training.threatconnect.com/learn/article/creating-user-accounts-kb-article#2). diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_image.png b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_image.png new file mode 100644 index 000000000000..002918ed21c0 Binary files /dev/null and b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_image.png differ diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_test.py b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_test.py new file mode 100644 index 000000000000..e4274808c8d6 --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/ThreatConnect_v2_test.py @@ -0,0 +1,225 @@ +from ThreatConnect_v2 import calculate_freshness_time, create_context, demisto +from freezegun import freeze_time +import pytest + +data_test_calculate_freshness_time = [ + (0, '2020-04-20'), + (1, '2020-04-19') +] + + +@freeze_time('2020-04-20') +@pytest.mark.parametrize('freshness, time_out', data_test_calculate_freshness_time) +def test_calculate_freshness_time(freshness, time_out): + time_out = f'{time_out}T00:00:00Z' + output = calculate_freshness_time(freshness) + assert output == time_out, f'calculate_freshness_time({freshness})\n\treturns: {output}\n\tinstead: {time_out}' + + +URL_INDICATOR = [{ + 'id': 113283093, + 'owner': 'Demisto Inc.', + 'dateAdded': '2020-05-14T09:07:29Z', + 'lastModified': '2020-05-14T09:07:29Z', + 'rating': 0.0, + 'confidence': 0, + 'threatAssessRating': 0.0, + 'threatAssessConfidence': 0.0, + 'webLink': 'https://sandbox.threatconnect.com/auth/indicators/details/url.xhtml?orgid=113283093&owner=Demisto+Inc.', + 'text': 'https://www.domain.info', + 'type': 'URL' +}] +URL_CONTEXT = ( + { + 'URL(val.Data && val.Data == obj.Data)': [{ + 'Malicious': { + 'Vendor': 'ThreatConnect', + 'Description': '' + }, + 'Data': 'https://www.domain.info' + }], + 'TC.Indicator(val.ID && val.ID === obj.ID)': [{ + 'ID': 113283093, + 'Name': 'https://www.domain.info', + 'Type': 'URL', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T09:07:29Z', + 'LastModified': '2020-05-14T09:07:29Z', + 'Rating': 0, + 'Confidence': 0 + }] + }, + [{ + 'ID': 113283093, + 'Name': 'https://www.domain.info', + 'Type': 'URL', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T09:07:29Z', + 'LastModified': '2020-05-14T09:07:29Z', + 'Rating': 0, + 'Confidence': 0 + }] +) +IP_INDICATOR = [{ + 'id': 113286420, + 'owner': 'Demisto Inc.', + 'dateAdded': '2020-05-14T13:16:32Z', + 'lastModified': '2020-05-14T13:16:32Z', + 'rating': 2.0, + 'confidence': 50, + 'threatAssessRating': 3.0, + 'threatAssessConfidence': 53.0, + 'webLink': 'https://sandbox.threatconnect.com/auth/indicators/details/address.xhtml?address=88.88.88.88&owner=Demisto+Inc.', + 'ip': '88.88.88.88', + 'type': 'Address' +}] +IP_CONTEXT = ( + { + 'IP(val.Address && val.Address == obj.Address)': [{ + 'Malicious': { + 'Vendor': 'ThreatConnect', + 'Description': '' + }, + 'Address': '88.88.88.88' + }], + 'TC.Indicator(val.ID && val.ID === obj.ID)': [{ + 'ID': 113286420, + 'Name': '88.88.88.88', + 'Type': 'Address', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T13:16:32Z', + 'LastModified': '2020-05-14T13:16:32Z', + 'Rating': 2, + 'Confidence': 50 + }] + }, + [{ + 'ID': 113286420, + 'Name': '88.88.88.88', + 'Type': 'Address', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T13:16:32Z', + 'LastModified': '2020-05-14T13:16:32Z', + 'Rating': 2, + 'Confidence': 50 + }] +) +DOMAIN_INDICATOR = [{ + 'id': 112618314, + 'owner': 'Demisto Inc.', + 'dateAdded': '2020-04-23T14:42:21Z', + 'lastModified': '2020-05-14T13:24:35Z', + 'rating': 0.0, + 'confidence': 0, + 'threatAssessRating': 0.0, + 'threatAssessConfidence': 0.0, + 'webLink': 'https://sandbox.threatconnect.com/auth/indicators/details/host.xhtml?host=domain.info&owner=Demisto+Inc.', + 'hostName': 'domain.info', + 'dnsActive': 'false', + 'whoisActive': 'false', + 'type': 'Host' +}] +DOMAIN_CONTEXT = ( + { + 'Domain(val.Name && val.Name == obj.Name)': [ + { + 'Malicious': { + 'Vendor': 'ThreatConnect', + 'Description': '' + }, + 'Name': 'domain.info' + } + ], + 'TC.Indicator(val.ID && val.ID === obj.ID)': [ + { + 'ID': 112618314, + 'Name': 'domain.info', + 'Type': 'Host', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-04-23T14:42:21Z', + 'LastModified': '2020-05-14T13:24:35Z', + 'Rating': 0, + 'Confidence': 0, + 'Active': 'false' + } + ] + }, + [{ + 'ID': 112618314, + 'Name': 'domain.info', + 'Type': 'Host', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-04-23T14:42:21Z', + 'LastModified': '2020-05-14T13:24:35Z', + 'Rating': 0, + 'Confidence': 0, + 'Active': 'false' + }] +) +FILE_INDICATOR = [{ + 'id': 113286426, + 'owner': 'Demisto Inc.', + 'dateAdded': '2020-05-14T13:22:49Z', + 'lastModified': '2020-05-14T13:22:49Z', + 'rating': 4.0, + 'confidence': 20, + 'threatAssessRating': 4.0, + 'threatAssessConfidence': 20.0, + 'webLink': 'https://sandbox.threatconnect.com/auth/indicators/details/file.xhtml?file=49456A' + # noqa: W504 + '40536940A1304A506D7278F6B19FC7F71BE545810F7CAFEAA35A086229&owner=Demisto+Inc.', + 'sha256': '49456A40536940A1304A506D7278F6B19FC7F71BE545810F7CAFEAA35A086229', + 'type': 'File' +}] +FILE_CONTEXT = ( + { + 'File(val.MD5 && val.MD5 == obj.MD5 || val.SHA1 && val.SHA1 == obj.SHA1 || val.SHA256 && ' + # noqa: W504 + 'val.SHA256 == obj.SHA256 || val.SHA512 && val.SHA512 == obj.SHA512 || val.CRC32 && ' + # noqa: W504 + 'val.CRC32 == obj.CRC32 || val.CTPH && val.CTPH == obj.CTPH || val.SSDeep && val.SSDeep == obj.SSDeep)': [{ + 'Malicious': { + 'Vendor': 'ThreatConnect', + 'Description': '' + }, + 'SHA256': '49456A40536940A1304A506D7278F6B19FC7F71BE545810F7CAFEAA35A086229' + }], + 'TC.Indicator(val.ID && val.ID === obj.ID)': [{ + 'ID': 113286426, + 'Type': 'File', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T13:22:49Z', + 'LastModified': '2020-05-14T13:22:49Z', + 'Rating': 4, + 'Confidence': 20, + 'File': { + 'SHA256': '49456A40536940A1304A506D7278F6B19FC7F71BE545810F7CAFEAA35A086229' + } + }] + }, + [{ + 'ID': 113286426, + 'Type': 'File', + 'Owner': 'Demisto Inc.', + 'CreateDate': '2020-05-14T13:22:49Z', + 'LastModified': '2020-05-14T13:22:49Z', + 'Rating': 4, + 'Confidence': 20, + 'File': { + 'SHA256': '49456A40536940A1304A506D7278F6B19FC7F71BE545810F7CAFEAA35A086229' + } + }] +) + +data_test_create_context = [ + ({}, ({}, [])), + (DOMAIN_INDICATOR, DOMAIN_CONTEXT), + (IP_INDICATOR, IP_CONTEXT), + (URL_INDICATOR, URL_CONTEXT), + (FILE_INDICATOR, FILE_CONTEXT), +] + + +@ pytest.mark.parametrize('indicators, expected_output', data_test_create_context) +def test_create_context(indicators, expected_output, mocker): + params = {"defaultOrg": "Demisto Inc.", "freshness": 7, "rating": 0, "confidence": 0} + mocker.patch.object(demisto, 'params', return_value=params) + output = create_context(indicators) + assert output == expected_output, f'expected_output({indicators})\n\treturns: {output}\n\tinstead: {expected_output}' diff --git a/Packs/ThreatConnect/Integrations/ThreatConnect_v2/comannds.txt b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/comannds.txt new file mode 100644 index 000000000000..56503d510321 --- /dev/null +++ b/Packs/ThreatConnect/Integrations/ThreatConnect_v2/comannds.txt @@ -0,0 +1,40 @@ +!ip ip=88.88.88.88 +!file file=4a4a4e885f7189bbaa2fcc2f2403b128f79e951826c57c0e1ab50e085ae390e7 +!domain domain=domain.info +!url url=https://www.domain.com +!tc-create-campaign name=test_campaign description="test campaign" +#!tc-create-document-group entry_id=<> file_name=test.txt name=test_document +#!tc-download-document document_id=<> +!tc-create-event name=test_event +!tc-create-incident incidentName=test_incident +!tc-create-threat name=test_threat +!tc-add-group-tag group_id=5101576 group_type=incidents tag_name="malicious ip" +!tc-get-group-tags group_id=5101576 group_type=incidents +!tc-add-group-security-label group_id=5101576 group_type=incidents security_label_name=TLP:GREEN +!tc-add-group-attribute group_id=5101576 group_type=incidents attribute_type=description attribute_value="test add group attribute" +!tc-associate-group-to-group group_id=5101576 group_type=incidents associated_group_id=5101578 associated_group_type=campaigns +!tc-get-associated-groups group_id=5101576 group_type=incidents +!tc-get-group-indicators group_id=5101576 group_type=incidents +!tc-get-incident-associate-indicators incidentId=5101576 owner="Demisto Inc." +!tc-fetch-incidents incidentId=5101576 +!tc-get-groups group_type=incidents +!tc-get-group group_id=5101576 group_type=incidents +!tc-get-group-security-labels group_id=5101576 group_type=incidents +!tc-get-group-attributes group_id=5101576 group_type=incidents +!tc-get-events +!tc-delete-group groupID=5101578 type=Campaigns +!tc-add-indicator indicator=99.99.99.99 confidence=70 rating=2 +!tc-tag-indicator indicator=99.99.99.99 tag="malicious ip" +!tc-get-indicators-by-tag tag="malicious ip" +!tc-delete-indicator-tag indicator=99.99.99.99 tag="malicious ip" +!tc-update-indicator indicator=99.99.99.99 rating=1 +!tc-get-indicator indicator=99.99.99.99 group_associations=false +!tc-get-indicator-owners indicator=99.99.99.99 +!tc-get-indicator-types +!tc-group-associate-indicator indicator_type=Addresses group_id=5101576 group_type=incidents indicator=99.99.99.99 +!tc-incident-associate-indicator indicator=99.99.99.99 indicatorType=ADDRESSES incidentId=5101577 +!tc-delete-indicator indicator=99.99.99.99 +!tc-get-tags +!tc-indicators limit=3 owner="Demisto Inc." +!tc-owners +!tc-get-tags diff --git a/Packs/ThreatConnect/ReleaseNotes/2_0_0.md b/Packs/ThreatConnect/ReleaseNotes/2_0_0.md new file mode 100644 index 000000000000..e2be77891e01 --- /dev/null +++ b/Packs/ThreatConnect/ReleaseNotes/2_0_0.md @@ -0,0 +1,6 @@ + +#### Integrations +##### ThreatConnect + - Depreciated old ThreatConnect. +##### ThreatConnect v2 + - New integration. diff --git a/Packs/ThreatConnect/TestPlaybooks/ThreatConnect_v2_-_Test.yml b/Packs/ThreatConnect/TestPlaybooks/ThreatConnect_v2_-_Test.yml new file mode 100644 index 000000000000..a03fa81de415 --- /dev/null +++ b/Packs/ThreatConnect/TestPlaybooks/ThreatConnect_v2_-_Test.yml @@ -0,0 +1,1889 @@ +id: ThreatConnect v2 - Test +version: -1 +name: ThreatConnect v2 - Test +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: b7e15a23-20e9-4a8f-8869-7bc79f35145f + type: start + task: + id: b7e15a23-20e9-4a8f-8869-7bc79f35145f + version: -1 + name: "" + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "39" + separatecontext: false + view: |- + { + "position": { + "x": 660, + "y": -170 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "1": + id: "1" + taskid: cfd1b9b6-d3be-49a9-80c5-85367f5e760b + type: regular + task: + id: cfd1b9b6-d3be-49a9-80c5-85367f5e760b + version: -1 + name: tc-add-indicator + description: Adds a new indicator to ThreatConnect. + script: 'tc-add-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "2" + - "23" + - "3" + scriptarguments: + confidence: + simple: "20" + indicator: + simple: 88.88.88.88 + owner: {} + rating: + simple: "0" + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "2": + id: "2" + taskid: 2ec22677-db80-4ab9-8dce-1f127560041b + type: regular + task: + id: 2ec22677-db80-4ab9-8dce-1f127560041b + version: -1 + name: ip + description: Searches for an indicator of type IP address. + script: 'ip' + type: regular + iscommand: true + brand: ThreatConnect v2 + nexttasks: + '#none#': + - "47" + scriptarguments: + confidenceThreshold: {} + ip: + simple: 88.88.88.88 + long: {} + owners: {} + ratingThreshold: {} + threshold: {} + separatecontext: false + view: |- + { + "position": { + "x": 470, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "3": + id: "3" + taskid: d6ff208c-64db-4afd-89d5-18f420d71ee5 + type: regular + task: + id: d6ff208c-64db-4afd-89d5-18f420d71ee5 + version: -1 + name: tc-tag-indicator + description: Adds a tag to an existing indicator. + script: 'tc-tag-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "4" + scriptarguments: + indicator: + simple: 88.88.88.88 + owner: {} + tag: + simple: hello + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "4": + id: "4" + taskid: c1dd608e-de49-4b6b-8917-80a6408aa275 + type: regular + task: + id: c1dd608e-de49-4b6b-8917-80a6408aa275 + version: -1 + name: tc-update-indicator + description: Updates the indicator in ThreatConnect. + script: 'tc-update-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "5" + scriptarguments: + confidence: + simple: "100" + dnsActive: {} + falsePositive: {} + indicator: + simple: 88.88.88.88 + observations: {} + rating: + simple: "0" + securityLabel: {} + size: {} + threatAssessConfidence: {} + threatAssessRating: {} + updatedValues: {} + whoisActive: {} + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 665 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "5": + id: "5" + taskid: 8c3dce3a-f91a-4638-80a6-a9997bb17e06 + type: regular + task: + id: 8c3dce3a-f91a-4638-80a6-a9997bb17e06 + version: -1 + name: tc-get-indicators-by-tag + description: Fetches all indicators that have a tag. + script: 'tc-get-indicators-by-tag' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "6" + scriptarguments: + owner: {} + tag: + simple: hello + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 830 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "6": + id: "6" + taskid: 06ecf98d-c0bf-4efe-8869-04e06cfd9256 + type: regular + task: + id: 06ecf98d-c0bf-4efe-8869-04e06cfd9256 + version: -1 + name: tc-get-indicator-owners + description: Get Owner for Indicator + script: 'tc-get-indicator-owners' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "12" + scriptarguments: + indicator: + simple: 88.88.88.88 + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1000 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "7": + id: "7" + taskid: aceb6c05-5769-4e62-8562-91742f12af1f + type: regular + task: + id: aceb6c05-5769-4e62-8562-91742f12af1f + version: -1 + name: tc-delete-indicator-tag + description: Removes a tag from a specified indicator. + script: 'tc-delete-indicator-tag' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "22" + scriptarguments: + indicator: + simple: 88.88.88.88 + tag: + simple: hello + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1315 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "8": + id: "8" + taskid: 5055f9cb-1aff-41fc-87e7-2601d0200491 + type: regular + task: + id: 5055f9cb-1aff-41fc-87e7-2601d0200491 + version: -1 + name: tc-owners + description: Retrieves all owners for the current account. + script: 'tc-owners' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + separatecontext: false + view: |- + { + "position": { + "x": 2250, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "9": + id: "9" + taskid: cf52b091-ff40-4fc7-84bf-0aca29d1e47d + type: regular + task: + id: cf52b091-ff40-4fc7-84bf-0aca29d1e47d + version: -1 + name: tc-indicators + description: Retrieves a list of all indicators. + script: 'tc-indicators' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + scriptarguments: + limit: {} + owner: {} + separatecontext: false + view: |- + { + "position": { + "x": 2670, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "10": + id: "10" + taskid: ad0471e6-bb6b-476f-8d63-91e526a226ff + type: regular + task: + id: ad0471e6-bb6b-476f-8d63-91e526a226ff + version: -1 + name: tc-get-tags + description: Returns a list of all ThreatConnect tags. + script: 'tc-get-tags' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + separatecontext: false + view: |- + { + "position": { + "x": 1830, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "11": + id: "11" + taskid: 8a18bb37-db0d-4659-8493-f6f4de9bba18 + type: regular + task: + id: 8a18bb37-db0d-4659-8493-f6f4de9bba18 + version: -1 + name: tc-get-indicator-types + description: Returns all indicator types available. + script: 'tc-get-indicator-types' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + separatecontext: false + view: |- + { + "position": { + "x": 1830, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "12": + id: "12" + taskid: 4d03213d-d58f-4528-82b4-637408b82e33 + type: regular + task: + id: 4d03213d-d58f-4528-82b4-637408b82e33 + version: -1 + name: tc-get-indicator + description: Retrieves information about an indicator. + script: 'tc-get-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "7" + scriptarguments: + confidenceThreshold: {} + group_associations: + simple: "false" + indicator: + simple: 88.88.88.88 + indicator_associations: {} + indicator_observations: + simple: "true" + indicator_tags: + simple: "true" + indicator_type: {} + owners: {} + ratingThreshold: {} + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1160 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "13": + id: "13" + taskid: a5635224-2d51-49b9-86a9-ee01ec9d059a + type: regular + task: + id: a5635224-2d51-49b9-86a9-ee01ec9d059a + version: -1 + name: tc-create-campaign + description: Creates a group based on the "Campaign" type. + script: 'tc-create-campaign' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "14" + scriptarguments: + description: {} + firstSeen: {} + name: + simple: test_group + owner: {} + securityLabel: {} + tag: {} + separatecontext: false + view: |- + { + "position": { + "x": -890, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "14": + id: "14" + taskid: d1762a2d-ab09-438f-8847-9413e63dd27b + type: regular + task: + id: d1762a2d-ab09-438f-8847-9413e63dd27b + version: -1 + name: tc-add-group-attribute + description: Adds an attribute to a specified group. + script: 'tc-add-group-attribute' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "15" + scriptarguments: + attribute_type: + simple: Description + attribute_value: + simple: try + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -890, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "15": + id: "15" + taskid: 4d78a0ca-0323-4ee1-83e8-415bed71af02 + type: regular + task: + id: 4d78a0ca-0323-4ee1-83e8-415bed71af02 + version: -1 + name: tc-add-group-security-label + description: Adds a security label to a group. + script: 'tc-add-group-security-label' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "16" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + security_label_name: + simple: try_test + separatecontext: false + view: |- + { + "position": { + "x": -890, + "y": 665 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "16": + id: "16" + taskid: b962c6d7-c7db-4371-825c-75a39188c027 + type: regular + task: + id: b962c6d7-c7db-4371-825c-75a39188c027 + version: -1 + name: tc-add-group-tag + description: Adds tags to a specified group. + script: 'tc-add-group-tag' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "18" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + tag_name: + simple: hello + separatecontext: false + view: |- + { + "position": { + "x": -890, + "y": 830 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "17": + id: "17" + taskid: ceb093cd-f9a7-4842-8382-601ed6af5ae0 + type: regular + task: + id: ceb093cd-f9a7-4842-8382-601ed6af5ae0 + version: -1 + name: tc-create-event + description: Creates a group based on the "Event" type. + script: 'tc-create-event' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "18" + scriptarguments: + description: {} + eventDate: {} + name: + simple: event_test + owner: {} + status: + simple: No Further Action + tag: {} + separatecontext: false + view: |- + { + "position": { + "x": -1340, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "18": + id: "18" + taskid: cc3b0f70-53e1-42d3-80a8-2b2914545335 + type: regular + task: + id: cc3b0f70-53e1-42d3-80a8-2b2914545335 + version: -1 + name: tc-associate-group-to-group + description: Associates one group with another group. + script: 'tc-associate-group-to-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "19" + scriptarguments: + associated_group_id: + simple: ${TC.Event.ID} + associated_group_type: + simple: events + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -1110, + "y": 1075 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "19": + id: "19" + taskid: c7e2364b-fd4f-4609-8ad4-1d42eaf43bd0 + type: regular + task: + id: c7e2364b-fd4f-4609-8ad4-1d42eaf43bd0 + version: -1 + name: tc-get-group-tags + description: Retrieves the tags of a group. + script: 'tc-get-group-tags' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "20" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -1110, + "y": 1235 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "20": + id: "20" + taskid: b4cd850d-9ff7-4bea-8b5e-3eb1478292a4 + type: regular + task: + id: b4cd850d-9ff7-4bea-8b5e-3eb1478292a4 + version: -1 + name: tc-get-group-security-labels + description: Retrieves the security labels of a group. + script: 'tc-get-group-security-labels' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "23" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -1110, + "y": 1390 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "21": + id: "21" + taskid: eda3f3e8-6c58-4037-827c-329dbc127ce8 + type: regular + task: + id: eda3f3e8-6c58-4037-827c-329dbc127ce8 + version: -1 + name: tc-create-incident + description: Creates a new incident group. + script: 'tc-create-incident' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "22" + scriptarguments: + description: {} + eventDate: {} + incidentName: + simple: test + owner: {} + securityLabel: + simple: TLP:AMBER + tag: {} + separatecontext: false + view: |- + { + "position": { + "x": -1790, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "22": + id: "22" + taskid: 14d6fac8-837a-49d5-8401-3d8116d2b702 + type: regular + task: + id: 14d6fac8-837a-49d5-8401-3d8116d2b702 + version: -1 + name: tc-incident-associate-indicator + description: Associates an indicator with an existing incident. The indicator + must exist before running this command. To add an indicator, run the tc-add-indicator + command. + script: 'tc-incident-associate-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "27" + scriptarguments: + incidentId: + simple: ${TC.Incident.ID} + indicator: + simple: 88.88.88.88 + indicatorType: + simple: ADDRESSES + owner: {} + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1470 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "23": + id: "23" + taskid: 860bd06a-b210-45a0-87ed-f0d9038f80d4 + type: regular + task: + id: 860bd06a-b210-45a0-87ed-f0d9038f80d4 + version: -1 + name: tc-group-associate-indicator + description: Associates an indicator with a group. + script: 'tc-group-associate-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "24" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + indicator: + simple: 88.88.88.88 + indicator_type: + simple: addresses + separatecontext: false + view: |- + { + "position": { + "x": -860, + "y": 1640 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "24": + id: "24" + taskid: bfd07163-5293-4220-8c04-9cb94906709a + type: regular + task: + id: bfd07163-5293-4220-8c04-9cb94906709a + version: -1 + name: tc-get-associated-groups + description: Returns indicators associated with a specified group. + script: 'tc-get-associated-groups' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "25" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -860, + "y": 1795 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "25": + id: "25" + taskid: 3bac4fce-ac8b-4e86-8d31-8f6172dbf717 + type: regular + task: + id: 3bac4fce-ac8b-4e86-8d31-8f6172dbf717 + version: -1 + name: tc-get-group-indicators + description: Returns indicators associated with a group. + script: 'tc-get-group-indicators' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "40" + scriptarguments: + group_id: + simple: ${TC.Campaign.ID} + group_type: + simple: campaigns + separatecontext: false + view: |- + { + "position": { + "x": -860, + "y": 1955 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "26": + id: "26" + taskid: 569f6353-5bf2-4481-8984-de13e10e8886 + type: regular + task: + id: 569f6353-5bf2-4481-8984-de13e10e8886 + version: -1 + name: tc-get-groups + description: Returns all groups, filtered by the group type. + script: 'tc-get-groups' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + scriptarguments: + group_type: + simple: incidents + separatecontext: false + view: |- + { + "position": { + "x": 2250, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "27": + id: "27" + taskid: 666d6a9f-7a55-43ed-8a8d-bda0d14694a1 + type: regular + task: + id: 666d6a9f-7a55-43ed-8a8d-bda0d14694a1 + version: -1 + name: tc-get-incident-associate-indicators + description: Returns indicators that are related to a specific incident. + script: 'tc-get-incident-associate-indicators' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "33" + scriptarguments: + incidentId: + simple: ${TC.Incident.ID} + owner: {} + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1640 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "28": + id: "28" + taskid: b9257f8f-f0d8-48c2-812b-82bb285c6005 + type: regular + task: + id: b9257f8f-f0d8-48c2-812b-82bb285c6005 + version: -1 + name: tc-delete-indicator + description: Deletes an indicator from ThreatConnect. + script: 'tc-delete-indicator' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "38" + scriptarguments: + indicator: + simple: 88.88.88.88 + separatecontext: false + view: |- + { + "position": { + "x": 1260, + "y": 2360 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "29": + id: "29" + taskid: f2cbefa2-597e-48ba-84e8-a667e78d00e1 + type: regular + task: + id: f2cbefa2-597e-48ba-84e8-a667e78d00e1 + version: -1 + name: tc-delete-group + description: Deletes a group. + script: 'tc-delete-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "38" + scriptarguments: + groupID: + simple: ${TC.Incident.ID} + type: + simple: Incidents + separatecontext: false + view: |- + { + "position": { + "x": 60, + "y": 2360 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "30": + id: "30" + taskid: 1c4c2a7c-163e-43c4-8d50-f077c2592d29 + type: regular + task: + id: 1c4c2a7c-163e-43c4-8d50-f077c2592d29 + version: -1 + name: domain + description: Searches for an indicator of type domain. + script: 'domain' + type: regular + iscommand: true + brand: ThreatConnect v2 + nexttasks: + '#none#': + - "47" + scriptarguments: + confidenceThreshold: {} + domain: + simple: test.com + long: {} + owners: {} + ratingThreshold: {} + threshold: {} + separatecontext: false + view: |- + { + "position": { + "x": 470, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "31": + id: "31" + taskid: f326bf50-2b0c-41da-8a8c-d9ad3a595c3f + type: regular + task: + id: f326bf50-2b0c-41da-8a8c-d9ad3a595c3f + version: -1 + name: file + description: Searches for an indicator of type file. + script: 'file' + type: regular + iscommand: true + brand: ThreatConnect v2 + nexttasks: + '#none#': + - "47" + scriptarguments: + confidenceThreshold: {} + file: + simple: 800304045813c739c71e691ef7f51b99d7491c78857f080b6121cac23a90f7cf + long: {} + owners: {} + ratingThreshold: {} + separatecontext: false + view: |- + { + "position": { + "x": 20, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "32": + id: "32" + taskid: 2bf311e2-c63e-421b-8247-d33d705bf22a + type: regular + task: + id: 2bf311e2-c63e-421b-8247-d33d705bf22a + version: -1 + name: url + description: Searches for an indicator of type URL. + script: 'url' + type: regular + iscommand: true + brand: ThreatConnect v2 + nexttasks: + '#none#': + - "47" + scriptarguments: + confidenceThreshold: {} + long: {} + owners: {} + ratingThreshold: {} + threshold: {} + url: + simple: https://www.test.com + separatecontext: false + view: |- + { + "position": { + "x": 20, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "33": + id: "33" + taskid: 93ba19ad-d169-4d43-8913-6338e2c8d582 + type: regular + task: + id: 93ba19ad-d169-4d43-8913-6338e2c8d582 + version: -1 + name: tc-fetch-incidents + description: Fetches incidents from ThreatConnect. + script: 'tc-fetch-incidents' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "40" + scriptarguments: + incidentId: + simple: ${TC.Incident.ID} + incidentName: {} + owner: {} + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 1810 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "34": + id: "34" + taskid: a66d861c-059b-46f1-8d03-cb0b30d86e2b + type: regular + task: + id: a66d861c-059b-46f1-8d03-cb0b30d86e2b + version: -1 + name: tc-create-threat + description: Creates a group based on the "Threats" type. + script: 'tc-create-threat' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "37" + scriptarguments: + name: + simple: test_threat + separatecontext: false + view: |- + { + "position": { + "x": -440, + "y": 330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "35": + id: "35" + taskid: 28c9a88b-3917-4b50-83fe-6878951c4cf8 + type: regular + task: + id: 28c9a88b-3917-4b50-83fe-6878951c4cf8 + version: -1 + name: tc-delete-group + description: Deletes a group. + script: 'tc-delete-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "38" + scriptarguments: + groupID: + simple: ${TC.Threat.ID} + type: + simple: Threats + separatecontext: false + view: |- + { + "position": { + "x": -440, + "y": 665 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "36": + id: "36" + taskid: 47276232-713f-4671-86fc-aff7ddedc0aa + type: regular + task: + id: 47276232-713f-4671-86fc-aff7ddedc0aa + version: -1 + name: tc-get-events + description: Returns a list of events. + script: 'tc-get-events' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "45" + separatecontext: false + view: |- + { + "position": { + "x": 2670, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "37": + id: "37" + taskid: b623b16d-631a-4851-821a-7bf81aeca475 + type: regular + task: + id: b623b16d-631a-4851-821a-7bf81aeca475 + version: -1 + name: tc-get-group + description: Retrieves a single group. + script: 'tc-get-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "35" + scriptarguments: + group_id: + simple: ${TC.Threat.ID} + group_type: + simple: threats + separatecontext: false + view: |- + { + "position": { + "x": -440, + "y": 500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "38": + id: "38" + taskid: 4aa016c6-8ffa-4fa2-8e80-de921cb735fe + type: title + task: + id: 4aa016c6-8ffa-4fa2-8e80-de921cb735fe + version: -1 + name: done + type: title + iscommand: false + description: '' + brand: '' + separatecontext: false + view: |- + { + "position": { + "x": 660, + "y": 2640 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "39": + id: "39" + taskid: b5477a27-6eb6-4512-8135-0fe495138ea1 + type: regular + task: + id: b5477a27-6eb6-4512-8135-0fe495138ea1 + version: -1 + name: delete_context + description: Delete field from context + scriptName: DeleteContext + type: regular + iscommand: false + brand: '' + nexttasks: + '#none#': + - "46" + - "48" + - "44" + - "43" + scriptarguments: + all: + simple: "yes" + index: {} + key: {} + keysToKeep: {} + subplaybook: {} + separatecontext: false + view: |- + { + "position": { + "x": 660, + "y": 0 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "40": + id: "40" + taskid: ad7425b1-3c42-46e9-8a3e-1bbbf5bdb047 + type: title + task: + id: ad7425b1-3c42-46e9-8a3e-1bbbf5bdb047 + version: -1 + name: delete + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "28" + - "29" + - "41" + - "42" + separatecontext: false + view: |- + { + "position": { + "x": 660, + "y": 2190 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "41": + id: "41" + taskid: 5d828810-6e31-4f28-8c26-4e8909dca43d + type: regular + task: + id: 5d828810-6e31-4f28-8c26-4e8909dca43d + version: -1 + name: tc-delete-group + description: Deletes a group. + script: 'tc-delete-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "38" + scriptarguments: + groupID: + simple: ${TC.Event.ID} + type: + simple: Events + separatecontext: false + view: |- + { + "position": { + "x": 860, + "y": 2360 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "42": + id: "42" + taskid: 654041c2-a13a-4c36-8d03-f98413eac087 + type: regular + task: + id: 654041c2-a13a-4c36-8d03-f98413eac087 + version: -1 + name: tc-delete-group + description: Deletes a group. + script: 'tc-delete-group' + type: regular + iscommand: true + brand: '' + nexttasks: + '#none#': + - "38" + scriptarguments: + groupID: + simple: ${TC.Campaign.ID} + type: + simple: Campaigns + separatecontext: false + view: |- + { + "position": { + "x": 460, + "y": 2360 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "43": + id: "43" + taskid: c04be99b-17ed-4ebc-88c3-ac5e440ecf96 + type: title + task: + id: c04be99b-17ed-4ebc-88c3-ac5e440ecf96 + version: -1 + name: groups + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "34" + - "17" + - "13" + - "21" + separatecontext: false + view: |- + { + "position": { + "x": -1120, + "y": 190 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "44": + id: "44" + taskid: 6bd1dcbf-4ab9-400f-8c6e-81ec232fc8f7 + type: title + task: + id: 6bd1dcbf-4ab9-400f-8c6e-81ec232fc8f7 + version: -1 + name: get commands + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "8" + - "9" + - "10" + - "36" + - "11" + - "26" + separatecontext: false + view: |- + { + "position": { + "x": 2250, + "y": 190 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "45": + id: "45" + taskid: 9dcb9e6f-9e3d-483f-84c9-ee349c0e750e + type: title + task: + id: 9dcb9e6f-9e3d-483f-84c9-ee349c0e750e + version: -1 + name: get output tests + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "51" + separatecontext: false + view: |- + { + "position": { + "x": 2260, + "y": 720 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "46": + id: "46" + taskid: cf827e27-b2de-4028-8172-95949a32440a + type: title + task: + id: cf827e27-b2de-4028-8172-95949a32440a + version: -1 + name: indicators + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "31" + - "32" + - "30" + - "2" + separatecontext: false + view: |- + { + "position": { + "x": 250, + "y": 190 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "47": + id: "47" + taskid: 3d50eb04-134f-406f-89b1-9f2e2490c02b + type: title + task: + id: 3d50eb04-134f-406f-89b1-9f2e2490c02b + version: -1 + name: indicators output + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "49" + separatecontext: false + view: |- + { + "position": { + "x": 250, + "y": 680 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "48": + id: "48" + taskid: cd7776d5-017a-4efc-88e7-da3390466b25 + type: title + task: + id: cd7776d5-017a-4efc-88e7-da3390466b25 + version: -1 + name: indicator commands + type: title + iscommand: false + description: '' + brand: '' + nexttasks: + '#none#': + - "1" + separatecontext: false + view: |- + { + "position": { + "x": 1280, + "y": 190 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "49": + id: "49" + taskid: 11d737d8-7cba-4874-806b-436b1cbee162 + type: condition + task: + id: 11d737d8-7cba-4874-806b-436b1cbee162 + version: -1 + name: output testing + type: condition + iscommand: false + description: '' + brand: '' + nexttasks: + '#default#': + - "50" + "yes": + - "38" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: ${TC.Indicator.[0].ID} + iscontext: true + - - operator: isNotEmpty + left: + value: + simple: ${TC.Indicator.[1].ID} + iscontext: true + - - operator: isNotEmpty + left: + value: + simple: ${TC.Indicator.[2].ID} + iscontext: true + - - operator: isNotEmpty + left: + value: + simple: ${TC.Indicator.[3].ID} + iscontext: true + view: |- + { + "position": { + "x": 250, + "y": 810 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "50": + id: "50" + taskid: 6bcc86ce-5abd-47a8-827e-f759a876da58 + type: regular + task: + id: 6bcc86ce-5abd-47a8-827e-f759a876da58 + version: -1 + name: print error + description: Prints an error entry with a given message + scriptName: PrintErrorEntry + type: regular + iscommand: false + brand: '' + nexttasks: + '#none#': + - "53" + scriptarguments: + message: + simple: indicator command failed. + separatecontext: false + view: |- + { + "position": { + "x": 0, + "y": 960 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "51": + id: "51" + taskid: 1f70cd40-0406-4123-8f27-ac9e66c57a77 + type: condition + task: + id: 1f70cd40-0406-4123-8f27-ac9e66c57a77 + version: -1 + name: test outputs for get commands + type: condition + iscommand: false + description: '' + brand: '' + nexttasks: + '#default#': + - "52" + "yes": + - "38" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: ${TC.Event.ID} + iscontext: true + - - operator: isEqualString + left: + value: + simple: ${TC.IndicatorType.[0].ApiBranch} + iscontext: true + right: + value: + simple: addresses + - - operator: isEqualString + left: + value: + simple: ${TC.Tags.[0]} + iscontext: true + right: + value: + simple: asdf + - - operator: isEqualString + left: + value: + simple: ${TC.Owner.[0].Name} + iscontext: true + right: + value: + simple: Demisto Inc. + view: |- + { + "position": { + "x": 2260, + "y": 840 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "52": + id: "52" + taskid: 64fff7de-c09b-4c20-8968-37fb7ee01605 + type: regular + task: + id: 64fff7de-c09b-4c20-8968-37fb7ee01605 + version: -1 + name: print error + description: Prints an error entry with a given message + scriptName: PrintErrorEntry + type: regular + iscommand: false + brand: '' + nexttasks: + '#none#': + - "53" + scriptarguments: + message: + simple: get command failure + separatecontext: false + view: |- + { + "position": { + "x": 2510, + "y": 980 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "53": + id: "53" + taskid: 33d21f92-1cb4-4bd5-80fb-878a83a0bd6e + type: title + task: + id: 33d21f92-1cb4-4bd5-80fb-878a83a0bd6e + version: -1 + name: error + type: title + iscommand: false + description: '' + brand: '' + separatecontext: false + view: |- + { + "position": { + "x": 2210, + "y": 1560 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 +view: |- + { + "linkLabelsPosition": {}, + "paper": { + "dimensions": { + "height": 2875, + "width": 4840, + "x": -1790, + "y": -170 + } + } + } +inputs: [] +outputs: [] +fromversion: 5.0.0 +description: '' diff --git a/Packs/ThreatConnect/pack_metadata.json b/Packs/ThreatConnect/pack_metadata.json index e49c9be4bfff..e788aaf674c1 100644 --- a/Packs/ThreatConnect/pack_metadata.json +++ b/Packs/ThreatConnect/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ThreatConnect", "description": "Threat intelligence platform.", "support": "xsoar", - "currentVersion": "1.0.1", + "currentVersion": "2.0.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.py b/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.py index 42d055e75bc8..d692e6374a56 100644 --- a/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.py +++ b/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.py @@ -107,7 +107,7 @@ def extract_and_validate_http_response(response, operation_err_message, test=Fal err_obj = json.loads(xml2json(response.text)) err_message = demisto.get(err_obj, 'Error.Message') except Exception: - err_message = f'Could not parse error' + err_message = 'Could not parse error' return_error(f'{operation_err_message}: \n{err_message}') @@ -138,7 +138,7 @@ def http_request(method, url_suffix, plain_url=False, params=None, data=None, op headers=create_headers(with_auth), ) except requests.exceptions.ConnectionError: - return_error(f'Error connecting to Traps server. Please check your connection and you server address') + return_error('Error connecting to Traps server. Please check your connection and you server address') if parse_response: result = extract_and_validate_http_response(result, operation_err, plain_url) return result @@ -278,7 +278,7 @@ def update_event_status(event_ids, status): Returns: API response. """ - path = f'events/status' + path = 'events/status' data = { "guids": event_ids, "status": status @@ -381,7 +381,7 @@ def hashes_blacklist_status(hash_ids): Returns: Hashes and blacklisting data. """ - path = f'hashes/blacklist-status' + path = 'hashes/blacklist-status' data = { 'hashes': hash_ids } @@ -471,7 +471,7 @@ def endpoint_isolate_status(operation_id): Returns: endpoint status, operation ID """ - status, _ = sam_operation(operation_id, f'Could not get endpoint isolate status') + status, _ = sam_operation(operation_id, 'Could not get endpoint isolate status') return {'Status': status, 'OperationID': operation_id} @@ -484,7 +484,7 @@ def event_quarantine_result(operation_id): Returns: quarantine data. """ - status, additional_data = sam_operation(operation_id, f'Could not get event quarantine status') + status, additional_data = sam_operation(operation_id, 'Could not get event quarantine status') quarantine_data = parse_data_from_response(additional_data.get('quarantineData'), 'event_quarantine_result') if additional_data else {} quarantine_data['Status'] = status @@ -501,12 +501,12 @@ def endpoint_files_retrieve_result(operation_id): Returns: file as an entry, status, operation_id. """ - status, additional_data = sam_operation(operation_id, f'Failed to get file retrieve results') + status, additional_data = sam_operation(operation_id, 'Failed to get file retrieve results') if status == 'finished': file_info = additional_data.get('uploadData') file_name = file_info.get('fileName') url = file_info.get('downloadUrl') - data = http_request('GET', url, plain_url=True, operation_err=f'Unable to download file.', with_auth=False) + data = http_request('GET', url, plain_url=True, operation_err='Unable to download file.', with_auth=False) demisto.results(fileResult(filename=file_name, data=data)) return {'Status': status, 'OperationID': operation_id} @@ -601,7 +601,7 @@ def endpoint_scan_result_command(): args = demisto.args() operation_id = args.get('operation_id') status_obj = endpoint_scan_result(operation_id) - context = {f'Traps.ScanResult(val.OperationID == obj.OperationID)': status_obj} + context = {'Traps.ScanResult(val.OperationID == obj.OperationID)': status_obj} human_readable = tableToMarkdown(f'Status of scan operation: {operation_id}', status_obj, headerTransform=pascalToSpace) return_outputs(human_readable, context, status_obj) @@ -665,7 +665,7 @@ def event_quarantine_result_command(): args = demisto.args() operation_id = args.get('operation_id') status_obj = event_quarantine_result(operation_id) - context = {f'Traps.QuarantineResult(val.OperationID == obj.OperationID)': status_obj} + context = {'Traps.QuarantineResult(val.OperationID == obj.OperationID)': status_obj} human_readable = tableToMarkdown(f'Status of quarantine operation: {operation_id}', status_obj, headerTransform=pascalToSpace) return_outputs(human_readable, context, status_obj) @@ -758,7 +758,7 @@ def endpoint_isolate_status_command(): operation_id = args.get('operation_id') isolate_status = endpoint_isolate_status(operation_id) human_readable = f'### Isolate status is: {isolate_status.get("Status")}' - context = {f'Traps.IsolateResult(val.OperationID == obj.OperationID)': isolate_status} + context = {'Traps.IsolateResult(val.OperationID == obj.OperationID)': isolate_status} return_outputs(human_readable, context, isolate_status) diff --git a/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.yml b/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.yml index 4638918c9201..77d8d4506beb 100644 --- a/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.yml +++ b/Packs/Traps/Integrations/PaloAltoNetworks_Traps/PaloAltoNetworks_Traps.yml @@ -380,7 +380,7 @@ script: - contextPath: Traps.ScanResult.Status description: The status of the scan. type: String - dockerimage: demisto/pyjwt3:1.0.0.7727 + dockerimage: demisto/pyjwt3:1.0.0.8871 feed: false isfetch: false longRunning: false diff --git a/Packs/Traps/ReleaseNotes/1_0_1.md b/Packs/Traps/ReleaseNotes/1_0_1.md new file mode 100644 index 000000000000..29e61972bd27 --- /dev/null +++ b/Packs/Traps/ReleaseNotes/1_0_1.md @@ -0,0 +1,5 @@ + diff --git a/Packs/Traps/pack_metadata.json b/Packs/Traps/pack_metadata.json index 5bcaaa4583e7..d754ed877643 100644 --- a/Packs/Traps/pack_metadata.json +++ b/Packs/Traps/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Palo Alto Networks Traps", "description": "Palo Alto Networks Traps pack.", "support": "xsoar", - "currentVersion": "1.0.0", + "currentVersion": "1.0.1", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Zscaler/Integrations/Zscaler/Zscaler_test.py b/Packs/Zscaler/Integrations/Zscaler/Zscaler_test.py index 1c80e509259d..84903dfad285 100644 --- a/Packs/Zscaler/Integrations/Zscaler/Zscaler_test.py +++ b/Packs/Zscaler/Integrations/Zscaler/Zscaler_test.py @@ -134,6 +134,8 @@ def test_get_whitelist(mocker): ('https://madeup.fake.com/css?family=blah:1,2,3', 'false', ['https://madeup.fake.com/css?family=blah:1,2,3']) ] # disable-secrets-detection-end + + @pytest.mark.parametrize('url,multiple,expected_data', test_data) def test_url_multiple_arg(url, multiple, expected_data): '''Scenario: Submit a URL with commas in it diff --git a/Packs/rasterize/Integrations/rasterize/rasterize.py b/Packs/rasterize/Integrations/rasterize/rasterize.py index 936559b90934..1c42f9379e2d 100644 --- a/Packs/rasterize/Integrations/rasterize/rasterize.py +++ b/Packs/rasterize/Integrations/rasterize/rasterize.py @@ -306,17 +306,18 @@ def rasterize_command(): def rasterize_image_command(): - entry_id = demisto.args().get('EntryID') - w = demisto.args().get('width', DEFAULT_W).rstrip('px') - h = demisto.args().get('height', DEFAULT_H).rstrip('px') + args = demisto.args() + entry_id = args.get('EntryID') + w = args.get('width', DEFAULT_W).rstrip('px') + h = args.get('height', DEFAULT_H).rstrip('px') file_path = demisto.getFilePath(entry_id).get('path') - filename = 'image.png' # type: ignore + filename = f'{entry_id}.pdf' with open(file_path, 'rb') as f, open('output_image', 'w') as image: data = base64.b64encode(f.read()).decode('utf-8') image.write(data) - output = rasterize(path=f'file://{os.path.realpath(f.name)}', width=w, height=h) + output = rasterize(path=f'file://{os.path.realpath(f.name)}', width=w, height=h, r_type='pdf') res = fileResult(filename=filename, data=output) res['Type'] = entryTypes['image'] diff --git a/Packs/rasterize/Integrations/rasterize/rasterize.yml b/Packs/rasterize/Integrations/rasterize/rasterize.yml index 4cea313ce575..b95a7392598b 100644 --- a/Packs/rasterize/Integrations/rasterize/rasterize.yml +++ b/Packs/rasterize/Integrations/rasterize/rasterize.yml @@ -174,7 +174,7 @@ script: description: Converts a PDF file to an image file. execution: false name: rasterize-pdf - dockerimage: demisto/chromium:1.0.0.9101 + dockerimage: demisto/chromium:1.0.0.9553 isfetch: false runonce: false script: '' diff --git a/Packs/rasterize/ReleaseNotes/1_0_2.md b/Packs/rasterize/ReleaseNotes/1_0_2.md new file mode 100644 index 000000000000..bb9a50c89b4a --- /dev/null +++ b/Packs/rasterize/ReleaseNotes/1_0_2.md @@ -0,0 +1,4 @@ + +#### Integrations +##### Rasterize + - Fixed an issue where the ***rasterize-image*** command returned an image instead of a pdf file. diff --git a/Packs/rasterize/TestPlaybooks/playbook-RasterizeImageTest.yml b/Packs/rasterize/TestPlaybooks/playbook-RasterizeImageTest.yml index bd86b2467bba..6d17658531c1 100644 --- a/Packs/rasterize/TestPlaybooks/playbook-RasterizeImageTest.yml +++ b/Packs/rasterize/TestPlaybooks/playbook-RasterizeImageTest.yml @@ -6,10 +6,10 @@ starttaskid: "0" tasks: "0": id: "0" - taskid: 68de2c2c-6c0d-4167-83e7-20d0bc09f48a + taskid: 77fb7cb0-2107-46df-8304-23ab3dbd906e type: start task: - id: 68de2c2c-6c0d-4167-83e7-20d0bc09f48a + id: 77fb7cb0-2107-46df-8304-23ab3dbd906e version: -1 name: "" iscommand: false @@ -21,17 +21,21 @@ tasks: view: |- { "position": { - "x": 50, + "x": 265, "y": 50 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 "1": id: "1" - taskid: 250330ca-f4af-42b2-8184-e905b8ec493c + taskid: cb5d4074-31f9-41ca-86a7-2b80e4428c1c type: regular task: - id: 250330ca-f4af-42b2-8184-e905b8ec493c + id: cb5d4074-31f9-41ca-86a7-2b80e4428c1c version: -1 name: Generate File scriptName: GenerateImageFileEntry @@ -45,17 +49,21 @@ tasks: view: |- { "position": { - "x": 50, + "x": 265, "y": 370 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 "2": id: "2" - taskid: 858d11de-d159-4b08-880d-dc93f68bdcd6 + taskid: 6fcb729b-74c5-4f90-822a-39d510cac8a7 type: regular task: - id: 858d11de-d159-4b08-880d-dc93f68bdcd6 + id: 6fcb729b-74c5-4f90-822a-39d510cac8a7 version: -1 name: Clear Context scriptName: DeleteContext @@ -76,17 +84,21 @@ tasks: view: |- { "position": { - "x": 50, + "x": 265, "y": 195 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 "3": id: "3" - taskid: 3df4c118-611d-48bf-8d8d-a49b2c49fe74 + taskid: 79b62c23-aae6-4e01-84e6-5f32da300ac9 type: regular task: - id: 3df4c118-611d-48bf-8d8d-a49b2c49fe74 + id: 79b62c23-aae6-4e01-84e6-5f32da300ac9 version: -1 name: Rasterize script: '|||rasterize-image' @@ -104,78 +116,131 @@ tasks: view: |- { "position": { - "x": 50, - "y": 550 + "x": 265, + "y": 545 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 "4": id: "4" - taskid: 807c3513-5fa8-44b5-8e6e-3272b790c24d + taskid: 085c5eec-b270-4cab-87f3-1cb7709a2d20 type: condition task: - id: 807c3513-5fa8-44b5-8e6e-3272b790c24d + id: 085c5eec-b270-4cab-87f3-1cb7709a2d20 version: -1 name: Check file type: condition iscommand: false brand: "" nexttasks: - "yes": + '#default#': + - "6" + "Yes": - "5" separatecontext: false conditions: - - label: "yes" + - label: "Yes" condition: - - - operator: greaterThan + - - operator: isExists left: value: - simple: InfoFile.Size + complex: + root: InfoFile + filters: + - - operator: greaterThan + left: + value: + simple: InfoFile.Size + iscontext: true + right: + value: + simple: "0" + - - operator: isEqualString + left: + value: + simple: InfoFile.Extension + iscontext: true + right: + value: + simple: pdf + accessor: Size iscontext: true - right: - value: - simple: "0" view: |- { "position": { - "x": 50, + "x": 265, "y": 720 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 "5": id: "5" - taskid: 27764f12-bf79-4f42-85ee-b775ac78439e + taskid: 50de363b-6c3c-4292-83c8-2d578c44cc4f + type: title + task: + id: 50de363b-6c3c-4292-83c8-2d578c44cc4f + version: -1 + name: Succeed + type: title + iscommand: false + brand: Builtin + separatecontext: false + view: |- + { + "position": { + "x": 50, + "y": 910 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + "6": + id: "6" + taskid: a3208c0f-c964-40c7-8d01-a858dea9d402 type: regular task: - id: 27764f12-bf79-4f42-85ee-b775ac78439e + id: a3208c0f-c964-40c7-8d01-a858dea9d402 version: -1 - name: Close - script: Builtin|||closeInvestigation + name: Not PDF - Print error + description: Prints an error entry with a given message + scriptName: PrintErrorEntry type: regular - iscommand: true - brand: Builtin + iscommand: false + brand: "" scriptarguments: - assetid: {} - closeNotes: {} - closeReason: {} - id: {} + message: + simple: Could not validate that the file exists and is pdf. separatecontext: false view: |- { "position": { - "x": 50, + "x": 480, "y": 895 } } note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 view: |- { "linkLabelsPosition": {}, "paper": { "dimensions": { "height": 940, - "width": 380, + "width": 810, "x": 50, "y": 50 } @@ -183,3 +248,4 @@ view: |- } inputs: [] outputs: [] +fromversion: 5.0.0 diff --git a/Packs/rasterize/pack_metadata.json b/Packs/rasterize/pack_metadata.json index f93e9899f6c9..a8b7b5af5835 100644 --- a/Packs/rasterize/pack_metadata.json +++ b/Packs/rasterize/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Rasterize", "description": "Converts URLs, PDF files, and emails to an image file or PDF file.", "support": "xsoar", - "currentVersion": "1.0.1", + "currentVersion": "1.0.2", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Tests/Marketplace/search_and_install_packs.py b/Tests/Marketplace/search_and_install_packs.py index 6fa159f0641f..eeaf5550fa98 100644 --- a/Tests/Marketplace/search_and_install_packs.py +++ b/Tests/Marketplace/search_and_install_packs.py @@ -5,7 +5,7 @@ import json import demisto_client from threading import Thread, Lock -from demisto_sdk.commands.common.tools import print_color, LOG_COLORS, run_threads_list +from demisto_sdk.commands.common.tools import print_color, LOG_COLORS, run_threads_list, print_error from Tests.Marketplace.marketplace_services import PACKS_FULL_PATH, IGNORED_FILES PACK_METADATA_FILE = 'pack_metadata.json' @@ -152,13 +152,14 @@ def search_pack(client, prints_manager, pack_display_name): raise Exception(err_msg) -def install_packs(client, host, prints_manager, packs_to_install, request_timeout=9999999): +def install_packs(client, host, prints_manager, thread_index, packs_to_install, request_timeout=9999999): """ Make a packs installation request. Args: client (demisto_client): The configured client to use. host (str): The server URL. prints_manager (ParallelPrintsManager): Print manager object. + thread_index (int): the thread index. packs_to_install (list): A list of the packs to install. request_timeout (int): Timeout settings for the installation request. """ @@ -170,8 +171,8 @@ def install_packs(client, host, prints_manager, packs_to_install, request_timeou packs_to_install_str = ', '.join([pack['id'] for pack in packs_to_install]) message = 'Installing the following packs in server {}:\n{}'.format(host, packs_to_install_str) - prints_manager.add_print_job(message, print_color, 0, LOG_COLORS.GREEN) - prints_manager.execute_thread_prints(0) + prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) + prints_manager.execute_thread_prints(thread_index) # make the pack installation request try: @@ -184,16 +185,19 @@ def install_packs(client, host, prints_manager, packs_to_install, request_timeou if 200 <= status_code < 300: message = 'Packs were successfully installed!\n' - prints_manager.add_print_job(message, print_color, 0, LOG_COLORS.GREEN) - prints_manager.execute_thread_prints(0) + prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) else: result_object = ast.literal_eval(response_data) message = result_object.get('message', '') - err_msg = 'Failed to install packs - with status code {}\n{}\n'.format(status_code, message) + err_msg = f'Failed to install packs - with status code {status_code}\n{message}\n' + prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) raise Exception(err_msg) except Exception as e: - err_msg = 'The request to install packs has failed. Reason:\n{}\n'.format(str(e)) + err_msg = f'The request to install packs has failed. Reason:\n{str(e)}\n' + prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) raise Exception(err_msg) + finally: + prints_manager.execute_thread_prints(thread_index) def search_pack_and_its_dependencies(client, prints_manager, pack_id, packs_to_install, @@ -241,13 +245,13 @@ def add_pack_to_installation_request(pack_id, installation_request_body): }) -def install_all_content_packs(client, host, prints_manager): +def install_all_content_packs(client, host, prints_manager, thread_index=0): all_packs = [] for pack_id in os.listdir(PACKS_FULL_PATH): if pack_id not in IGNORED_FILES and pack_id != 'Silverfort': # todo: remove silverfort when fixed add_pack_to_installation_request(pack_id, all_packs) - install_packs(client, host, prints_manager, all_packs) + install_packs(client, host, prints_manager, thread_index, all_packs) # todo: remove if not used @@ -291,43 +295,39 @@ def upload_zipped_packs(client, host, prints_manager): raise Exception(err_msg) -def search_and_install_packs_and_their_dependencies(pack_ids, client, prints_manager, is_nightly=False): +def search_and_install_packs_and_their_dependencies(pack_ids, client, prints_manager, thread_index=0): """ Searches for the packs from the specified list, searches their dependencies, and then installs them. Args: pack_ids (list): A list of the pack ids to search and install. client (demisto_client): The client to connect to. prints_manager (ParallelPrintsManager): A prints manager object. - is_nightly (bool): Whether or not the build is a nightly build. + thread_index (int): the thread index. Returns (list): A list of the installed packs' ids, or an empty list if is_nightly == True. """ host = client.api_client.configuration.host - if is_nightly: - install_all_content_packs(client, host, prints_manager) - return [] - else: - msg = 'Starting to search and install packs in server: {}\n'.format(host) - prints_manager.add_print_job(msg, print_color, 0, LOG_COLORS.GREEN) - prints_manager.execute_thread_prints(0) - - packs_to_install = [] # we save all the packs we want to install, to avoid duplications - installation_request_body = [] # the packs to install, in the request format - - threads_list = [] - lock = Lock() - - for pack_id in pack_ids: - thread = Thread(target=search_pack_and_its_dependencies, - kwargs={'client': client, - 'prints_manager': prints_manager, - 'pack_id': pack_id, - 'packs_to_install': packs_to_install, - 'installation_request_body': installation_request_body, - 'lock': lock}) - threads_list.append(thread) - run_threads_list(threads_list) - - install_packs(client, host, prints_manager, installation_request_body) - - return packs_to_install + msg = 'Starting to search and install packs in server: {}\n'.format(host) + prints_manager.add_print_job(msg, print_color, thread_index, LOG_COLORS.GREEN) + prints_manager.execute_thread_prints(thread_index) + + packs_to_install = [] # we save all the packs we want to install, to avoid duplications + installation_request_body = [] # the packs to install, in the request format + + threads_list = [] + lock = Lock() + + for pack_id in pack_ids: + thread = Thread(target=search_pack_and_its_dependencies, + kwargs={'client': client, + 'prints_manager': prints_manager, + 'pack_id': pack_id, + 'packs_to_install': packs_to_install, + 'installation_request_body': installation_request_body, + 'lock': lock}) + threads_list.append(thread) + run_threads_list(threads_list) + + install_packs(client, host, prints_manager, thread_index, installation_request_body) + + return packs_to_install diff --git a/Tests/conf.json b/Tests/conf.json index 2be6f0763ed3..08788c8b653a 100644 --- a/Tests/conf.json +++ b/Tests/conf.json @@ -1602,6 +1602,11 @@ "integrations": "ThreatConnect", "playbookID": "test-ThreatConnect" }, + { + "integrations": "ThreatConnect v2", + "playbookID": "ThreatConnect v2 - Test", + "fromversion": "5.0.0" + }, { "integrations": "VxStream", "playbookID": "VxStream Test", @@ -2330,7 +2335,8 @@ }, { "integrations": "Rasterize", - "playbookID": "RasterizeImageTest" + "playbookID": "RasterizeImageTest", + "fromversion": "5.0.0" }, { "integrations": "Ipstack", @@ -3063,6 +3069,7 @@ "HelloWorldSimple": "This is just an example integration - no need for test", "TestHelloWorldPlaybook": "This is just an example integration - no need for test", "Lockpath KeyLight": "Deprecated. No tests.", + "ThreatConnect": "Deprecated.", "Cymulate": "Partner didn't provided test playbook", "Lastline v2": "Temporary skipping, due to quota issues, in order to merge a PR" }, diff --git a/Tests/configure_and_test_integration_instances.py b/Tests/configure_and_test_integration_instances.py index bf74b637b2d4..ecd7e4192ed1 100644 --- a/Tests/configure_and_test_integration_instances.py +++ b/Tests/configure_and_test_integration_instances.py @@ -21,7 +21,8 @@ from Tests.test_content import load_conf_files, extract_filtered_tests, ParallelPrintsManager, \ get_server_numeric_version from Tests.update_content_data import update_content -from Tests.Marketplace.search_and_install_packs import search_and_install_packs_and_their_dependencies +from Tests.Marketplace.search_and_install_packs import search_and_install_packs_and_their_dependencies, \ + install_all_content_packs MARKET_PLACE_MACHINES = ('master',) @@ -800,17 +801,36 @@ def main(): prints_manager.execute_thread_prints(0) sleep(60) - pack_ids = get_pack_ids_to_install() - # install content packs in every server - for server_url in servers: - try: - client = demisto_client.configure(base_url=server_url, username=username, password=password, - verify_ssl=False) - search_and_install_packs_and_their_dependencies(pack_ids, client, prints_manager, options.is_nightly) - except Exception as exc: - prints_manager.add_print_job(str(exc), print_error, 0) - prints_manager.execute_thread_prints(0) - installed_content_packs_successfully = False + if options.is_nightly: + threads_list = [] + threads_print_manager = ParallelPrintsManager(len(servers)) + # For each server url we install content + for thread_index, server_url in enumerate(servers): + client = demisto_client.configure(base_url=server_url, username=username, + password=password, verify_ssl=False) + t = Thread(target=install_all_content_packs, + kwargs={'client': client, 'host': server_url, + 'prints_manager': threads_print_manager, + 'thread_index': thread_index}) + threads_list.append(t) + run_threads_list(threads_list) + prints_manager.add_print_job('Sleeping for 45 seconds...', print_warning, 0, include_timestamp=True) + prints_manager.execute_thread_prints(0) + sleep(45) + + else: + # install content packs in every server + pack_ids = get_pack_ids_to_install() + for server_url in servers: + try: + client = demisto_client.configure(base_url=server_url, username=username, password=password, + verify_ssl=False) + + search_and_install_packs_and_their_dependencies(pack_ids, client, prints_manager) + except Exception as exc: + prints_manager.add_print_job(str(exc), print_error, 0) + prints_manager.execute_thread_prints(0) + installed_content_packs_successfully = False if new_integrations_files: new_integrations_names = get_integration_names_from_files(new_integrations_files)