From 8a3d222e0072dff6d12ce4fd0987d6d4c6fecabf Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Mon, 22 Jun 2020 17:20:05 +0000 Subject: [PATCH 1/8] Handle outside td --- Packs/Code42/Integrations/Code42/Code42.py | 8 +- .../Code42/Integrations/Code42/Code42_test.py | 259 ++++++++++++------ .../Code42/integration-Code42.yml | 8 +- 3 files changed, 193 insertions(+), 82 deletions(-) diff --git a/Packs/Code42/Integrations/Code42/Code42.py b/Packs/Code42/Integrations/Code42/Code42.py index 8d83633fe331..e9aaae8fdaf2 100644 --- a/Packs/Code42/Integrations/Code42/Code42.py +++ b/Packs/Code42/Integrations/Code42/Code42.py @@ -338,10 +338,14 @@ def _create_category_filter(file_type): class ObservationToSecurityQueryMapper(object): """Class to simplify the process of mapping observation data to query objects.""" + # Exfiltration consts _ENDPOINT_TYPE = "FedEndpointExfiltration" _CLOUD_TYPE = "FedCloudSharePermissions" + + # Query consts _PUBLIC_SEARCHABLE = "PublicSearchableShare" _PUBLIC_LINK = "PublicLinkShare" + _OUTSIDE_TRUSTED_DOMAINS = "SharedOutsideTrustedDomain" def __init__(self, observation, actor): self._obs = observation @@ -399,10 +403,12 @@ def _create_exposure_filters(self, exposure_types): exp_types.append(ExposureType.IS_PUBLIC) if self._PUBLIC_LINK in exposure_types: exp_types.append(ExposureType.SHARED_VIA_LINK) + if self._OUTSIDE_TRUSTED_DOMAINS in exposure_types: + exp_types.append("OutsideTrustedDomains") return [ExposureType.is_in(exp_types)] elif self._is_endpoint_exfiltration: return [ - EventType.is_in(["CREATED", "MODIFIED", "READ_BY_APP"]), + EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), ExposureType.is_in(exposure_types), ] return [] diff --git a/Packs/Code42/Integrations/Code42/Code42_test.py b/Packs/Code42/Integrations/Code42/Code42_test.py index e2d7dba7ce58..33db9382873d 100644 --- a/Packs/Code42/Integrations/Code42/Code42_test.py +++ b/Packs/Code42/Integrations/Code42/Code42_test.py @@ -395,79 +395,137 @@ }""" MOCK_ALERT_DETAILS_RESPONSE = """{ - "type$": "ALERT_DETAILS_RESPONSE", - "alerts": [ - {"type$": "ALERT_DETAILS", - "tenantId": "1d71796f-af5b-4231-9d8e-df6434da4663", - "type": "FED_ENDPOINT_EXFILTRATION", - "name": "Departing Employee Alert", - "description": "Cortex XSOAR is cool.", - "actor": "user1@example.com", - "actorId": "912098363086307495", - "target": "N/A", - "severity": "HIGH", - "ruleId": "4576576e-13cb-4f88-be3a-ee77739de649", - "ruleSource": "Alerting", - "id": "36fb8ca5-0533-4d25-9763-e09d35d60610", - "createdAt": "2019-10-02T17:02:23.5867670Z", - "state": "OPEN", - "observations": [ - { - "type$": "OBSERVATION", - "id": "240526fc-3a32-4755-85ab-c6ee6e7f31ce", - "observedAt": "2020-05-28T12:50:00.0000000Z", - "type": "FedEndpointExfiltration", - "data": { - "type$": "OBSERVED_ENDPOINT_ACTIVITY", - "id": "240526fc-3a32-4755-85ab-c6ee6e7f31ce", - "sources": ["Endpoint"], - "exposureTypes": ["ApplicationRead"], - "firstActivityAt": "2020-05-28T12:50:00.0000000Z", - "lastActivityAt": "2020-05-28T12:50:00.0000000Z", - "fileCount": 3, - "totalFileSize": 533846, - "fileCategories": [ - { - "type$": "OBSERVED_FILE_CATEGORY", - "category": "Image", - "fileCount": 3, - "totalFileSize": 533846, - "isSignificant": true - } - ], - "files": [ - { - "type$": "OBSERVED_FILE", - "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_5", - "path": "C:/Users/QA/Downloads/", - "name": "Customers.jpg", - "category": "Image", - "size": 265122 - }, - { - "type$": "OBSERVED_FILE", - "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_6", - "path": "C:/Users/QA/Downloads/", - "name": "data.png", - "category": "Image", - "size": 129129 - }, - { - "type$": "OBSERVED_FILE", - "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_7", - "path": "C:/Users/QA/Downloads/", - "name": "company_secrets.ps", - "category": "Image", - "size": 139595 - } - ], - "syncToServices": [], - "sendingIpAddresses": ["127.0.0.1"] - } - } + "type$": "ALERT_DETAILS_RESPONSE", + "alerts": [ + { + "type$": "ALERT_DETAILS", + "tenantId": "1d71796f-af5b-4231-9d8e-df6434da4663", + "type": "FED_ENDPOINT_EXFILTRATION", + "name": "Departing Employee Alert", + "description": "Cortex XSOAR is cool.", + "actor": "user1@example.com", + "actorId": "912098363086307495", + "target": "N/A", + "severity": "HIGH", + "ruleId": "4576576e-13cb-4f88-be3a-ee77739de649", + "ruleSource": "Alerting", + "id": "36fb8ca5-0533-4d25-9763-e09d35d60610", + "createdAt": "2019-10-02T17:02:23.5867670Z", + "state": "OPEN", + "observations": [ + { + "type$": "OBSERVATION", + "id": "240526fc-3a32-4755-85ab-c6ee6e7f31ce", + "observedAt": "2020-05-28T12:50:00.0000000Z", + "type": "FedEndpointExfiltration", + "data": { + "type$": "OBSERVED_ENDPOINT_ACTIVITY", + "id": "240526fc-3a32-4755-85ab-c6ee6e7f31ce", + "sources": [ + "Endpoint" + ], + "exposureTypes": [ + "ApplicationRead" + ], + "firstActivityAt": "2020-05-28T12:50:00.0000000Z", + "lastActivityAt": "2020-05-28T12:50:00.0000000Z", + "fileCount": 3, + "totalFileSize": 533846, + "fileCategories": [ + { + "type$": "OBSERVED_FILE_CATEGORY", + "category": "Image", + "fileCount": 3, + "totalFileSize": 533846, + "isSignificant": true + } + ], + "files": [ + { + "type$": "OBSERVED_FILE", + "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_5", + "path": "C:/Users/QA/Downloads/", + "name": "Customers.jpg", + "category": "Image", + "size": 265122 + }, + { + "type$": "OBSERVED_FILE", + "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_6", + "path": "C:/Users/QA/Downloads/", + "name": "data.png", + "category": "Image", + "size": 129129 + }, + { + "type$": "OBSERVED_FILE", + "eventId": "0_1d71796f-af5b-4231-9d8e-df6434da4663_935873453596901068_956171635867906205_7", + "path": "C:/Users/QA/Downloads/", + "name": "company_secrets.ps", + "category": "Image", + "size": 139595 + } + ], + "syncToServices": [], + "sendingIpAddresses": [ + "127.0.0.1" ] + } + }, + { + "type$": "OBSERVATION", + "id": "7f4d125d-c7ca-4264-83fe-fa442bf270b6", + "observedAt": "2020-06-11T20:20:00.0000000Z", + "type": "FedCloudSharePermissions", + "data": { + "type$": "OBSERVED_CLOUD_SHARE_ACTIVITY", + "id": "7f4d125d-c7ca-4264-83fe-fa442bf270b6", + "sources": [ + "GoogleDrive" + ], + "exposureTypes": [ + "SharedOutsideTrustedDomain" + ], + "firstActivityAt": "2020-06-11T20:20:00.0000000Z", + "lastActivityAt": "2020-06-11T20:25:00.0000000Z", + "fileCount": 1, + "totalFileSize": 182554405, + "fileCategories": [ + { + "type$": "OBSERVED_FILE_CATEGORY", + "category": "Archive", + "fileCount": 1, + "totalFileSize": 182554405, + "isSignificant": false + } + ], + "files": [ + { + "type$": "OBSERVED_FILE", + "eventId": "14FnN9-YOhVUO_Tv8Mu-hEgevc2K4l07l_5_9e633ffd-9329-4cf4-8645-27a23b83ebc0", + "name": "Code42CrashPlan_8.0.0_1525200006800_778_Mac.dmg", + "category": "Archive", + "size": 182554405 + } + ], + "outsideTrustedDomainsEmails": [ + "user1@example.com" + ], + "outsideTrustedDomainsEmailsCount": 1, + "outsideTrustedDomainsCounts": [ + { + "type$": "OBSERVED_DOMAIN_INFO", + "domain": "gmail.com", + "count": 1 + } + ], + "outsideTrustedDomainsTotalDomainCount": 1, + "outsideTrustedDomainsTotalDomainCountTruncated": false + } } - ] + ] + } + ] }""" MOCK_CODE42_ALERT_CONTEXT = [ @@ -585,6 +643,46 @@ "srtDir": "asc", "srtKey": "eventId", }, + { + "groupClause": "AND", + "groups": [ + { + "filterClause": "AND", + "filters": [{"operator": "IS", "term": "actor", "value": "user1@example.com"}], + }, + { + "filterClause": "AND", + "filters": [ + { + "operator": "ON_OR_AFTER", + "term": "eventTimestamp", + "value": "2020-06-11T20:20:00.000Z", + } + ], + }, + { + "filterClause": "AND", + "filters": [ + { + "operator": "ON_OR_BEFORE", + "term": "eventTimestamp", + "value": "2020-06-11T20:25:00.000Z", + } + ], + }, + { + "filterClause": "AND", + "filters": [ + {"operator": "IS", "term": "exposure", "value": "OutsideTrustedDomains"} + ], + }, + {"filterClause": "AND", "filters": []}, + ], + "pgNum": 1, + "pgSize": 10000, + "srtDir": "asc", + "srtKey": "eventId", + }, { "groupClause": "AND", "groups": [ @@ -926,7 +1024,9 @@ def get_empty_detectionlist_response(mocker, base_text): def test_client_when_no_alert_found_raises_exception(code42_sdk_mock): - code42_sdk_mock.alerts.get_details.return_value = """{'type$': 'ALERT_DETAILS_RESPONSE', 'alerts': []}""" + code42_sdk_mock.alerts.get_details.return_value = ( + """{'type$': 'ALERT_DETAILS_RESPONSE', 'alerts': []}""" + ) client = create_client(code42_sdk_mock) with pytest.raises(Exception): client.get_alert_details("mock-id") @@ -948,14 +1048,13 @@ def test_build_query_payload(): def test_map_observation_to_security_query(): response = json.loads(MOCK_ALERT_DETAILS_RESPONSE) - alerts = response["alerts"] - for i in range(0, len(alerts)): - observation = alerts[i]["observations"][0] - actor = alerts[i]["actor"] - query = map_observation_to_security_query(observation, actor) - assert query.sort_key == MOCK_OBSERVATION_QUERIES[i]["srtKey"] - assert query.page_number == MOCK_OBSERVATION_QUERIES[i]["pgNum"] - assert json.loads(str(query)) == MOCK_OBSERVATION_QUERIES[i] + alert = response["alerts"][0] + actor = alert["actor"] + observations = alert["observations"] + first_actual = json.loads(str(map_observation_to_security_query(observations[0], actor))) + second_actual = json.loads(str(map_observation_to_security_query(observations[1], actor))) + assert first_actual == MOCK_OBSERVATION_QUERIES[0] + assert second_actual == MOCK_OBSERVATION_QUERIES[1] def test_map_to_code42_event_context(): diff --git a/Packs/Code42/Integrations/Code42/integration-Code42.yml b/Packs/Code42/Integrations/Code42/integration-Code42.yml index 1bf98b61977e..947f67dfea7c 100644 --- a/Packs/Code42/Integrations/Code42/integration-Code42.yml +++ b/Packs/Code42/Integrations/Code42/integration-Code42.yml @@ -410,10 +410,14 @@ script: class ObservationToSecurityQueryMapper(object): """Class to simplify the process of mapping observation data to query objects.""" + # Exfiltration consts _ENDPOINT_TYPE = "FedEndpointExfiltration" _CLOUD_TYPE = "FedCloudSharePermissions" + + # Query consts _PUBLIC_SEARCHABLE = "PublicSearchableShare" _PUBLIC_LINK = "PublicLinkShare" + _OUTSIDE_TRUSTED_DOMAINS = "SharedOutsideTrustedDomain" def __init__(self, observation, actor): self._obs = observation @@ -471,10 +475,12 @@ script: exp_types.append(ExposureType.IS_PUBLIC) if self._PUBLIC_LINK in exposure_types: exp_types.append(ExposureType.SHARED_VIA_LINK) + if self._OUTSIDE_TRUSTED_DOMAINS in exposure_types: + exp_types.append("OutsideTrustedDomains") return [ExposureType.is_in(exp_types)] elif self._is_endpoint_exfiltration: return [ - EventType.is_in(["CREATED", "MODIFIED", "READ_BY_APP"]), + EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), ExposureType.is_in(exposure_types), ] return [] From 02798674b6a40d4b621f260513a471b1d017aa4b Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 23 Jun 2020 16:20:48 +0000 Subject: [PATCH 2/8] To prove that it wont bomb on unsupported types --- .../Code42/Integrations/Code42/Code42_test.py | 76 +++++++++++++++---- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/Packs/Code42/Integrations/Code42/Code42_test.py b/Packs/Code42/Integrations/Code42/Code42_test.py index 33db9382873d..d8c85dfdc5aa 100644 --- a/Packs/Code42/Integrations/Code42/Code42_test.py +++ b/Packs/Code42/Integrations/Code42/Code42_test.py @@ -522,6 +522,57 @@ "outsideTrustedDomainsTotalDomainCount": 1, "outsideTrustedDomainsTotalDomainCountTruncated": false } + }, + { + "type$": "OBSERVATION", + "id": "7f4d125d-c7ca-4264-83fe-fa442bf270b6", + "observedAt": "2020-06-11T20:20:00.0000000Z", + "type": "FedCloudSharePermissions", + "data": { + "type$": "OBSERVED_CLOUD_SHARE_ACTIVITY", + "id": "7f4d125d-c7ca-4264-83fe-fa442bf270b6", + "sources": [ + "GoogleDrive" + ], + "exposureTypes": [ + "UnknownExposureTypeThatWeDontSupportYet" + ], + "firstActivityAt": "2020-06-11T20:20:00.0000000Z", + "lastActivityAt": "2020-06-11T20:25:00.0000000Z", + "fileCount": 1, + "totalFileSize": 182554405, + "fileCategories": [ + { + "type$": "OBSERVED_FILE_CATEGORY", + "category": "Archive", + "fileCount": 1, + "totalFileSize": 182554405, + "isSignificant": false + } + ], + "files": [ + { + "type$": "OBSERVED_FILE", + "eventId": "14FnN9-YOhVUO_Tv8Mu-hEgevc2K4l07l_5_9e633ffd-9329-4cf4-8645-27a23b83ebc0", + "name": "Code42CrashPlan_8.0.0_1525200006800_778_Mac.dmg", + "category": "Archive", + "size": 182554405 + } + ], + "outsideTrustedDomainsEmails": [ + "user1@example.com" + ], + "outsideTrustedDomainsEmailsCount": 1, + "outsideTrustedDomainsCounts": [ + { + "type$": "OBSERVED_DOMAIN_INFO", + "domain": "gmail.com", + "count": 1 + } + ], + "outsideTrustedDomainsTotalDomainCount": 1, + "outsideTrustedDomainsTotalDomainCountTruncated": false + } } ] } @@ -688,7 +739,7 @@ "groups": [ { "filterClause": "AND", - "filters": [{"operator": "IS", "term": "actor", "value": "user2@example.com"}], + "filters": [{"operator": "IS", "term": "actor", "value": "user1@example.com"}], }, { "filterClause": "AND", @@ -696,7 +747,7 @@ { "operator": "ON_OR_AFTER", "term": "eventTimestamp", - "value": "2019-10-02T16:50:00.000Z", + "value": "2020-06-11T20:20:00.000Z", } ], }, @@ -706,17 +757,12 @@ { "operator": "ON_OR_BEFORE", "term": "eventTimestamp", - "value": "2019-10-02T16:55:00.000Z", + "value": "2020-06-11T20:25:00.000Z", } ], }, - { - "filterClause": "OR", - "filters": [ - {"operator": "IS", "term": "exposure", "value": "IsPublic"}, - {"operator": "IS", "term": "exposure", "value": "SharedViaLink"}, - ], - }, + {"filterClause": "AND", "filters": []}, + {"filterClause": "AND", "filters": []}, ], "pgNum": 1, "pgSize": 10000, @@ -1051,10 +1097,12 @@ def test_map_observation_to_security_query(): alert = response["alerts"][0] actor = alert["actor"] observations = alert["observations"] - first_actual = json.loads(str(map_observation_to_security_query(observations[0], actor))) - second_actual = json.loads(str(map_observation_to_security_query(observations[1], actor))) - assert first_actual == MOCK_OBSERVATION_QUERIES[0] - assert second_actual == MOCK_OBSERVATION_QUERIES[1] + actual_queries = [ + json.loads(str(map_observation_to_security_query(o, actor))) for o in observations + ] + assert actual_queries[0] == MOCK_OBSERVATION_QUERIES[0] + assert actual_queries[1] == MOCK_OBSERVATION_QUERIES[1] + assert actual_queries[2] == MOCK_OBSERVATION_QUERIES[2] def test_map_to_code42_event_context(): From 8ab51e4941f8b0852d2730fc4b1b94794ac6ce8f Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 23 Jun 2020 16:36:21 +0000 Subject: [PATCH 3/8] Save --- Packs/Code42/Integrations/Code42/Code42.py | 25 ++++++++++++------- .../Code42/Integrations/Code42/Code42_test.py | 3 --- .../Code42/integration-Code42.yml | 25 ++++++++++++------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Packs/Code42/Integrations/Code42/Code42.py b/Packs/Code42/Integrations/Code42/Code42.py index e9aaae8fdaf2..0027504643bb 100644 --- a/Packs/Code42/Integrations/Code42/Code42.py +++ b/Packs/Code42/Integrations/Code42/Code42.py @@ -347,6 +347,12 @@ class ObservationToSecurityQueryMapper(object): _PUBLIC_LINK = "PublicLinkShare" _OUTSIDE_TRUSTED_DOMAINS = "SharedOutsideTrustedDomain" + exposure_type_map = { + "PublicSearchableShare": ExposureType.IS_PUBLIC, + "PublicLinkShare": ExposureType.SHARED_VIA_LINK, + "SharedOutsideTrustedDomain": "OutsideTrustedDomains" + } + def __init__(self, observation, actor): self._obs = observation self._actor = actor @@ -394,18 +400,19 @@ def _create_search_args(self): return filters + @logger def _create_exposure_filters(self, exposure_types): """Determine exposure types based on alert type""" - + exp_types = [] if self._is_cloud_exfiltration: - exp_types = [] - if self._PUBLIC_SEARCHABLE in exposure_types: - exp_types.append(ExposureType.IS_PUBLIC) - if self._PUBLIC_LINK in exposure_types: - exp_types.append(ExposureType.SHARED_VIA_LINK) - if self._OUTSIDE_TRUSTED_DOMAINS in exposure_types: - exp_types.append("OutsideTrustedDomains") - return [ExposureType.is_in(exp_types)] + for t in exposure_types: + exp_type = self.exposure_type_map.get(t) + if exp_type: + exp_types.append(exp_type) + else: + LOG("Received unsupported exposure type {0}.".format(t)) + if exp_types: + return [ExposureType.is_in(exp_types)] elif self._is_endpoint_exfiltration: return [ EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), diff --git a/Packs/Code42/Integrations/Code42/Code42_test.py b/Packs/Code42/Integrations/Code42/Code42_test.py index d8c85dfdc5aa..0587bdeb4eb3 100644 --- a/Packs/Code42/Integrations/Code42/Code42_test.py +++ b/Packs/Code42/Integrations/Code42/Code42_test.py @@ -727,7 +727,6 @@ {"operator": "IS", "term": "exposure", "value": "OutsideTrustedDomains"} ], }, - {"filterClause": "AND", "filters": []}, ], "pgNum": 1, "pgSize": 10000, @@ -761,8 +760,6 @@ } ], }, - {"filterClause": "AND", "filters": []}, - {"filterClause": "AND", "filters": []}, ], "pgNum": 1, "pgSize": 10000, diff --git a/Packs/Code42/Integrations/Code42/integration-Code42.yml b/Packs/Code42/Integrations/Code42/integration-Code42.yml index 947f67dfea7c..340e81afb974 100644 --- a/Packs/Code42/Integrations/Code42/integration-Code42.yml +++ b/Packs/Code42/Integrations/Code42/integration-Code42.yml @@ -419,6 +419,12 @@ script: _PUBLIC_LINK = "PublicLinkShare" _OUTSIDE_TRUSTED_DOMAINS = "SharedOutsideTrustedDomain" + exposure_type_map = { + "PublicSearchableShare": ExposureType.IS_PUBLIC, + "PublicLinkShare": ExposureType.SHARED_VIA_LINK, + "SharedOutsideTrustedDomain": "OutsideTrustedDomains" + } + def __init__(self, observation, actor): self._obs = observation self._actor = actor @@ -466,18 +472,19 @@ script: return filters + @logger def _create_exposure_filters(self, exposure_types): """Determine exposure types based on alert type""" - + exp_types = [] if self._is_cloud_exfiltration: - exp_types = [] - if self._PUBLIC_SEARCHABLE in exposure_types: - exp_types.append(ExposureType.IS_PUBLIC) - if self._PUBLIC_LINK in exposure_types: - exp_types.append(ExposureType.SHARED_VIA_LINK) - if self._OUTSIDE_TRUSTED_DOMAINS in exposure_types: - exp_types.append("OutsideTrustedDomains") - return [ExposureType.is_in(exp_types)] + for t in exposure_types: + exp_type = self.exposure_type_map.get(t) + if exp_type: + exp_types.append(exp_type) + else: + LOG("Received unsupported exposure type {0}.".format(t)) + if exp_types: + return [ExposureType.is_in(exp_types)] elif self._is_endpoint_exfiltration: return [ EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), From 7f4d82af6a0391d24a0a9ef09afa3734051c72e6 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 23 Jun 2020 16:40:17 +0000 Subject: [PATCH 4/8] Handle no cats --- Packs/Code42/Integrations/Code42/Code42.py | 3 ++- .../Code42/Integrations/Code42/Code42_test.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Packs/Code42/Integrations/Code42/Code42.py b/Packs/Code42/Integrations/Code42/Code42.py index 0027504643bb..8d90784ad825 100644 --- a/Packs/Code42/Integrations/Code42/Code42.py +++ b/Packs/Code42/Integrations/Code42/Code42.py @@ -424,7 +424,8 @@ def _create_file_category_filters(self): """Determine if file categorization is significant""" observed_file_categories = self._observation_data["fileCategories"] categories = [c["category"].upper() for c in observed_file_categories if c["isSignificant"]] - return FileCategory.is_in(categories) + if categories: + return FileCategory.is_in(categories) def map_observation_to_security_query(observation, actor): diff --git a/Packs/Code42/Integrations/Code42/Code42_test.py b/Packs/Code42/Integrations/Code42/Code42_test.py index 0587bdeb4eb3..7a470d757439 100644 --- a/Packs/Code42/Integrations/Code42/Code42_test.py +++ b/Packs/Code42/Integrations/Code42/Code42_test.py @@ -1240,6 +1240,25 @@ def test_highriskemployee_remove_command(code42_sdk_mock): code42_sdk_mock.detectionlists.high_risk_employee.remove.assert_called_once_with(expected) +def test_fetch_when_no_significant_file_categories_ignores_filter(code42_fetch_incidents_mock, mocker): + response_text = MOCK_ALERT_DETAILS_RESPONSE.replace('"isSignificant": true', '"isSignificant": false') + alert_details_response = create_mock_code42_sdk_response(mocker, response_text) + code42_fetch_incidents_mock.alerts.get_details.return_value = alert_details_response + client = create_client(code42_fetch_incidents_mock) + _, _, _ = fetch_incidents( + client=client, + last_run={"last_fetch": None}, + first_fetch_time=MOCK_FETCH_TIME, + event_severity_filter=None, + fetch_limit=10, + include_files=True, + integration_context=None, + ) + actual_query = str(code42_fetch_incidents_mock.securitydata.search_file_events.call_args[0][0]) + assert "fileCategory" not in actual_query + assert "IMAGE" not in actual_query + + def test_highriskemployee_get_all_command(code42_high_risk_employee_mock): client = create_client(code42_high_risk_employee_mock) _, _, res = highriskemployee_get_all_command(client, {}) From 5f514ec993916d28a2295e9221e5b4240ba180a8 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Tue, 23 Jun 2020 16:55:05 +0000 Subject: [PATCH 5/8] Create integ yml --- Packs/Code42/Integrations/Code42/integration-Code42.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packs/Code42/Integrations/Code42/integration-Code42.yml b/Packs/Code42/Integrations/Code42/integration-Code42.yml index 340e81afb974..406bba7503ed 100644 --- a/Packs/Code42/Integrations/Code42/integration-Code42.yml +++ b/Packs/Code42/Integrations/Code42/integration-Code42.yml @@ -496,7 +496,8 @@ script: """Determine if file categorization is significant""" observed_file_categories = self._observation_data["fileCategories"] categories = [c["category"].upper() for c in observed_file_categories if c["isSignificant"]] - return FileCategory.is_in(categories) + if categories: + return FileCategory.is_in(categories) def map_observation_to_security_query(observation, actor): From cebc8f33767ca7040ad091355e46ff9997d2f09b Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Wed, 24 Jun 2020 13:53:25 +0000 Subject: [PATCH 6/8] Handle unsupported ets better --- Packs/Code42/Integrations/Code42/Code42.py | 4 ++++ Packs/Code42/Integrations/Code42/Code42_test.py | 16 ++++++++++++++-- .../Integrations/Code42/integration-Code42.yml | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Packs/Code42/Integrations/Code42/Code42.py b/Packs/Code42/Integrations/Code42/Code42.py index 8d90784ad825..b8bb42e227b8 100644 --- a/Packs/Code42/Integrations/Code42/Code42.py +++ b/Packs/Code42/Integrations/Code42/Code42.py @@ -413,6 +413,10 @@ def _create_exposure_filters(self, exposure_types): LOG("Received unsupported exposure type {0}.".format(t)) if exp_types: return [ExposureType.is_in(exp_types)] + else: + # If not given a support exposure type, search for all unsupported exposure types.s + supported_exp_types = list(self.exposure_type_map.values()) + return [ExposureType.not_in(supported_exp_types)] elif self._is_endpoint_exfiltration: return [ EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), diff --git a/Packs/Code42/Integrations/Code42/Code42_test.py b/Packs/Code42/Integrations/Code42/Code42_test.py index 7a470d757439..e30512bac844 100644 --- a/Packs/Code42/Integrations/Code42/Code42_test.py +++ b/Packs/Code42/Integrations/Code42/Code42_test.py @@ -760,6 +760,14 @@ } ], }, + { + "filterClause": "AND", + "filters": [ + {"operator": "IS_NOT", "term": "exposure", "value": "IsPublic"}, + {"operator": "IS_NOT", "term": "exposure", "value": "SharedViaLink"}, + {"operator": "IS_NOT", "term": "exposure", "value": "OutsideTrustedDomains"}, + ], + }, ], "pgNum": 1, "pgSize": 10000, @@ -1240,8 +1248,12 @@ def test_highriskemployee_remove_command(code42_sdk_mock): code42_sdk_mock.detectionlists.high_risk_employee.remove.assert_called_once_with(expected) -def test_fetch_when_no_significant_file_categories_ignores_filter(code42_fetch_incidents_mock, mocker): - response_text = MOCK_ALERT_DETAILS_RESPONSE.replace('"isSignificant": true', '"isSignificant": false') +def test_fetch_when_no_significant_file_categories_ignores_filter( + code42_fetch_incidents_mock, mocker +): + response_text = MOCK_ALERT_DETAILS_RESPONSE.replace( + '"isSignificant": true', '"isSignificant": false' + ) alert_details_response = create_mock_code42_sdk_response(mocker, response_text) code42_fetch_incidents_mock.alerts.get_details.return_value = alert_details_response client = create_client(code42_fetch_incidents_mock) diff --git a/Packs/Code42/Integrations/Code42/integration-Code42.yml b/Packs/Code42/Integrations/Code42/integration-Code42.yml index 406bba7503ed..9ca7ff4a6bdf 100644 --- a/Packs/Code42/Integrations/Code42/integration-Code42.yml +++ b/Packs/Code42/Integrations/Code42/integration-Code42.yml @@ -485,6 +485,10 @@ script: LOG("Received unsupported exposure type {0}.".format(t)) if exp_types: return [ExposureType.is_in(exp_types)] + else: + # If not given a support exposure type, search for all unsupported exposure types.s + supported_exp_types = list(self.exposure_type_map.values()) + return [ExposureType.not_in(supported_exp_types)] elif self._is_endpoint_exfiltration: return [ EventType.is_in([EventType.CREATED, EventType.MODIFIED, EventType.READ_BY_APP]), From dbff2a06c7faed6f0e5242fd3d884679fb378a61 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Wed, 24 Jun 2020 13:54:20 +0000 Subject: [PATCH 7/8] Fix comment --- Packs/Code42/Integrations/Code42/Code42.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Code42/Integrations/Code42/Code42.py b/Packs/Code42/Integrations/Code42/Code42.py index b8bb42e227b8..fb48223c408b 100644 --- a/Packs/Code42/Integrations/Code42/Code42.py +++ b/Packs/Code42/Integrations/Code42/Code42.py @@ -414,7 +414,7 @@ def _create_exposure_filters(self, exposure_types): if exp_types: return [ExposureType.is_in(exp_types)] else: - # If not given a support exposure type, search for all unsupported exposure types.s + # If not given a support exposure type, search for all unsupported exposure types supported_exp_types = list(self.exposure_type_map.values()) return [ExposureType.not_in(supported_exp_types)] elif self._is_endpoint_exfiltration: From 662c7e8e3649aec534e6488c0249e0e2145da7cb Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Wed, 24 Jun 2020 13:54:49 +0000 Subject: [PATCH 8/8] Gen yml --- Packs/Code42/Integrations/Code42/integration-Code42.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/Code42/Integrations/Code42/integration-Code42.yml b/Packs/Code42/Integrations/Code42/integration-Code42.yml index 9ca7ff4a6bdf..0bd326f1a27a 100644 --- a/Packs/Code42/Integrations/Code42/integration-Code42.yml +++ b/Packs/Code42/Integrations/Code42/integration-Code42.yml @@ -486,7 +486,7 @@ script: if exp_types: return [ExposureType.is_in(exp_types)] else: - # If not given a support exposure type, search for all unsupported exposure types.s + # If not given a support exposure type, search for all unsupported exposure types supported_exp_types = list(self.exposure_type_map.values()) return [ExposureType.not_in(supported_exp_types)] elif self._is_endpoint_exfiltration: