Awscloudtrail Aws S3 Bucket Publicly Exposed
KQL detection rule by ep3p · MIT
The query_now parameter represents the time (in UTC) at which the scheduled analytics rule ran to produce this alert.
// The query_now parameter represents the time (in UTC) at which the scheduled analytics rule ran to produce this alert.
set query_now = datetime(2024-04-15T14:13:46.6297420Z);
let _SharedAWSAccounts = toscalar(
_GetWatchlist("AccountId-AuditAWSAccounts")
| where Notes has "[ShareBucket]"
| summarize make_list(AccountId)
);
let _Headers_PutBucketAcl =
AWSCloudTrail
| where EventName in ("PutBucketAcl", "PutObjectAcl")
| extend RequestParameters = todynamic(RequestParameters)
| where tostring(RequestParameters["accessControlList"]["x-amz-grant-full-control"]) has_any ("AuthenticatedUsers", "AllUsers", "emailAddress=", "id=")
or tostring(RequestParameters["accessControlList"]["x-amz-grant-read"]) has_any ("AuthenticatedUsers", "AllUsers", "emailAddress=", "id=")
or tostring(RequestParameters["accessControlList"]["x-amz-grant-read-acp"]) has_any ("AuthenticatedUsers", "AllUsers", "emailAddress=", "id=")
or tostring(RequestParameters["accessControlList"]["x-amz-grant-write"]) has_any ("AuthenticatedUsers", "AllUsers", "emailAddress=", "id=")
or tostring(RequestParameters["accessControlList"]["x-amz-grant-write-acp"]) has_any ("AuthenticatedUsers", "AllUsers", "emailAddress=", "id=")
;
let _ACL_PutBucketAcl =
AWSCloudTrail
| where EventName in ("PutBucketAcl", "PutObjectAcl")
| extend RequestParameters = todynamic(RequestParameters)
| mv-expand Grant = iff(isempty(array_length(RequestParameters["AccessControlPolicy"]["AccessControlList"])), pack_array(RequestParameters["AccessControlPolicy"]["AccessControlList"]), RequestParameters["AccessControlPolicy"]["AccessControlList"])
| where Grant has_any ("AuthenticatedUsers", "AllUsers", "EmailAddress", "ID", "authenticated-read", "public-read", "public-read-write")
;
let _BucketPolicies =
AWSCloudTrail
| where EventName in ("PutBucketPolicy", "PutAccessPointPolicy")
| extend RequestParameters = todynamic(RequestParameters)
// | extend Statement = case(
// bag_keys(RequestParameters) has "bucketPolicy", todynamic(tostring(RequestParameters["bucketPolicy"]))["Statement"],
// bag_keys(RequestParameters) has "PutAccessPointPolicyRequest", todynamic(tostring(RequestParameters["PutAccessPointPolicyRequest"]))["Policy"]["Statement"],
// bag_keys(RequestParameters) has "policyDocument", todynamic(tostring(RequestParameters["policyDocument"]))["Statement"],
// bag_keys(RequestParameters) has "content", todynamic(tostring(RequestParameters["content"]))["Statement"],
// dynamic(null)
// )
// | mv-expand Statement = iff(isnotempty(bag_keys(Statement)), pack_array(Statement), Statement)
// | extend
// Principal = tostring(Statement["Principal"]),
// Effect = tostring(Statement["Effect"]),
// Action = tostring(Statement["Action"]),
// Resource = tostring(Statement["Resource"]),
// Condition = tostring(Statement["Condition"])
// | where Effect == "Allow"
// | where Action has "*" or (not(strcat(Principal, "|", Condition) has RecipientAccountId) and not(strcat(Principal, "|", Condition) has_any (_SharedAWSAccounts)))
// | summarize take_any(*) by AwsEventId
;
union _Headers_PutBucketAcl, _ACL_PutBucketAcl, _BucketPolicies
| invoke AWSIdentityRole()
| project
TimeGenerated,
UserIdentityType,
Identity,
ActorRole,
UserIdentityAccountId,
UserIdentityAccountName,
RecipientAccountId,
RecipientAccountName,
AWSRegion,
SessionCreationDate,
UserIdentityPrincipalid,
UserIdentityArn,
SourceIpAddress,
EventSource,
EventTypeName,
EventName,
ManagementEvent,
ReadOnly,
ErrorCode,
ErrorMessage,
RequestParameters,
ResponseElements,
Resources,
SessionMfaAuthenticated,
UserAgent,
AwsEventId