Detection rules › Panther

GCP CloudBuild Potential Privilege Escalation

Severity
high
Log types
GCP.AuditLog
Reference
https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/
Source
github.com/panther-labs/panther-analysis

Detects privilege escalation attacks designed to gain access to the Cloud Build Service Account. A user with permissions to start a new build with Cloud Build can gain access to the Cloud Build Service Account and abuse it for more access to the environment.

MITRE ATT&CK coverage

TacticTechniques
Privilege EscalationT1548 Abuse Elevation Control Mechanism

Rule body yaml

AnalysisType: rule
LogTypes:
  - GCP.AuditLog
Description:
  Detects privilege escalation attacks designed to gain access to the Cloud Build Service Account.
  A user with permissions to start a new build with Cloud Build can gain access to the Cloud Build Service Account
  and abuse it for more access to the environment.
DisplayName: "GCP CloudBuild Potential Privilege Escalation"
RuleID: "GCP.CloudBuild.Potential.Privilege.Escalation"
Enabled: true
Filename: gcp_cloudbuild_potential_privilege_escalation.py
Reference: https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/
Runbook:
  Confirm this was authorized and necessary behavior. To defend against this privilege escalation attack,
  it is necessary to restrict the permissions granted to the Cloud Build Service Account and to be careful granting
  the cloudbuild.builds.create permission to any users in your Organization. Most importantly, you need to know that
  any user who is granted cloudbuild.builds.create, is also indirectly granted all the permissions granted to the
  Cloud Build Service Account. If that’s alright with you, then you may not need to worry about this attack vector,
  but it is still highly recommended to modify the default permissions granted to the Cloud Build Service Account.
Reports:
  MITRE ATT&CK:
    - TA0004:T1548 # Abuse Elevation Control Mechanism
Severity: High
DedupPeriodMinutes: 60
Threshold: 1
Tests:
  - Name: GCP CloudBuild - Build with Potentially Privileged Access
    ExpectedResult: true
    Log:
      {
        "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity",
        "operation":
          {
            "first": true,
            "id": "operations/build/some-project/YzNhZWI0YWYtNjAwNi00YzM5LTgxYmUtMjhmMjc1YzJkOGEz",
            "producer": "cloudbuild.googleapis.com",
          },
        "protoPayload":
          {
            "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo":
              {
                "principalEmail": "whodoneit@some-project.iam.gserviceaccount.com",
                "principalSubject": "serviceAccount:whodoneit@some-project.iam.gserviceaccount.com",
                "serviceAccountKeyName": "//iam.googleapis.com/projects/some-project/serviceAccounts/whodoneit@some-project.iam.gserviceaccount.com/keys/123er456788",
              },
            "authorizationInfo":
              [
                {
                  "granted": true,
                  "permission": "cloudbuild.builds.create",
                  "resource": "projects/some-project",
                  "resourceAttributes": {},
                },
              ],
            "methodName": "google.devtools.cloudbuild.v1.CloudBuild.CreateBuild",
            "request":
              {
                "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.CreateBuildRequest",
                "build": {},
                "projectId": "some-project",
              },
            "requestMetadata":
              {
                "callerIP": "189.163.74.177",
                "callerSuppliedUserAgent": "(gzip),gzip(gfe),gzip(gfe)",
                "destinationAttributes": {},
                "requestAttributes":
                  { "auth": {}, "time": "2024-01-25T11:55:09.740095Z" },
              },
            "resourceLocation": { "currentLocations": ["global"] },
            "resourceName": "projects/some-project/builds",
            "serviceName": "cloudbuild.googleapis.com",
          },
        "receiveTimestamp": "2024-01-25 11:55:09.854909113",
        "resource":
          {
            "labels":
              {
                "build_id": "c3aeb4ap-6006-4c39-81be-28f275c2d8a3",
                "build_trigger_id": "",
                "project_id": "some-project",
              },
            "type": "build",
          },
        "severity": "NOTICE",
        "timestamp": "2024-01-25 11:55:08.919358000",
      }
  - Name: GCP CreateBrand - No Privileged Access
    ExpectedResult: false
    Log:
      {
        "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity",
        "protoPayload":
          {
            "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo":
              { "principalEmail": "john.doe@some-project.com" },
            "authorizationInfo":
              [
                {
                  "granted": true,
                  "permission": "clientauthconfig.brands.create",
                  "resource": "brands/1028347248702",
                  "resourceAttributes": {},
                },
              ],
            "methodName": "CreateBrand",
            "request":
              {
                "brand":
                  {
                    "displayName": "NewBrand",
                    "projectNumbers": ["1028345275902"],
                    "supportEmail": "john.doe@some-project.com",
                  },
                "visibility": "INTERNAL",
              },
            "requestMetadata":
              {
                "callerIP": "189.163.74.177",
                "destinationAttributes": {},
                "requestAttributes":
                  { "auth": {}, "time": "2024-01-24T14:30:05.891336Z" },
              },
            "resourceName": "brands/1028347275902",
            "response":
              {
                "brandId": "1028347248702",
                "creationTime": "2024-01-24T14:30:05.400Z",
                "displayName": "NewBrand test",
                "projectNumbers": ["1028347248702"],
                "supportEmail": "some.user@company.com",
                "updateTime": "2024-01-24T14:30:05.866002Z",
              },
            "serviceName": "clientauthconfig.googleapis.com",
            "status": {},
          },
        "receiveTimestamp": "2024-01-24 14:30:06.741210353",
        "resource":
          {
            "labels":
              { "brand_id": "1028347248702", "project_id": "some-project" },
            "type": "client_auth_config_brand",
          },
        "severity": "NOTICE",
        "timestamp": "2024-01-24 14:30:05.207884000",
      }

Detection logic

Condition

protoPayload.methodName ends_with "CloudBuild.CreateBuild"
protoPayload.authorizationInfo is_not_null
protoPayload.authenticationInfo.principalEmail not ends_with "@gcf-admin-robot.iam.gserviceaccount.com"
protoPayload.authorizationInfo array_any

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
protoPayload.authenticationInfo.principalEmailends_with@gcf-admin-robot.iam.gserviceaccount.com

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
protoPayload.authorizationInfois_not_null
  • (no value, null check)
protoPayload.methodNameends_with
  • CloudBuild.CreateBuild

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
projectresource.labels.project_id
principalprotoPayload.authenticationInfo.principalEmail
caller_ipprotoPayload.requestMetadata.callerIP
methodNameprotoPayload.methodName
resourceNameprotoPayload.resourceName
serviceNameprotoPayload.serviceName