From 744e7ff5ac09265eeb8a65eeb51f8061d59486e7 Mon Sep 17 00:00:00 2001 From: Amogh Bantwal <100332169+abant07@users.noreply.github.com> Date: Wed, 25 Sep 2024 06:15:47 -0700 Subject: [PATCH] feat(threat-detection): Use IAM Identity for Cloudtrail Threat Detection instead of IP (#5166) --- ...cloudtrail_threat_detection_enumeration.py | 29 ++++++++++----- ...l_threat_detection_privilege_escalation.py | 35 ++++++++++++------- ...trail_threat_detection_enumeration_test.py | 6 ++-- ...eat_detection_privilege_escalation_test.py | 6 ++-- 4 files changed, 49 insertions(+), 27 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 82eddb6372..fe6e965be7 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 @@ -39,14 +39,27 @@ class cloudtrail_threat_detection_enumeration(Check): minutes=threat_detection_minutes, ): event_log = json.loads(event_log["CloudTrailEvent"]) - if ".amazonaws.com" not in event_log["sourceIPAddress"]: - if event_log["sourceIPAddress"] not in potential_enumeration: - potential_enumeration[event_log["sourceIPAddress"]] = set() - potential_enumeration[event_log["sourceIPAddress"]].add( - event_name + 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"], ) - for source_ip, actions in potential_enumeration.items(): - ip_threshold = round(len(actions) / len(enumeration_actions), 2) + ].add(event_name) + + for aws_identity, actions in potential_enumeration.items(): + identity_threshold = round(len(actions) / len(enumeration_actions), 2) + aws_identity_type = aws_identity[1] + aws_identity_arn = aws_identity[0] if len(actions) / len(enumeration_actions) > threshold: found_potential_enumeration = True report = Check_Report_AWS(self.metadata()) @@ -56,7 +69,7 @@ class cloudtrail_threat_detection_enumeration(Check): cloudtrail_client.region ) report.status = "FAIL" - report.status_extended = f"Potential enumeration attack detected from source IP {source_ip} with an threshold of {ip_threshold}." + report.status_extended = f"Potential enumeration attack detected from AWS {aws_identity_type} {aws_identity_arn.split('/')[-1]} with an threshold of {identity_threshold}." findings.append(report) if not found_potential_enumeration: report = Check_Report_AWS(self.metadata()) 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 1af9f0f1bc..b295534f90 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 @@ -40,19 +40,28 @@ class cloudtrail_threat_detection_privilege_escalation(Check): minutes=threat_detection_minutes, ): event_log = json.loads(event_log["CloudTrailEvent"]) - if ".amazonaws.com" not in event_log["sourceIPAddress"]: - if ( - event_log["sourceIPAddress"] - not in potential_privilege_escalation - ): - potential_privilege_escalation[ - event_log["sourceIPAddress"] - ] = set() + if ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) not in potential_privilege_escalation: potential_privilege_escalation[ - event_log["sourceIPAddress"] - ].add(event_name) - for source_ip, actions in potential_privilege_escalation.items(): - ip_threshold = round(len(actions) / len(privilege_escalation_actions), 2) + ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) + ] = set() + potential_privilege_escalation[ + ( + event_log["userIdentity"]["arn"], + event_log["userIdentity"]["type"], + ) + ].add(event_name) + for aws_identity, actions in potential_privilege_escalation.items(): + identity_threshold = round( + len(actions) / len(privilege_escalation_actions), 2 + ) + aws_identity_type = aws_identity[1] + aws_identity_arn = aws_identity[0] if len(actions) / len(privilege_escalation_actions) > threshold: found_potential_privilege_escalation = True report = Check_Report_AWS(self.metadata()) @@ -62,7 +71,7 @@ class cloudtrail_threat_detection_privilege_escalation(Check): cloudtrail_client.region ) report.status = "FAIL" - report.status_extended = f"Potential privilege escalation attack detected from source IP {source_ip} with an threshold of {ip_threshold}." + report.status_extended = f"Potential privilege escalation attack detected from AWS {aws_identity_type} {aws_identity_arn.split('/')[-1]} with an threshold of {identity_threshold}." findings.append(report) if not found_potential_privilege_escalation: report = Check_Report_AWS(self.metadata()) 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 e13fa3f736..67399dff35 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 @@ -19,10 +19,10 @@ def mock_get_trail_arn_template(region=None, *_) -> str: def mock__get_lookup_events__(trail=None, event_name=None, minutes=None, *_) -> list: return [ { - "CloudTrailEvent": '{"sourceIPAddress": "172.28.7.0/24", "eventName": "DescribeAccessEntry"}' + "CloudTrailEvent": '{"eventName": "DescribeAccessEntry", "userIdentity": {"type": "IAMUser", "principalId": "EXAMPLE6E4XEGITWATV6R", "arn": "arn:aws:iam::123456789012:user/Mateo", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "userName": "Mateo", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' }, { - "CloudTrailEvent": '{"sourceIPAddress": "172.28.7.0/24", "eventName": "DescribeAccountAttributes"}' + "CloudTrailEvent": '{"eventName": "DescribeAccountAttributes", "userIdentity": {"type": "IAMUser", "principalId": "EXAMPLE6E4XEGITWATV6R", "arn": "arn:aws:iam::123456789012:user/Mateo", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "userName": "Mateo", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' }, ] @@ -154,7 +154,7 @@ class Test_cloudtrail_threat_detection_enumeration: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Potential enumeration attack detected from source IP 172.28.7.0/24 with an threshold of 1.0." + == "Potential enumeration attack detected from AWS IAMUser Mateo with an threshold of 1.0." ) assert result[0].resource_id == AWS_ACCOUNT_NUMBER assert result[0].region == AWS_REGION_US_EAST_1 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 a39deff5ef..fcf4a90965 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 @@ -19,10 +19,10 @@ def mock_get_trail_arn_template(region=None, *_) -> str: def mock__get_lookup_events__(trail=None, event_name=None, minutes=None, *_) -> list: return [ { - "CloudTrailEvent": '{"sourceIPAddress": "172.28.7.0/24", "eventName": "CreateLoginProfile"}' + "CloudTrailEvent": '{"eventName": "CreateLoginProfile", "userIdentity": {"type": "IAMUser", "principalId": "EXAMPLE6E4XEGITWATV6R", "arn": "arn:aws:iam::123456789012:user/Mateo", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "userName": "Mateo", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' }, { - "CloudTrailEvent": '{"sourceIPAddress": "172.28.7.0/24", "eventName": "UpdateLoginProfile"}' + "CloudTrailEvent": '{"eventName": "UpdateLoginProfile", "userIdentity": {"type": "IAMUser", "principalId": "EXAMPLE6E4XEGITWATV6R", "arn": "arn:aws:iam::123456789012:user/Mateo", "accountId": "123456789012", "accessKeyId": "AKIAIOSFODNN7EXAMPLE", "userName": "Mateo", "sessionContext": {"sessionIssuer": {}, "webIdFederationData": {}, "attributes": {"creationDate": "2023-07-19T21:11:57Z", "mfaAuthenticated": "false"}}}}' }, ] @@ -153,7 +153,7 @@ class Test_cloudtrail_threat_detection_privilege_escalation: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "Potential privilege escalation attack detected from source IP 172.28.7.0/24 with an threshold of 1.0." + == "Potential privilege escalation attack detected from AWS IAMUser Mateo with an threshold of 1.0." ) assert result[0].resource_id == AWS_ACCOUNT_NUMBER assert result[0].region == AWS_REGION_US_EAST_1