AnalysisType: rule
DisplayName: "GCP Cloud Storage Buckets Modified Or Deleted"
Enabled: true
Filename: gcp_cloud_storage_buckets_modified_or_deleted.py
Description: >
Detects when a GCS bucket configuration is updated or deleted. Bucket configuration changes can be
part of a ransomware attack, such as disabling security settings to prevent data recovery.
Runbook: |
1. Query GCP Audit logs for all bucket operations by the principal email in the 24 hours before and after this alert
2. Check if the source IP is associated with known cloud provider IP ranges, VPN endpoints, or matches the user's typical access patterns
3. Identify what specific configuration was changed (encryption, retention, versioning, lifecycle policies)
4. Search for related KMS key changes or IAM policy modifications on the same bucket in the past 6 hours
5. Look for bulk object operations (rewrite, copy, delete) on this bucket following the configuration change
Reference: https://cloud.google.com/storage/docs/json_api/v1/buckets/update
Tags:
- GCP
- Google Cloud Storage
- Defense Evasion:Impair Defenses
- Impact:Data Encrypted for Impact
- Ransomware
Reports:
MITRE ATT&CK:
- TA0005:T1562
- TA0040:T1486
SummaryAttributes:
- severity
- p_any_ip_addresses
- p_any_emails
Severity: Low
Tests:
- ExpectedResult: false
Log:
insertid: ezyd47c12y
logname: projects/gcp-project1/logs/cloudaudit.googleapis.com%2Factivity
p_any_ip_addresses:
- 1.2.3.4
p_event_time: "2023-03-09 16:41:30.524"
p_log_type: GCP.AuditLog
p_parse_time: "2023-03-09 16:44:14.617"
p_row_id: "1234567909689348911"
p_source_id: 4fc88a5a-2d51-4279-9c4a-08fa7cc52566
p_source_label: gcplogsource
protoPayload:
at_sign_type: type.googleapis.com/google.cloud.audit.AuditLog
authenticationInfo:
principalEmail: john@justice.org
authorizationInfo:
- granted: true
permission: logging.sinks.update
resource: projects/gcp-project1/sinks/log-sink
resourceAttributes:
name: projects/gcp-project1/sinks/log-sink
service: logging.googleapis.com
methodName: google.logging.v2.ConfigServiceV2.UpdateSink
request:
"@type": type.googleapis.com/google.logging.v2.UpdateSinkRequest
sink:
destination: pubsub.googleapis.com/projects/gcp-project1/topics/gcp-topic1
exclusions:
- filter: protoPayload.serviceName = 'k8s.io
name: excludek8s
name: log-sink
writerIdentity: serviceAccount:denethor@lotr.com
sinkName: projects/gcp-project1/sinks/log-sink
uniqueWriterIdentity: true
updateMask: exclusions
requestMetadata:
callerIP: 1.2.3.4
callerSuppliedUserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36,gzip(gfe),gzip(gfe)
destinationAttributes: {}
requestAttributes:
auth: {}
time: "2023-03-09T16:41:30.540045105Z"
resourceName: projects/gcp-project1/sinks/log-sink
serviceName: logging.googleapis.com
status: {}
receivetimestamp: "2023-03-09 16:41:32.21"
resource:
labels:
destination: ""
name: log-sink
project_id: gcp-project1
type: logging_sink
severity: NOTICE
timestamp: "2023-03-09 16:41:30.524"
Name: other event
- ExpectedResult: true
Log:
insertId: asdf1234asdfg
logName: projects/gcp-project1/logs/cloudaudit.googleapis.com%2Factivity
p_any_ip_addresses:
- 1.2.3.4
p_event_time: "2023-03-09 10:05:23.603"
p_log_type: GCP.AuditLog
p_parse_time: "2023-03-09 10:07:14.731"
p_row_id: 7ad218d42253b7e6f78cc0ed1635
p_source_id: 4fc88a5a-2d51-4279-9c4a-08fa7cc52566
p_source_label: gcplogsource
protoPayload:
at_sign_type: type.googleapis.com/google.cloud.audit.AuditLog
authenticationInfo:
principalEmail: user@company.io
authorizationInfo:
- granted: true
permission: storage.buckets.update
resource: projects/_/buckets/my-bucket
resourceAttributes: {}
methodName: storage.buckets.update
requestMetadata:
callerIP: 1.2.3.4
callerSuppliedUserAgent: apitools Python/3.9.11 gsutil/5.11 (darwin) analytics/enabled interactive/True command/notification google-cloud-sdk/394.0.0,gzip(gfe)
destinationAttributes: {}
requestAttributes:
auth: {}
time: "2023-03-09T10:05:23.610372568Z"
resourceName: projects/_/buckets/my-bucket
serviceName: storage.googleapis.com
status: {}
receiveTimestamp: "2023-03-09 10:05:25.146"
resource:
labels:
bucket_name: my-bucket
location: us-east1
project_id: gcp-project1
type: gcs_bucket
severity: NOTICE
timestamp: "2023-03-09 10:05:23.603"
Name: bucket update
DedupPeriodMinutes: 60
LogTypes:
- GCP.AuditLog
RuleID: "GCP.Cloud.Storage.Buckets.Modified.Or.Deleted"
Threshold: 1
# ------ paired body: gcp_cloud_storage_buckets_modified_or_deleted.py ------
BUCKET_OPERATIONS = ["storage.buckets.delete", "storage.buckets.update"]
def rule(event):
return all(
[
event.deep_get("protoPayload", "serviceName", default="") == "storage.googleapis.com",
event.deep_get("protoPayload", "methodName", default="") in BUCKET_OPERATIONS,
event.get("severity") != "ERROR",
]
)
def title(event):
actor = event.deep_get(
"protoPayload", "authenticationInfo", "principalEmail", default="<ACTOR_NOT_FOUND>"
)
operation = event.deep_get("protoPayload", "methodName", default="<OPERATION_NOT_FOUND>")
project = event.deep_get("resource", "labels", "project_id", default="<PROJECT_NOT_FOUND>")
bucket = event.deep_get("resource", "labels", "bucket_name", default="<BUCKET_NOT_FOUND>")
return f"GCP: [{actor}] performed a [{operation}] on bucket [{bucket}] in project [{project}]."
def alert_context(event):
return {
"actor": event.deep_get("protoPayload", "authenticationInfo", "principalEmail"),
"bucket": event.deep_get("resource", "labels", "bucket_name"),
"source_ip": event.deep_get("protoPayload", "requestMetadata", "callerIp"),
"user_agent": event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent"),
"project": event.deep_get("resource", "labels", "project_id"),
}