Detection rules › Panther

GCP User Added to Privileged Group

Severity
low
Log types
GCP.AuditLog
Tags
Configuration Required
Reference
https://github.com/GoogleCloudPlatform/security-analytics/blob/main/src/2.02/2.02.md
Source
github.com/panther-labs/panther-analysis

A user was added to a group with special previleges

MITRE ATT&CK coverage

Rule body yaml

AnalysisType: rule
Filename: gcp_user_added_to_privileged_group.py
RuleID: "GCP.User.Added.To.Privileged.Group"
DisplayName: "GCP User Added to Privileged Group"
Enabled: false
LogTypes:
  - GCP.AuditLog
Severity: Low
Tags:
  - Configuration Required
Reports:
  MITRE ATT&CK:
    - TA0004:T1078.004 # Privilege Escalation: Valid Accounts: Cloud Accounts
    - TA0004:T1484.001 # Privilege Escalation: Domain or Tenant Policy Modification: Group Policy Modification
Description: A user was added to a group with special previleges
DedupPeriodMinutes: 60
Threshold: 1
Reference: 
  https://github.com/GoogleCloudPlatform/security-analytics/blob/main/src/2.02/2.02.md
Runbook: Determine if the user had been added to the group for legitimate reasons.
Tests:
  - Name: User Added to Privileged Group
    ExpectedResult: true
    Mocks:
      - objectName: get_privileged_groups
        returnValue: '["admins@example.com"]'
    Log:
      {
        "logName": "organizations/123/logs/cloudaudit.googleapis.com%2Factivity",
        "severity": "NOTICE",
        "insertId": "285djodxlmu",
        "resource": {
          "type": "audited_resource",
          "labels": {
            "method": "google.admin.AdminService.addGroupMember",
            "service": "admin.googleapis.com"
          }
        },
        "timestamp": "2022-03-22T22:12:58.916Z",
        "receiveTimestamp": "2022-03-22T22:12:59.439766009Z",
        "protoPayload": {
          "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
          "serviceName": "admin.googleapis.com",
          "methodName": "google.admin.AdminService.addGroupMember",
          "resourceName": "organizations/123/groupSettings",
          "authenticationInfo": {
            "principalEmail": "admin@example.com"
          },
          "requestMetadata": {
            "callerIP": "11.22.33.44",
            "requestAttributes": {},
            "destinationAttributes": {}
          },
          "metadata": {
            "@type": "type.googleapis.com/ccc_hosted_reporting.ActivityProto",
            "activityId": {
              "timeUsec": "1647987178916000",
              "uniqQualifier": "-8614641986436885296"
            },
            "event": [
              {
                "eventName": "ADD_GROUP_MEMBER",
                "eventType": "GROUP_SETTINGS",
                "parameter": [
                  {
                    "label": "LABEL_OPTIONAL",
                    "value": "test-user@example.com",
                    "type": "TYPE_STRING",
                    "name": "USER_EMAIL"
                  },
                  {
                    "type": "TYPE_STRING",
                    "value": "admins@example.com",
                    "label": "LABEL_OPTIONAL",
                    "name": "GROUP_EMAIL"
                  }
                ]
              }
            ]
          }
        }
      }
  - Name: User Added to Non-Privileged Group
    ExpectedResult: false
    Log:
      {
        "logName": "organizations/123/logs/cloudaudit.googleapis.com%2Factivity",
        "severity": "NOTICE",
        "insertId": "285djodxlmu",
        "resource": {
          "type": "audited_resource",
          "labels": {
            "method": "google.admin.AdminService.addGroupMember",
            "service": "admin.googleapis.com"
          }
        },
        "timestamp": "2022-03-22T22:12:58.916Z",
        "receiveTimestamp": "2022-03-22T22:12:59.439766009Z",
        "protoPayload": {
          "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
          "serviceName": "admin.googleapis.com",
          "methodName": "google.admin.AdminService.addGroupMember",
          "resourceName": "organizations/123/groupSettings",
          "authenticationInfo": {
            "principalEmail": "admin@example.com"
          },
          "requestMetadata": {
            "callerIP": "11.22.33.44",
            "requestAttributes": {},
            "destinationAttributes": {}
          },
          "metadata": {
            "@type": "type.googleapis.com/ccc_hosted_reporting.ActivityProto",
            "activityId": {
              "timeUsec": "1647987178916000",
              "uniqQualifier": "-8614641986436885296"
            },
            "event": [
              {
                "eventName": "ADD_GROUP_MEMBER",
                "eventType": "GROUP_SETTINGS",
                "parameter": [
                  {
                    "label": "LABEL_OPTIONAL",
                    "value": "test-user@example.com",
                    "type": "TYPE_STRING",
                    "name": "USER_EMAIL"
                  },
                  {
                    "type": "TYPE_STRING",
                    "value": "normies@example.com",
                    "label": "LABEL_OPTIONAL",
                    "name": "GROUP_EMAIL"
                  }
                ]
              }
            ]
          }
        }
      }

Detection logic

Rule logic imperative Python

from panther_base_helpers import key_value_list_to_dict
PRIVILEGED_GROUPS = {
}
USER_EMAIL = ""
GROUP_EMAIL = ""
def rule(event):
    events = event.deep_get("protoPayload", "metadata", "event", default=[])
    for event_ in events:
        if event_.get("eventname") != "ADD_GROUP_MEMBER":
            continue
        params = key_value_list_to_dict(event_.get("parameter", []), "name", "value")
        global USER_EMAIL, GROUP_EMAIL
        USER_EMAIL = params.get("USER_EMAIL")
        GROUP_EMAIL = params.get("GROUP_EMAIL")
        if GROUP_EMAIL in get_privileged_groups():
            return True
    return False
def title(event):
    actor = event.deep_get("actor", "email", default="")
    global USER_EMAIL, GROUP_EMAIL
    return f"{actor} has added {USER_EMAIL} to the privileged group {GROUP_EMAIL}"
def get_privileged_groups():
    return PRIVILEGED_GROUPS

The parser cannot express this rule's logic as a field filter; the imperative Python above is the detection.

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
emailactor.email