Detection rules › Kusto

GCP Audit Logs - Data Access Logging Exemption Added for Principal

Status
available
Severity
high
Time window
1h
Group by
AuthEmail, CallerIpAddress, ExemptedAccountName, ExemptedMember, GCPResourceName, LogName, MethodName, PrincipalEmail, ProjectId, ServiceName, UserAgent
Source
github.com/Azure/Azure-Sentinel

Detects when a principal (user or service account) is exempted from GCP data access audit logging. This is a critical security event as it reduces visibility into privileged operations and may indicate an attempt to hide malicious activity. Adversaries may exempt their accounts from audit logging to evade detection while performing reconnaissance, privilege escalation, or data exfiltration. This rule monitors SetIamPolicy operations that add audit log exemptions for ADMIN_READ, DATA_READ, or DATA_WRITE log types.

MITRE ATT&CK coverage

Telemetry coverage

PlatformRecord / event type
GCPSetIamPolicy

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: b7da45ce-fcc8-43c7-a37c-c08454579d26
name: GCP Audit Logs - Data Access Logging Exemption Added for Principal
description: |
  'Detects when a principal (user or service account) is exempted from GCP data access audit logging.
  This is a critical security event as it reduces visibility into privileged operations and may indicate an attempt to hide malicious activity.
  Adversaries may exempt their accounts from audit logging to evade detection while performing reconnaissance, privilege escalation, or data exfiltration.
  This rule monitors SetIamPolicy operations that add audit log exemptions for ADMIN_READ, DATA_READ, or DATA_WRITE log types.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: GCPAuditLogsDefinition
    dataTypes:
      - GCPAuditLogs
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
  - PrivilegeEscalation
relevantTechniques:
  - T1562.008
  - T1078.004
tags:
  - Cloud Security
  - Audit Logging
  - Defense Evasion
query: |
 GCPAuditLogs
  | where ServiceName == "cloudresourcemanager.googleapis.com"
  | where MethodName == "SetIamPolicy"
  | where GCPResourceType == "project" and Severity == "NOTICE"
  | where isnotempty(ServiceData)
  | extend ServiceDataJson = parse_json(ServiceData)
  | extend PolicyDelta = ServiceDataJson.policyDelta.auditConfigDeltas
  | where isnotempty(PolicyDelta)
  | mv-expand ConfigDelta = PolicyDelta
  | where ConfigDelta.action == "ADD"
  | extend LogType = tostring(ConfigDelta.logType)
  | where LogType in ("ADMIN_READ", "DATA_READ", "DATA_WRITE")
  | extend 
      ExemptedMember = tostring(ConfigDelta.exemptedMember),
      ServiceAffected = tostring(ConfigDelta.service),
      RequestMetadataJson = parse_json(RequestMetadata),
      AuthInfoJson = parse_json(AuthenticationInfo)
  | where isnotempty(ExemptedMember)
  | extend 
      CallerIpAddress = tostring(RequestMetadataJson.callerIp),
      UserAgent = tostring(RequestMetadataJson.callerSuppliedUserAgent),
      AuthEmail = tostring(AuthInfoJson.principalEmail),
      ExemptedAccountName = tostring(split(ExemptedMember, ":")[1])
  | summarize 
      ExemptedLogTypes = make_set(LogType, 10),
      ExemptedServices = make_set(ServiceAffected, 50),
      FirstExemption = min(TimeGenerated),
      LastExemption = max(TimeGenerated)
      by PrincipalEmail, ProjectId, GCPResourceName, ExemptedMember, 
         CallerIpAddress, UserAgent, LogName, ExemptedAccountName, MethodName, ServiceName, AuthEmail
  | extend
      AccountName = tostring(split(PrincipalEmail, "@")[0]), 
      AccountUPNSuffix = tostring(split(PrincipalEmail, "@")[1])
  | project TimeGenerated = LastExemption,
      PrincipalEmail,
      ProjectId,
      ResourceName = GCPResourceName,
      ExemptedMember,
      ExemptedAccountName,
      ExemptedLogTypes,
      ExemptedServices,
      FirstExemption,
      LastExemption,
      CallerIpAddress,
      UserAgent,
      AuthEmail,
      MethodName,
      ServiceName,
      LogName,
      AccountName,
      AccountUPNSuffix
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: PrincipalEmail
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: CallerIpAddress
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: ProjectId
      - identifier: InstanceName
        columnName: ResourceName
