GCP Cloud Storage Buckets Modified Or Deleted


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.

Query · python

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"),
    }

Analyst notes

  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
Raw source GCP Cloud Storage Buckets Modified Or Deleted · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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"),
    }

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.