Detection rules › Panther

GCP IAM serviceAccounts.signJwt Privilege Escalation

Severity
high
Log types
GCP.AuditLog
Reference
https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/
Source
github.com/panther-labs/panther-analysis

Detects iam.serviceAccounts.signJwt method for privilege escalation in GCP. This method works by signing well-formed JSON web tokens (JWTs). The script for this method will sign a well-formed JWT and request a new access token belonging to the Service Account with it.

MITRE ATT&CK coverage

TacticTechniques
Privilege EscalationT1548 Abuse Elevation Control Mechanism

Rule body yaml

AnalysisType: rule
Filename: gcp_iam_serviceaccounts_signjwt.py
RuleID: "GCP.IAM.serviceAccounts.signJwt.Privilege.Escalation"
DisplayName: "GCP IAM serviceAccounts.signJwt Privilege Escalation"
Enabled: true
LogTypes:
  - GCP.AuditLog
Reports:
  MITRE ATT&CK:
    - TA0004:T1548
Severity: High
Description:
  Detects iam.serviceAccounts.signJwt method for privilege escalation in GCP. This method works
  by signing well-formed JSON web tokens (JWTs). The script for this method will sign a well-formed JWT and
  request a new access token belonging to the Service Account with it.
Runbook:
  These is not a vulnerability in GCP, this is a vulnerability in how you have configured your GCP environment,
  so it is your responsibility to be aware of these attack vectors and to defend against them. Make sure
  to follow the principle of least-privilege in your environments to help mitigate these security risks.
Reference: https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/
Tests:
  - Name: JWT Signed
    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.signJwt",
                  "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: JWT Not Signed
    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.signJwt",
                  "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",
      }

Detection logic

Condition

protoPayload.methodName eq "SignJwt"
protoPayload.authorizationInfo is_not_null
protoPayload.authorizationInfo array_any

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.methodNameeq
  • SignJwt

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