From 3950d7eba862fce96d7be9323fca672ee193deba Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:25:09 -0400 Subject: [PATCH] fix(threat detection): ignore AWS services events (#5276) --- ...cloudtrail_threat_detection_enumeration.py | 23 ++++--- ...l_threat_detection_privilege_escalation.py | 23 ++++--- ...trail_threat_detection_enumeration_test.py | 62 ++++++++++++++++++ ...eat_detection_privilege_escalation_test.py | 63 +++++++++++++++++++ 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration.py index fe6e965be7..be32be559f 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration.py @@ -40,21 +40,24 @@ class cloudtrail_threat_detection_enumeration(Check): ): event_log = json.loads(event_log["CloudTrailEvent"]) if ( - event_log["userIdentity"]["arn"], - event_log["userIdentity"]["type"], - ) not in potential_enumeration: + "arn" in event_log["userIdentity"] + ): # Ignore event logs without ARN since they are AWS services + if ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) not in potential_enumeration: + potential_enumeration[ + ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) + ] = set() potential_enumeration[ ( event_log["userIdentity"]["arn"], event_log["userIdentity"]["type"], ) - ] = set() - potential_enumeration[ - ( - event_log["userIdentity"]["arn"], - event_log["userIdentity"]["type"], - ) - ].add(event_name) + ].add(event_name) for aws_identity, actions in potential_enumeration.items(): identity_threshold = round(len(actions) / len(enumeration_actions), 2) diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation.py index b295534f90..a87184c0f1 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation.py @@ -41,21 +41,24 @@ class cloudtrail_threat_detection_privilege_escalation(Check): ): event_log = json.loads(event_log["CloudTrailEvent"]) if ( - event_log["userIdentity"]["arn"], - event_log["userIdentity"]["type"], - ) not in potential_privilege_escalation: + "arn" in event_log["userIdentity"] + ): # Ignore event logs without ARN since they are AWS services + if ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) not in potential_privilege_escalation: + potential_privilege_escalation[ + ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) + ] = set() potential_privilege_escalation[ ( event_log["userIdentity"]["arn"], event_log["userIdentity"]["type"], ) - ] = set() - potential_privilege_escalation[ - ( - event_log["userIdentity"]["arn"], - event_log["userIdentity"]["type"], - ) - ].add(event_name) + ].add(event_name) for aws_identity, actions in potential_privilege_escalation.items(): identity_threshold = round( len(actions) / len(privilege_escalation_actions), 2 diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration_test.py index 67399dff35..b38d448eac 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_enumeration/cloudtrail_threat_detection_enumeration_test.py @@ -27,6 +27,19 @@ def mock__get_lookup_events__(trail=None, event_name=None, minutes=None, *_) -> ] +def mock__get_lookup_events_aws_service__( + trail=None, event_name=None, minutes=None, *_ +) -> list: + return [ + { + "CloudTrailEvent": '{"eventName": "DescribeAccessEntry", "userIdentity": {"type": "AWSService", "principalId": "EXAMPLE6E4XEGITWATV6R", "accountId": "123456789012", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' + }, + { + "CloudTrailEvent": '{"eventName": "DescribeAccountAttributes", "userIdentity": {"type": "AWSService", "principalId": "EXAMPLE6E4XEGITWATV6R", "accountId": "123456789012", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' + }, + ] + + class Test_cloudtrail_threat_detection_enumeration: @mock_aws def test_no_trails(self): @@ -211,3 +224,52 @@ class Test_cloudtrail_threat_detection_enumeration: result[0].resource_arn == f"arn:aws:cloudtrail:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trail" ) + + @mock_aws + def test_potential_enumeration_from_aws_service(self): + ENUMERATION_ACTIONS = ["DescribeAccessEntry", "DescribeAccountAttributes"] + THRESHOLD = 2.0 + THREAT_DETECTION_MINUTES = 1440 + cloudtrail_client = mock.MagicMock() + cloudtrail_client.trails = {"us-east-1": mock.MagicMock()} + cloudtrail_client.trails["us-east-1"].is_multiregion = False + cloudtrail_client.trails["us-east-1"].name = "trail_test_us" + cloudtrail_client.trails["us-east-1"].s3_bucket_name = "bucket_test_us" + cloudtrail_client.trails["us-east-1"].region = "us-east-1" + cloudtrail_client.audited_account = AWS_ACCOUNT_NUMBER + cloudtrail_client.region = AWS_REGION_US_EAST_1 + cloudtrail_client.audit_config = { + "threat_detection_enumeration_actions": ENUMERATION_ACTIONS, + "threat_detection_enumeration_threshold": THRESHOLD, + "threat_detection_enumeration_minutes": THREAT_DETECTION_MINUTES, + } + + cloudtrail_client._lookup_events = mock__get_lookup_events_aws_service__ + cloudtrail_client._get_trail_arn_template = mock_get_trail_arn_template + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.cloudtrail.cloudtrail_threat_detection_enumeration.cloudtrail_threat_detection_enumeration.cloudtrail_client", + new=cloudtrail_client, + ): + # Test Check + from prowler.providers.aws.services.cloudtrail.cloudtrail_threat_detection_enumeration.cloudtrail_threat_detection_enumeration import ( + cloudtrail_threat_detection_enumeration, + ) + + check = cloudtrail_threat_detection_enumeration() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended == "No potential enumeration attack detected." + ) + assert result[0].resource_id == AWS_ACCOUNT_NUMBER + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:cloudtrail:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trail" + ) diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation_test.py index fcf4a90965..ba278db3cf 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_threat_detection_privilege_escalation/cloudtrail_threat_detection_privilege_escalation_test.py @@ -27,6 +27,19 @@ def mock__get_lookup_events__(trail=None, event_name=None, minutes=None, *_) -> ] +def mock__get_lookup_events_aws_service__( + trail=None, event_name=None, minutes=None, *_ +) -> list: + return [ + { + "CloudTrailEvent": '{"eventName": "CreateLoginProfile", "userIdentity": {"type": "AWSService", "principalId": "EXAMPLE6E4XEGITWATV6R", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' + }, + { + "CloudTrailEvent": '{"eventName": "UpdateLoginProfile", "userIdentity": {"type": "AWSService", "principalId": "EXAMPLE6E4XEGITWATV6R", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' + }, + ] + + class Test_cloudtrail_threat_detection_privilege_escalation: @mock_aws def test_no_trails(self): @@ -211,3 +224,53 @@ class Test_cloudtrail_threat_detection_privilege_escalation: result[0].resource_arn == f"arn:aws:cloudtrail:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trail" ) + + @mock_aws + def test_potential_enumeration_from_aws_service(self): + cloudtrail_client = mock.MagicMock() + cloudtrail_client.trails = {"us-east-1": mock.MagicMock()} + cloudtrail_client.trails["us-east-1"].is_multiregion = False + cloudtrail_client.trails["us-east-1"].name = "trail_test_us" + cloudtrail_client.trails["us-east-1"].s3_bucket_name = "bucket_test_us" + cloudtrail_client.trails["us-east-1"].region = "us-east-1" + cloudtrail_client.audited_account = AWS_ACCOUNT_NUMBER + cloudtrail_client.region = AWS_REGION_US_EAST_1 + cloudtrail_client.audit_config = { + "threat_detection_privilege_escalation_actions": [ + "CreateLoginProfile", + "UpdateLoginProfile", + ], + "threat_detection_privilege_escalation_threshold": 2.0, + "threat_detection_privilege_escalation_minutes": 1440, + } + + cloudtrail_client._lookup_events = mock__get_lookup_events_aws_service__ + cloudtrail_client._get_trail_arn_template = mock_get_trail_arn_template + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.cloudtrail.cloudtrail_threat_detection_privilege_escalation.cloudtrail_threat_detection_privilege_escalation.cloudtrail_client", + new=cloudtrail_client, + ): + # Test Check + from prowler.providers.aws.services.cloudtrail.cloudtrail_threat_detection_privilege_escalation.cloudtrail_threat_detection_privilege_escalation import ( + cloudtrail_threat_detection_privilege_escalation, + ) + + check = cloudtrail_threat_detection_privilege_escalation() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "No potential privilege escalation attack detected." + ) + assert result[0].resource_id == AWS_ACCOUNT_NUMBER + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:cloudtrail:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trail" + )