Detection rules › Kusto

Conditional Access - A Conditional Access policy was put into report-only mode

Severity
low
Time window
5m
Source
github.com/Azure/Azure-Sentinel

A Conditional Access policy was put into report-only mode in Entra ID.

MITRE ATT&CK coverage

Telemetry coverage

PlatformRecord / event type
AzureUpdate conditional access policy

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: 5588de32-73b1-40b9-bddc-4d9e74051859
name: Conditional Access - A Conditional Access policy was put into report-only mode
version: 1.0.1
kind: Scheduled
description: A Conditional Access policy was put into report-only mode in Entra ID.
severity: Low
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
  - T1562.007
query: |+
  // A Conditional Access policy was put into report-only mode.
  AuditLogs
  | where OperationName in ("Update conditional access policy")
  | extend stateOld = extractjson("$.state", tostring(TargetResources[0].modifiedProperties[0].oldValue))
  | extend stateNew = extractjson("$.state", tostring(TargetResources[0].modifiedProperties[0].newValue))
  | where stateOld == "enabled" and stateNew == "enabledForReportingButNotEnforced"
  | extend modifiedBy = tostring(InitiatedBy.user.userPrincipalName)
  | extend accountName = tostring(split(modifiedBy, "@")[0])
  | extend upnSuffix = tostring(split(modifiedBy, "@")[1])
  | project
      TimeGenerated,
      OperationName,
      policy = TargetResources[0].displayName,
      modifiedBy,
      accountName,
      upnSuffix,
      result = Result,
      stateOld,
      stateNew
  | order by TimeGenerated desc
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: accountName
  - identifier: UPNSuffix
    columnName: upnSuffix
suppressionEnabled: false
suppressionDuration: 5h
eventGroupingSettings:
  aggregationKind: AlertPerResult
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: false
    reopenClosedIncident: false
    lookbackDuration: PT5M
    matchingMethod: AllEntities
    groupByEntities: []
    groupByAlertDetails: []
    groupByCustomDetails: []

Stages and Predicates

Stage 1: source

AuditLogs

Stage 2: where

| where OperationName in ("Update conditional access policy")

Stage 3: extend

| extend stateOld = extractjson("$.state", tostring(TargetResources[0].modifiedProperties[0].oldValue))

Stage 4: extend

| extend stateNew = extractjson("$.state", tostring(TargetResources[0].modifiedProperties[0].newValue))

Stage 5: where

| where stateOld == "enabled" and stateNew == "enabledForReportingButNotEnforced"

Stage 6: extend (3 consecutive steps)

| extend modifiedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend accountName = tostring(split(modifiedBy, "@")[0])
| extend upnSuffix = tostring(split(modifiedBy, "@")[1])

Stage 7: project

| project
    TimeGenerated,
    OperationName,
    policy = TargetResources[0].displayName,
    modifiedBy,
    accountName,
    upnSuffix,
    result = Result,
    stateOld,
    stateNew

Stage 8: sort

| order by TimeGenerated desc

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
OperationNameproject
TimeGeneratedproject
accountNameproject
modifiedByproject
policyproject
resultproject
stateNewproject
stateOldproject
upnSuffixproject