Detection rules › Kusto

Conditional Access Policy Modified by New User

Severity
medium
Time window
14d
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

Detects a Conditional Access Policy being modified by a user who has not modified a policy in the last 14 days. A threat actor may try to modify policies to weaken the security controls in place. Investigate any change to ensure they are approved. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-infrastructure#conditional-access

MITRE ATT&CK coverage

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: 25a7f951-54b7-4cf5-9862-ebc04306c590
name: Conditional Access Policy Modified by New User
description: |
  'Detects a Conditional Access Policy being modified by a user who has not modified a policy in the last 14 days.
    A threat actor may try to modify policies to weaken the security controls in place.
    Investigate any change to ensure they are approved.
    Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-infrastructure#conditional-access'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  let known_users = (AuditLogs
    | where TimeGenerated between(ago(14d)..ago(1d))
    | where OperationName has "conditional access policy"
    | where Result =~ "success"
    | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
    | summarize by InitiatingUserPrincipalName);
    AuditLogs
    | where TimeGenerated > ago(1d)
    | where OperationName has "conditional access policy"
    | where Result =~ "success"
    | extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
    | extend InitiatingAppId = tostring(InitiatedBy.app.appId)
    | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
    | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
    | extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
    | extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
    | extend CAPolicyName = tostring(TargetResources[0].displayName)
    | where InitiatingUserPrincipalName !in (known_users)
    | extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
    | extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
    | extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
    | project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: InitiatingUserPrincipalName
      - identifier: Name
        columnName: InitiatingAccountName
      - identifier: UPNSuffix
        columnName: InitiatingAccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: InitiatingAadUserId
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: InitiatingIPAddress
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: InitiatingAppId
      - identifier: Name
        columnName: InitiatingAppName
version: 1.1.1
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - Others" ]

Stages and Predicates

Let binding: known_users used in Stage 6

let known_users = (AuditLogs
  | where TimeGenerated between(ago(14d)..ago(1d))
  | where OperationName has "conditional access policy"
  | where Result =~ "success"
  | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
  | summarize by InitiatingUserPrincipalName);

Stage 1: source

AuditLogs

Stage 2: where

| where TimeGenerated > ago(1d)

Stage 3: where

| where OperationName has "conditional access policy"

Stage 4: where

| where Result =~ "success"

Stage 5: extend (7 consecutive steps)

| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppId = tostring(InitiatedBy.app.appId)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend CAPolicyName = tostring(TargetResources[0].displayName)

Stage 6: where

| where InitiatingUserPrincipalName !in (known_users)

Stage 7: extend (3 consecutive steps)

| extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
| extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])

Stage 8: project-reorder

| project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
InitiatingUserPrincipalNameeqknown_usersexcludes:InitiatingUserPrincipalName field:"InitiatingUserPrincipalName" value:"known_users"

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
InitiatingAppNameextend
InitiatingAppIdextend
InitiatingAppServicePrincipalIdextend
InitiatingUserPrincipalNameextend
InitiatingAadUserIdextend
InitiatingIPAddressextend
CAPolicyNameextend
NewPolicyValuesextend
OldPolicyValuesextend
InitiatingAccountNameextend
InitiatingAccountUPNSuffixextend