GCP IAM serviceAccounts signBlob


Description

The iam.serviceAccounts.signBlob permission "allows signing of arbitrary payloads" in GCP. This means we can create a signed blob that requests an access token from the Service Account we are targeting.

Query · python

from panther_gcp_helpers import gcp_alert_context


def rule(event):
    authorization_info = event.deep_walk("protoPayload", "authorizationInfo")
    if not authorization_info:
        return False

    for auth in authorization_info:
        if auth.get("permission") == "iam.serviceAccounts.signBlob" and auth.get("granted") is True:
            return True
    return False


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_id = event.deep_get("resource", "labels", "project_id", default="<PROJECT_NOT_FOUND>")

    return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]"


def alert_context(event):
    return gcp_alert_context(event)
Raw source GCP IAM serviceAccounts signBlob · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: gcp_iam_service_accounts_sign_blob.py
RuleID: "GCP.IAM.serviceAccounts.signBlob"
DisplayName: "GCP IAM serviceAccounts signBlob"
Enabled: true
LogTypes:
  - GCP.AuditLog
Reports:
  MITRE ATT&CK:
    - TA0004:T1548
Severity: High
Description:
  The iam.serviceAccounts.signBlob permission "allows signing of arbitrary payloads" in GCP.
  This means we can create a signed blob that requests an access token from the Service Account we are targeting.
Reference: https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/
Tests:
  - Name: iam.serviceAccounts.signBlob granted
    ExpectedResult: true
    Log:
      {
        "protoPayload":
          {
            "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "status": {},
            "authenticationInfo":
              {
                "principalEmail": "some-project@company.iam.gserviceaccount.com",
                "serviceAccountKeyName": "//iam.googleapis.com/projects/some-project/serviceAccounts/some-project@company.iam.gserviceaccount.com/keys/a378358365ff3d22e9c1a72fecf4605ddff76b47",
                "principalSubject": "serviceAccount:some-project@company.iam.gserviceaccount.com",
              },
            "requestMetadata":
              {
                "callerIp": "1.2.3.4",
                "requestAttributes":
                  { "time": "2024-02-26T17:15:16.327542536Z", "auth": {} },
                "destinationAttributes": {},
              },
            "serviceName": "iamcredentials.googleapis.com",
            "methodName": "SignJwt",
            "authorizationInfo":
              [
                {
                  "permission": "iam.serviceAccounts.signBlob",
                  "granted": true,
                  "resourceAttributes": {},
                },
              ],
            "resourceName": "projects/-/serviceAccounts/114885146936855121342",
            "request":
              {
                "name": "projects/-/serviceAccounts/some-project@company.iam.gserviceaccount.com",
                "@type": "type.googleapis.com/google.iam.credentials.v1.SignJwtRequest",
              },
          },
        "insertId": "1hu88qbef4d2o",
        "resource":
          {
            "type": "service_account",
            "labels":
              {
                "project_id": "some-project",
                "unique_id": "114885146936855121342",
                "email_id": "some-project@company.iam.gserviceaccount.com",
              },
          },
        "timestamp": "2024-02-26T17:15:16.314854637Z",
        "severity": "INFO",
        "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Fdata_access",
        "receiveTimestamp": "2024-02-26T17:15:17.100020459Z",
      }
  - Name: iam.serviceAccounts.signBlob not granted
    ExpectedResult: false
    Log:
      {
        "protoPayload":
          {
            "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "status": {},
            "authenticationInfo":
              {
                "principalEmail": "some-project@company.iam.gserviceaccount.com",
                "serviceAccountKeyName": "//iam.googleapis.com/projects/some-project/serviceAccounts/some-project@company.iam.gserviceaccount.com/keys/a378358365ff3d22e9c1a72fecf4605ddff76b47",
                "principalSubject": "serviceAccount:some-project@company.iam.gserviceaccount.com",
              },
            "requestMetadata":
              {
                "callerIp": "1.2.3.4",
                "requestAttributes":
                  { "time": "2024-02-26T17:15:16.327542536Z", "auth": {} },
                "destinationAttributes": {},
              },
            "serviceName": "iamcredentials.googleapis.com",
            "methodName": "SignJwt",
            "authorizationInfo":
              [
                {
                  "permission": "iam.serviceAccounts.signBlob",
                  "granted": false,
                  "resourceAttributes": {},
                },
              ],
            "resourceName": "projects/-/serviceAccounts/114885146936855121342",
            "request":
              {
                "name": "projects/-/serviceAccounts/some-project@company.iam.gserviceaccount.com",
                "@type": "type.googleapis.com/google.iam.credentials.v1.SignJwtRequest",
              },
          },
        "insertId": "1hu88qbef4d2o",
        "resource":
          {
            "type": "service_account",
            "labels":
              {
                "project_id": "some-project",
                "unique_id": "114885146936855121342",
                "email_id": "some-project@company.iam.gserviceaccount.com",
              },
          },
        "timestamp": "2024-02-26T17:15:16.314854637Z",
        "severity": "INFO",
        "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Fdata_access",
        "receiveTimestamp": "2024-02-26T17:15:17.100020459Z",
      }


# ------ paired body: gcp_iam_service_accounts_sign_blob.py ------

from panther_gcp_helpers import gcp_alert_context


def rule(event):
    authorization_info = event.deep_walk("protoPayload", "authorizationInfo")
    if not authorization_info:
        return False

    for auth in authorization_info:
        if auth.get("permission") == "iam.serviceAccounts.signBlob" and auth.get("granted") is True:
            return True
    return False


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_id = event.deep_get("resource", "labels", "project_id", default="<PROJECT_NOT_FOUND>")

    return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]"


def alert_context(event):
    return gcp_alert_context(event)

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.