customDetails:
  ProjectId: ProjectId
  ExemptedMember: ExemptedMember
  ExemptedAccountName: ExemptedAccountName
  ExemptedLogTypes: ExemptedLogTypes
  ExemptedServices: ExemptedServices
  UserAgent: UserAgent
alertDetailsOverride:
  alertDisplayNameFormat: "GCP Data Access Logging Exemption Added for {{ExemptedAccountName}} by {{PrincipalEmail}} in Service {{ExemptedServices}}"
  alertDescriptionFormat: |-
    Principal {{ExemptedAccountName}} added as exception from Data Access logging in project {{ProjectId}} for Service {{ExemptedServices}}.
    This action reduces audit visibility and may indicate an attempt to evade detection. Verify this change was authorized and investigate any suspicious activity performed by the exempted principal.
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

GCPAuditLogs

Stage 2: where

| where ServiceName == "cloudresourcemanager.googleapis.com"

Stage 3: where

| where MethodName == "SetIamPolicy"

Stage 4: where

| where GCPResourceType == "project" and Severity == "NOTICE"

Stage 5: where

| where isnotempty(ServiceData)

Stage 6: extend

| extend ServiceDataJson = parse_json(ServiceData)

Stage 7: extend

| extend PolicyDelta = ServiceDataJson.policyDelta.auditConfigDeltas

Stage 8: where

| where isnotempty(PolicyDelta)

Stage 9: mv-expand

| mv-expand ConfigDelta = PolicyDelta

Stage 10: where

| where ConfigDelta.action == "ADD"

Stage 11: extend

| extend LogType = tostring(ConfigDelta.logType)

Stage 12: where

| where LogType in ("ADMIN_READ", "DATA_READ", "DATA_WRITE")

Stage 13: extend

| extend 
     ExemptedMember = tostring(ConfigDelta.exemptedMember),
     ServiceAffected = tostring(ConfigDelta.service),
     RequestMetadataJson = parse_json(RequestMetadata),
     AuthInfoJson = parse_json(AuthenticationInfo)

Stage 14: where

| where isnotempty(ExemptedMember)

Stage 15: extend

| extend 
     CallerIpAddress = tostring(RequestMetadataJson.callerIp),
     UserAgent = tostring(RequestMetadataJson.callerSuppliedUserAgent),
     AuthEmail = tostring(AuthInfoJson.principalEmail),
     ExemptedAccountName = tostring(split(ExemptedMember, ":")[1])

Stage 16: summarize

| summarize 
     ExemptedLogTypes = make_set(LogType, 10),
     ExemptedServices = make_set(ServiceAffected, 50),
     FirstExemption = min(TimeGenerated),
     LastExemption = max(TimeGenerated)
     by PrincipalEmail, ProjectId, GCPResourceName, ExemptedMember, 
        CallerIpAddress, UserAgent, LogName, ExemptedAccountName, MethodName, ServiceName, AuthEmail

Stage 17: extend

| extend
     AccountName = tostring(split(PrincipalEmail, "@")[0]), 
     AccountUPNSuffix = tostring(split(PrincipalEmail, "@")[1])

Stage 18: project

| project TimeGenerated = LastExemption,
     PrincipalEmail,
     ProjectId,
     ResourceName = GCPResourceName,
     ExemptedMember,
     ExemptedAccountName,
     ExemptedLogTypes,
     ExemptedServices,
     FirstExemption,
     LastExemption,
     CallerIpAddress,
     UserAgent,
     AuthEmail,
     MethodName,
     ServiceName,
     LogName,
     AccountName,
     AccountUPNSuffix

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
AccountUPNSuffixproject
AuthEmailproject
CallerIpAddressproject
ExemptedAccountNameproject
ExemptedLogTypesproject
ExemptedMemberproject
ExemptedServicesproject
FirstExemptionproject
LastExemptionproject
LogNameproject
MethodNameproject
PrincipalEmailproject
ProjectIdproject
ResourceNameproject
ServiceNameproject
TimeGeneratedproject
UserAgentproject