diff --git a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed.py b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed.py index 88822582818e..9fe01f630ce3 100644 --- a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed.py +++ b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed.py @@ -105,7 +105,7 @@ def __init__(self, credentials, base_url, include_deleted, type, limit, tlp_colo params = assign_params(credentials=credentials, server_url=base_url, insecure=insecure, - ok_codes=tuple(), + ok_codes=(), proxy=proxy, timeout=timeout) super().__init__(params) @@ -129,6 +129,16 @@ def get_indicators(self, params): ) return response + def get_actors_names_request(self, params_string): + response = self._http_request( + method='GET', + url_suffix=f'intel/entities/actors/v1?{params_string}', + timeout=30 + ) + if 'resources' not in response: + raise DemistoException("Get actors request completed. Parse error: could not find resources in response.") + return response['resources'] + def fetch_indicators(self, limit: int, offset: int = 0, @@ -195,9 +205,11 @@ def fetch_indicators(self, demisto.info(f'set last_run to: {new_last_marker_time}') indicators.extend(self.create_indicators_from_response(response, + self.get_actors_names_request, self.tlp_color, self.feed_tags, - self.create_relationships)) + self.create_relationships, + )) return indicators def handle_first_fetch_context_or_pre_2_1_0(self, filter_string: str) -> tuple[str, list[dict]]: @@ -236,6 +248,7 @@ def handle_first_fetch_context_or_pre_2_1_0(self, filter_string: str) -> tuple[s demisto.debug(f'Importing the indicator marker in first time: {_marker=}') last_run = f"_marker:>'{_marker}'" parse_indicator = self.create_indicators_from_response(response, + self.get_actors_names_request, self.tlp_color, self.feed_tags, self.create_relationships) @@ -264,7 +277,8 @@ def get_last_run() -> str: return params @staticmethod - def create_indicators_from_response(raw_response, tlp_color=None, feed_tags=None, create_relationships=True) -> list: + def create_indicators_from_response(raw_response, get_actors_names_request_func, tlp_color=None, feed_tags=None, + create_relationships=True) -> list: """ Builds indicators from API raw response Args: @@ -308,7 +322,7 @@ def create_indicators_from_response(raw_response, tlp_color=None, feed_tags=None if feed_tags: indicator['fields']['tags'].extend(feed_tags) if create_relationships: - relationships = create_and_add_relationships(indicator, resource) + relationships = create_and_add_relationships(indicator, resource, get_actors_names_request_func) indicator['relationships'] = relationships parsed_indicators.append(indicator) @@ -327,7 +341,7 @@ def build_type_fql(types_list: list) -> str: if 'ALL' in types_list: # Replaces "ALL" for all types supported on XSOAR. - crowdstrike_types = [f"type:'{type}'" for type in CROWDSTRIKE_TO_XSOAR_TYPES.keys()] + crowdstrike_types = [f"type:'{type}'" for type in CROWDSTRIKE_TO_XSOAR_TYPES] else: crowdstrike_types = [f"type:'{XSOAR_TYPES_TO_CROWDSTRIKE.get(type.lower())}'" for type in types_list if type.lower() in XSOAR_TYPES_TO_CROWDSTRIKE] @@ -336,7 +350,7 @@ def build_type_fql(types_list: list) -> str: return result -def create_and_add_relationships(indicator: dict, resource: dict) -> list: +def create_and_add_relationships(indicator: dict, resource: dict, get_actors_names_request_func) -> list: """ Creates and adds relationships to indicators for each CrowdStrike relationships type. @@ -352,12 +366,14 @@ def create_and_add_relationships(indicator: dict, resource: dict) -> list: for field in CROWDSTRIKE_INDICATOR_RELATION_FIELDS: if field in resource and resource[field]: - relationships.extend(create_relationships(field, indicator, resource)) + relationships.extend(create_relationships(field, indicator, resource, get_actors_names_request_func)) return relationships -def create_relationships(field: str, indicator: dict, resource: dict) -> list: +def create_relationships( + field: str, indicator: dict, resource: dict, get_actors_names_request_func +) -> List: """ Creates indicator relationships. @@ -370,6 +386,8 @@ def create_relationships(field: str, indicator: dict, resource: dict) -> list: List of relationships objects. """ relationships = [] + if field == 'actors' and resource['actors']: + resource['actors'] = change_actors_from_id_to_name(resource['actors'], get_actors_names_request_func) for relation in resource[field]: if field == 'relations' and not CROWDSTRIKE_TO_XSOAR_TYPES.get(relation.get('type')): demisto.debug(f"The related indicator type {relation.get('type')} is not supported in XSOAR.") @@ -392,10 +410,30 @@ def create_relationships(field: str, indicator: dict, resource: dict) -> list: ).to_indicator() relationships.append(indicator_relation) - return relationships +def change_actors_from_id_to_name(indicator_actors_array: List[str], get_name_of_actors__func): + integration_context = get_integration_context() + actors_to_convert = [] + converted_actors_array = [] + for actor in indicator_actors_array: + if converted_actor := integration_context.get(actor, None): + converted_actors_array.append(converted_actor) + else: + actors_to_convert.append(actor) + if actors_to_convert: + actor_ids_params = 'ids=' + '&ids='.join(actors_to_convert) + '&fields=name' + actors_response = get_name_of_actors__func(actor_ids_params) + converted_actors_from_request = [] + for actor_dict in actors_response: + converted_actors_from_request.append(actor_dict.get('name')) + zipped_actors_list_to_context = dict(zip(actors_to_convert, converted_actors_from_request)) + update_integration_context(zipped_actors_list_to_context) + converted_actors_array += converted_actors_from_request + return converted_actors_array + + def auto_detect_indicator_type_from_cs(value: str, crowdstrike_resource_type: str) -> str | None: ''' The function determines the type of indicator according to two cases:: diff --git a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed_test.py b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed_test.py index 6909a9dabe28..6cc1222359d2 100644 --- a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed_test.py +++ b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/CrowdStrikeIndicatorFeed_test.py @@ -1,11 +1,10 @@ import json -import io import demistomock as demisto import pytest def util_load_json(path): - with io.open(path, mode='r', encoding='utf-8') as f: + with open(path, encoding='utf-8') as f: return json.loads(f.read()) @@ -27,7 +26,8 @@ def test_crowdstrike_indicators_list_command(requests_mock): mock_response = util_load_json('test_data/crowdstrike_indicators_list_command.json') requests_mock.post('https://api.crowdstrike.com/oauth2/token', json={'access_token': '12345'}) requests_mock.get(url='https://api.crowdstrike.com/intel/combined/indicators/v1', json=mock_response) - + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?ids=GOBLINPANDA&fields=name', + json={'resources': [{'name': 'GOBLIN PANDA'}]}) feed_tags = ['Tag1', 'Tag2'] client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, type='Domain', include_deleted='false', limit=2, feed_tags=feed_tags) @@ -39,7 +39,8 @@ def test_crowdstrike_indicators_list_command(requests_mock): assert len(response.raw_response) == 3 assert "Indicators from CrowdStrike Falcon Intel" in response.readable_output assert "domain_abc" in response.readable_output - assert feed_tags[0] and feed_tags[1] in response.raw_response[0]['fields']['tags'] + assert feed_tags[0] + assert feed_tags[1] in response.raw_response[0]['fields']['tags'] @pytest.mark.parametrize( @@ -66,7 +67,7 @@ def test_build_type_fql(types_list, expected): assert res == expected -def test_create_indicators_from_response(): +def test_create_indicators_from_response(requests_mock, mocker): """Tests build_type_fql function Given - Indicator types that were chosen by the user. @@ -76,10 +77,10 @@ def test_create_indicators_from_response(): - validate result as expected """ from CrowdStrikeIndicatorFeed import Client - + mocker.patch('CrowdStrikeIndicatorFeed.get_integration_context', return_value={'GOBLINPANDA': 'GOBLIN PANDA'}) raw_response = util_load_json('test_data/crowdstrike_indicators_list_command.json') expected_result = util_load_json('test_data/create_indicators_from_response.json') - res = Client.create_indicators_from_response(raw_response) + res = Client.create_indicators_from_response(raw_response, Client.get_actors_names_request) assert res == expected_result @@ -123,8 +124,9 @@ def test_create_relationships_unknown_key(field, indicator, resource, expected_r Then - validate that no Key Error exception was thrown, and that only 1 relationship was created. """ + from CrowdStrikeIndicatorFeed import Client from CrowdStrikeIndicatorFeed import create_relationships - rs_ls = create_relationships(field, indicator, resource) + rs_ls = create_relationships(field, indicator, resource, Client.get_actors_names_request) assert rs_ls == expected_results assert len(rs_ls) == 1 @@ -293,6 +295,8 @@ def test_handling_first_fetch_and_old_integration_context(mocker, client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, type='ALL', include_deleted='false', limit=2, first_fetch=first_fetch) mocker.patch('CrowdStrikeIndicatorFeed.demisto.getIntegrationContext', return_value=integration_context) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?ids=DOPPELSPIDER&fields=name', + json={'resources': [{'name': 'DOPPEL SPIDER'}]}) get_indicator_call = mocker.patch.object(client, 'get_indicators', return_value=get_indicators_response) results = client.handle_first_fetch_context_or_pre_2_1_0(filter) @@ -327,3 +331,101 @@ def test_auto_detect_indicator_type_from_cs(indicator: dict, expected_results: s from CrowdStrikeIndicatorFeed import auto_detect_indicator_type_from_cs assert auto_detect_indicator_type_from_cs(indicator['indicator'], indicator['type']) == expected_results + + +def test_get_actors_names_request_check_output(mocker, requests_mock): + """ + Given + - params for get_actors_names_request http request + When + - calling get_actors_names_request after fetching/listing indicators + Then + - Ensure the result is correct + """ + from CrowdStrikeIndicatorFeed import Client + + mock_response = util_load_json('test_data/crowdstrike_indicators_list_command.json') + requests_mock.post('https://api.crowdstrike.com/oauth2/token', json={'access_token': '12345'}) + requests_mock.get(url='https://api.crowdstrike.com/intel/combined/indicators/v1', json=mock_response) + crowdstrike_client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, + type='Domain', include_deleted='false', limit=2) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?', json={'resources': ''}) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?ids=123&fields=name', + json={'resources': {'name': 'TEST TEST'}}) + res = crowdstrike_client.get_actors_names_request(params_string='ids=123&fields=name') + assert res == {'name': 'TEST TEST'} + + +def test_get_actors_names_request_called_with(mocker, requests_mock): + """ + Given + - params for get_actors_names_request http request + When + - calling get_actors_names_request after fetching/listing indicators + Then + - Ensure the request is called with the right args + """ + from CrowdStrikeIndicatorFeed import Client + mock_response = util_load_json('test_data/crowdstrike_indicators_list_command.json') + requests_mock.post('https://api.crowdstrike.com/oauth2/token', json={'access_token': '12345'}) + requests_mock.get(url='https://api.crowdstrike.com/intel/combined/indicators/v1', json=mock_response) + crowdstrike_client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, + type='Domain', include_deleted='false', limit=2) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?', json={'resources': ''}) + http_request_mock = mocker.patch.object(crowdstrike_client, '_http_request', + return_value={'resources': {'name': 'TEST TEST'}}) + crowdstrike_client.get_actors_names_request(params_string='ids=123&fields=name') + http_request_mock.assert_called_once_with(method='GET', url_suffix='intel/entities/actors/v1?ids=123&fields=name', timeout=30) + + +def test_crowdstrike_indicators_list_command_check_actors_convert(mocker, requests_mock): + """ + Given + - params for crowdstrike_indicators_list_command http request + When + - calling get_actors_names_request after fetching/listing indicators + Then + - Ensure the response is correct + """ + from CrowdStrikeIndicatorFeed import Client, crowdstrike_indicators_list_command + mock_response = util_load_json('test_data/crowdstrike_test_actors_convert.json') + requests_mock.post('https://api.crowdstrike.com/oauth2/token', json={'access_token': '12345'}) + requests_mock.get(url='https://api.crowdstrike.com/intel/combined/indicators/v1', json=mock_response) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?ids=TESTTEST&fields=name', + json={'resources': [{'name': 'TEST TEST'}]}) + mocker.patch('CrowdStrikeIndicatorFeed.get_integration_context', return_value={}) + mocker.patch('CrowdStrikeIndicatorFeed.update_integration_context') + feed_tags = ['Tag1', 'Tag2'] + crowdstrike_client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, + type='Domain', include_deleted='false', limit=2, feed_tags=feed_tags) + args = { + 'limit': '2' + } + response = crowdstrike_indicators_list_command(crowdstrike_client, args) + assert len(response.outputs) == 1 + assert len(response.raw_response) == 1 + assert len(response.raw_response[0].get('relationships', None)) == 2 + assert response.raw_response[0].get('relationships', None)[1].get('entityB', None) == 'TEST TEST' + + +def test_change_actors_from_id_to_name(mocker, requests_mock): + """ + Given + - params for change_actors_from_id_to_name http request + When + - calling get_actors_names_request after fetching/listing indicators + Then + - Ensure the response is correct + """ + from CrowdStrikeIndicatorFeed import Client, change_actors_from_id_to_name + requests_mock.post('https://api.crowdstrike.com/oauth2/token', json={'access_token': '12345'}) + crowdstrike_client = Client(base_url='https://api.crowdstrike.com/', credentials={'identifier': '123', 'password': '123'}, + type='Domain', include_deleted='false', limit=2) + actors_unparsed_array = ['TEST', 'TEST1', 'TEST2'] + mocker.patch('CrowdStrikeIndicatorFeed.get_integration_context', return_value={'TEST': 'WAS IN CONTEXT'}) + requests_mock.get(url='https://api.crowdstrike.com/intel/entities/actors/v1?ids=TEST1&ids=TEST2&fields=name', + json={'resources': [{'name': 'Changedtest1'}, {'name': 'Changedtest2'}]}) + result = change_actors_from_id_to_name(actors_unparsed_array, crowdstrike_client.get_actors_names_request) + assert result[0] == "WAS IN CONTEXT" + assert result[1] == "Changedtest1" + assert result[2] == "Changedtest2" diff --git a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/create_indicators_from_response.json b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/create_indicators_from_response.json index 517234fcff65..3f2385bcfe04 100644 --- a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/create_indicators_from_response.json +++ b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/create_indicators_from_response.json @@ -1,321 +1,237 @@ [ - { - "fields": { - "actor": [ - "GOBLINPANDA" - ], - "confidence": "medium", - "creationdate": 1532708005, - "domainname": [], - "ipaddress": [], - "malwarefamily": [], - "reports": [ - "CSA-123" - ], - "stixkillchainphases": [], - "tags": [ - "MaliciousConfidence/Medium", - "Actor/GOBLINPANDA" - ], - "targets": [], - "threattypes": [ - { - "threatcategory": "Suspicious" - }, - { - "threatcategory": "Targeted" - } - ], - "updateddate": 1612244501, - "vulnerabilities": [] - }, - "rawJSON": { - "_marker": "123", - "actors": [ - "GOBLINPANDA" - ], - "deleted": false, - "domain_types": [], - "id": "domain_abc", - "indicator": "abc", - "ip_address_types": [], - "kill_chains": [], - "labels": [ - { - "created_on": 1532708005, - "last_valid_on": 1612244501, - "name": "MaliciousConfidence/Medium" - }, - { - "created_on": 1532708004, - "last_valid_on": 1588311187, - "name": "Actor/GOBLINPANDA" - } - ], - "last_updated": 1612244501, - "malicious_confidence": "medium", - "malware_families": [], - "published_date": 1532708005, - "relations": [ - { - "created_date": 1532712929, - "id": "ip_address_1.1.1.1", - "indicator": "1.1.1.1", - "last_valid_date": 1532712929, - "type": "ip_address" - } - ], - "reports": [ - "CSA-123" - ], - "targets": [], - "threat_types": [ - "Suspicious", - "Targeted" - ], - "type": "domain", - "vulnerabilities": [] - }, - "type": "Domain", + {"type": "Domain", "value": "abc", - "relationships": [ - { - "entityA": "abc", - "entityAFamily": "Indicator", - "entityAType": "Domain", - "entityB": "CSA-123", - "entityBFamily": "Indicator", - "entityBType": "Report", - "fields": {}, - "name": "indicator-of", - "reverseName": "indicated-by", - "type": "IndicatorToIndicator" - }, - { - "entityA": "abc", - "entityAFamily": "Indicator", - "entityAType": "Domain", - "entityB": "GOBLINPANDA", - "entityBFamily": "Indicator", - "entityBType": "Threat Actor", - "fields": {}, - "name": "indicator-of", - "reverseName": "indicated-by", - "type": "IndicatorToIndicator" - }, - { - "entityA": "abc", - "entityAFamily": "Indicator", - "entityAType": "Domain", - "entityB": "1.1.1.1", - "entityBFamily": "Indicator", - "entityBType": "IP", - "fields": {}, - "name": "related-to", - "reverseName": "related-to", - "type": "IndicatorToIndicator" - } - ] - }, - { - "fields": { - "actor": [], - "confidence": "high", - "creationdate": 1573579421, - "domainname": [], - "ipaddress": [], - "malwarefamily": [ - "Gootkit" - ], - "reports": [], - "stixkillchainphases": [ - "Command & Control", - "Delivery" - ], - "tags": [ - "Malware/Gootkit" - ], - "targets": [], - "threattypes": [ - { - "threatcategory": "Criminal" - }, - { - "threatcategory": "Banking" - } - ], - "updateddate": 1612070569, - "vulnerabilities": [] - }, "rawJSON": { - "_marker": "1234", - "actors": [], - "deleted": false, - "domain_types": [], - "id": "domain_abc1", - "indicator": "abc1", - "ip_address_types": [], - "kill_chains": [ - "C2", "delivery" - ], - "labels": [ - { - "created_on": 1588309967, - "last_valid_on": 1588309967, - "name": "Malware/Gootkit" - } - ], - "last_updated": 1612070569, - "malicious_confidence": "high", - "malware_families": [ - "Gootkit" - ], - "published_date": 1573579421, - "relations": [ - { - "created_date": 1609238446, - "id": "hash_sha256_1234567890", - "indicator": "1234567890", - "last_valid_date": 1609238446, - "type": "hash_sha256" - } - ], - "reports": [], - "targets": [], - "threat_types": [ - "Criminal", - "Banking" - ], - "type": "domain", - "vulnerabilities": [] + "id": "domain_abc", + "indicator": "abc", + "type": "domain", + "deleted": false, + "published_date": 1532708005, + "last_updated": 1612244501, + "reports": ["CSA-123"], + "actors": ["GOBLIN PANDA"], + "malware_families": [], + "kill_chains": [], + "ip_address_types": [], + "domain_types": [], + "malicious_confidence": "medium", + "_marker": "123", + "labels": + [{"name": "MaliciousConfidence/Medium", "created_on": 1532708005, "last_valid_on": 1612244501}, + {"name": "Actor/GOBLINPANDA", "created_on": 1532708004, "last_valid_on": 1588311187}], + "relations": + [{"id": "ip_address_1.1.1.1", "indicator": "1.1.1.1", "type": "ip_address", "created_date": 1532712929, "last_valid_date": 1532712929}], + "targets": [], + "threat_types": ["Suspicious", "Targeted"], + "vulnerabilities": []}, + "fields": + {"actor": ["GOBLINPANDA"], + "reports": ["CSA-123"], + "malwarefamily": [], + "stixkillchainphases": [], + "ipaddress": [], + "domainname": [], + "targets": [], + "threattypes": + [{"threatcategory": "Suspicious"}, + {"threatcategory": "Targeted"}], + "vulnerabilities": [], + "confidence": "medium", + "updateddate": 1612244501, + "creationdate": 1532708005, + "tags": ["MaliciousConfidence/Medium", "Actor/GOBLINPANDA"]}, + "relationships": [ + {"name": "indicator-of", + "reverseName": "indicated-by", + "type": "IndicatorToIndicator", + "entityA": "abc", + "entityAFamily": "Indicator", + "entityAType": "Domain", + "entityB": "CSA-123", + "entityBFamily": "Indicator", + "entityBType": "Report", + "fields": {}}, + {"name": "indicator-of", + "reverseName": "indicated-by", + "type": "IndicatorToIndicator", + "entityA": "abc", + "entityAFamily": "Indicator", + "entityAType": "Domain", + "entityB": "GOBLIN PANDA", + "entityBFamily": "Indicator", + "entityBType": "Threat Actor", + "fields": {}}, + {"name": "related-to", + "reverseName": "related-to", + "type": "IndicatorToIndicator", + "entityA": "abc", + "entityAFamily": "Indicator", + "entityAType": "Domain", + "entityB": "1.1.1.1", + "entityBFamily": "Indicator", + "entityBType": "IP", + "fields": {}}]}, + { + "type": "Domain", + "value": "abc1", + "rawJSON": { + "id": "domain_abc1", + "indicator": "abc1", + "type": "domain", + "deleted": false, + "published_date": 1573579421, + "last_updated": 1612070569, + "reports": [], + "actors": [], + "malware_families": ["Gootkit"], + "kill_chains": ["C2", "delivery"], + "ip_address_types": [], + "domain_types": [], + "malicious_confidence": "high", + "_marker": "1234", + "labels": [ + { + "name": "Malware/Gootkit", + "created_on": 1588309967, + "last_valid_on": 1588309967 + } + ], + "relations": [ + { + "id": "hash_sha256_1234567890", + "indicator": "1234567890", + "type": "hash_sha256", + "created_date": 1609238446, + "last_valid_date": 1609238446}], + "targets": [], + "threat_types": ["Criminal", "Banking"], + "vulnerabilities": [] + }, + "fields": + {"actor": [], + "reports": [], + "malwarefamily": ["Gootkit"], + "stixkillchainphases": ["Command & Control", "Delivery"], + "ipaddress": [], + "domainname": [], + "targets": [], + "threattypes": [ + {"threatcategory": "Criminal"}, + {"threatcategory": "Banking"} + ], "vulnerabilities": [], + "confidence": "high", + "updateddate": 1612070569, + "creationdate": 1573579421, + "tags": ["Malware/Gootkit"]}, + "relationships": [ + { + "name": "indicator-of", + "reverseName": "indicated-by", + "type": "IndicatorToIndicator", + "entityA": "abc1", + "entityAFamily": "Indicator", + "entityAType": "Domain", + "entityB": "Gootkit", + "entityBFamily": "Indicator", + "entityBType": "Malware", "fields": {} + }, + { + "name": "related-to", + "reverseName": "related-to", + "type": "IndicatorToIndicator", + "entityA": "abc1", + "entityAFamily": "Indicator", + "entityAType": "Domain", + "entityB": "1234567890", + "entityBFamily": "Indicator", + "entityBType": "File", "fields": {} + } + ] }, - "type": "Domain", - "value": "abc1", - "relationships": [ - { - "entityA": "abc1", - "entityAFamily": "Indicator", - "entityAType": "Domain", - "entityB": "Gootkit", - "entityBFamily": "Indicator", - "entityBType": "Malware", - "fields": {}, - "name": "indicator-of", - "reverseName": "indicated-by", - "type": "IndicatorToIndicator" - }, - { - "entityA": "abc1", - "entityAFamily": "Indicator", - "entityAType": "Domain", - "entityB": "1234567890", - "entityBFamily": "Indicator", - "entityBType": "File", - "fields": {}, - "name": "related-to", - "reverseName": "related-to", - "type": "IndicatorToIndicator" - } - ] - }, - { - "fields": { - "actor": [], - "confidence": "high", - "creationdate": 1573579421, - "domainname": [], - "ipaddress": [], - "malwarefamily": [ - "Gootkit" - ], - "reports": [], - "stixkillchainphases": [ - "Command & Control" - ], - "tags": [ - "Malware/Gootkit" - ], - "targets": [], - "threattypes": [ - { - "threatcategory": "Criminal" + { + "type": "File", + "value": "abc1", + "rawJSON": { + "id": "file_abc1", + "indicator": "abc1", + "type": "hash_md5", + "deleted": false, + "published_date": 1573579421, + "last_updated": 1612070569, + "reports": [], + "actors": [], + "malware_families": ["Gootkit"], + "kill_chains": ["C2"], + "ip_address_types": [], + "domain_types": [], + "malicious_confidence": "high", + "_marker": "1234", + "labels": [ + { + "name": "Malware/Gootkit", + "created_on": 1588309967, + "last_valid_on": 1588309967 + } + ], + "relations": [ + { + "id": "hash_sha256_1234567890", + "indicator": "1234567890", + "type": "hash_sha256", + "created_date": 1609238446, + "last_valid_date": 1609238446 + } + ], + "targets": [], + "threat_types": ["Criminal", "Banking"], + "vulnerabilities": [] }, - { - "threatcategory": "Banking" + "fields": { + "actor": [], + "reports": [], + "malwarefamily": ["Gootkit"], + "stixkillchainphases": ["Command & Control"], + "ipaddress": [], + "domainname": [], + "targets": [], + "threattypes": [ + { + "threatcategory": "Criminal" + }, + { + "threatcategory": "Banking" + } + ], + "vulnerabilities": [], + "confidence": "high", + "updateddate": 1612070569, + "creationdate": 1573579421, + "tags": ["Malware/Gootkit"]}, + "relationships": [ + { + "name": "indicator-of", + "reverseName": "indicated-by", + "type": "IndicatorToIndicator", + "entityA": "abc1", + "entityAFamily": "Indicator", + "entityAType": "File", + "entityB": "Gootkit", + "entityBFamily": "Indicator", + "entityBType": "Malware", + "fields": {} + }, + { + "name": "related-to", + "reverseName": "related-to", + "type": "IndicatorToIndicator", + "entityA": "abc1", + "entityAFamily": "Indicator", + "entityAType": "File", + "entityB": "1234567890", + "entityBFamily": "Indicator", + "entityBType": "File", + "fields": {} + } + ] } - ], - "updateddate": 1612070569, - "vulnerabilities": [] - }, - "rawJSON": { - "_marker": "1234", - "actors": [], - "deleted": false, - "domain_types": [], - "id": "file_abc1", - "indicator": "abc1", - "ip_address_types": [], - "kill_chains": [ - "C2" - ], - "labels": [ - { - "created_on": 1588309967, - "last_valid_on": 1588309967, - "name": "Malware/Gootkit" - } - ], - "last_updated": 1612070569, - "malicious_confidence": "high", - "malware_families": [ - "Gootkit" - ], - "published_date": 1573579421, - "relations": [ - { - "created_date": 1609238446, - "id": "hash_sha256_1234567890", - "indicator": "1234567890", - "last_valid_date": 1609238446, - "type": "hash_sha256" - } - ], - "reports": [], - "targets": [], - "threat_types": [ - "Criminal", - "Banking" - ], - "type": "hash_md5", - "vulnerabilities": [] - }, - "type": "File", - "value": "abc1", - "relationships": [ - { - "entityA": "abc1", - "entityAFamily": "Indicator", - "entityAType": "File", - "entityB": "Gootkit", - "entityBFamily": "Indicator", - "entityBType": "Malware", - "fields": {}, - "name": "indicator-of", - "reverseName": "indicated-by", - "type": "IndicatorToIndicator" - }, - { - "entityA": "abc1", - "entityAFamily": "Indicator", - "entityAType": "File", - "entityB": "1234567890", - "entityBFamily": "Indicator", - "entityBType": "File", - "fields": {}, - "name": "related-to", - "reverseName": "related-to", - "type": "IndicatorToIndicator" - } - ] - } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/crowdstrike_test_actors_convert.json b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/crowdstrike_test_actors_convert.json new file mode 100644 index 000000000000..7555e4242146 --- /dev/null +++ b/Packs/FeedCrowdstrikeFalconIntel/Integrations/CrowdStrikeIndicatorFeed/test_data/crowdstrike_test_actors_convert.json @@ -0,0 +1,54 @@ +{ + "meta": { + "query_time": 1.5230555030000001, + "pagination": { + "offset": 0, + "limit": 1, + "total": 11 + }, + "powered_by": "msa-api", + "trace_id": "b18f911b-f0a0-471d-9a0e-2eab8f651591" + }, + "resources": [ + { + "id": "domain_abc", + "indicator": "abc", + "type": "domain", + "deleted": false, + "published_date": 1532708005, + "last_updated": 1612244501, + "reports": [ + "CSA-123" + ], + "actors": [ + "TESTTEST" + ], + "malware_families": [], + "kill_chains": [], + "ip_address_types": [], + "domain_types": [], + "malicious_confidence": "medium", + "_marker": "123", + "labels": [ + { + "name": "MaliciousConfidence/Medium", + "created_on": 1532708005, + "last_valid_on": 1612244501 + }, + { + "name": "Actor/GOBLINPANDA", + "created_on": 1532708004, + "last_valid_on": 1588311187 + } + ], + "relations": [], + "targets": [], + "threat_types": [ + "Suspicious", + "Targeted" + ], + "vulnerabilities": [] + } + ], + "errors": [] +} \ No newline at end of file diff --git a/Packs/FeedCrowdstrikeFalconIntel/ReleaseNotes/2_1_16.md b/Packs/FeedCrowdstrikeFalconIntel/ReleaseNotes/2_1_16.md new file mode 100644 index 000000000000..c47b49f6a41f --- /dev/null +++ b/Packs/FeedCrowdstrikeFalconIntel/ReleaseNotes/2_1_16.md @@ -0,0 +1,5 @@ +#### Integrations + +##### CrowdStrike Indicator Feed + + - Fixed an issue with the threat actor names coming back with nospaces causing XSOAR to create incorrect relationships. diff --git a/Packs/FeedCrowdstrikeFalconIntel/pack_metadata.json b/Packs/FeedCrowdstrikeFalconIntel/pack_metadata.json index e55ed31625fe..1d6c7b1e8f81 100644 --- a/Packs/FeedCrowdstrikeFalconIntel/pack_metadata.json +++ b/Packs/FeedCrowdstrikeFalconIntel/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Crowdstrike Falcon Intel Feed", "description": "Tracks the activities of threat actor groups and advanced persistent threats (APTs) to understand as much as possible about their known aliases, targets, methods, and more.", "support": "xsoar", - "currentVersion": "2.1.15", + "currentVersion": "2.1.16", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "",