Detection rules › Kusto
End-user consent stopped due to risk-based consent
Detects a user's consent to an OAuth application being blocked due to it being too risky. These events should be investigated to understand why the user attempted to consent to the applicaiton and what other applicaitons they may have consented to. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#end-user-stopped-due-to-risk-based-consent
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Azure | any: Entra ID audit event (any operation) |
Rules detecting the same action
These rules filter on the same operation.
- [Entra ID] Application Assigned Administrator Permissions Immediately After Obtaining Role Management Permissions (Kusto)
- [Entra ID] Application Granted Administrative Permission to Assign Microsoft Entra ID Roles (Kusto)
- Added Credentials to Existing Application (Sigma)
- Added Owner To Application (Sigma)
- Admin promotion after Role Management Application Permission Grant (Kusto)
- App Granted Microsoft Permissions (Sigma)
- App Granted Privileged Delegated Or App Permissions (Sigma)
- Application AppID Uri Configuration Changes (Sigma)
Rule body
id: 009b9bae-23dd-43c4-bcb9-11c4ba7c784a
name: End-user consent stopped due to risk-based consent
description: |
'Detects a user's consent to an OAuth application being blocked due to it being too risky.
These events should be investigated to understand why the user attempted to consent to the applicaiton and what other applicaitons they may have consented to.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#end-user-stopped-due-to-risk-based-consent'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1078.004
tags:
- AADSecOpsGuide
query: |
AuditLogs
| where OperationName has "Consent to application"
| where Result =~ "failure"
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend userAgent = iif(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), tostring(AdditionalDetails[1].value))
| where isnotempty(TargetResources)
| extend TargetAppName = tostring(TargetResources[0].displayName)
| extend TargetAppId = tostring(TargetResources[0].id)
| mv-expand TargetResources[0].modifiedProperties
| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
| where isnotempty(TargetResources_0_modifiedProperties)
| where TargetResources_0_modifiedProperties.displayName =~ "MethodExecutionResult."
| extend TargetPropertyDisplayName = tostring(TargetResources_0_modifiedProperties.displayName)
| extend FailureReason = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
| where FailureReason contains "Risky"
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, OperationName, Result, TargetAppName, TargetAppId, FailureReason, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, userAgent
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: TargetAppId
- identifier: Name
columnName: TargetAppName
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
Stage 1: source
AuditLogs
Stage 2: where
| where OperationName has "Consent to application"
Stage 3: where
| where Result =~ "failure"
Stage 4: extend (4 consecutive steps)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend userAgent = iif(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), tostring(AdditionalDetails[1].value))
Stage 5: where
| where isnotempty(TargetResources)
Stage 6: extend
| extend TargetAppName = tostring(TargetResources[0].displayName)
Stage 7: extend
| extend TargetAppId = tostring(TargetResources[0].id)
Stage 8: mv-expand
| mv-expand TargetResources[0].modifiedProperties
Stage 9: extend
| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
Stage 10: where
| where isnotempty(TargetResources_0_modifiedProperties)
Stage 11: where
| where TargetResources_0_modifiedProperties.displayName =~ "MethodExecutionResult."
Stage 12: extend
| extend TargetPropertyDisplayName = tostring(TargetResources_0_modifiedProperties.displayName)
Stage 13: extend
| extend FailureReason = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
Stage 14: where
| where FailureReason contains "Risky"
Stage 15: extend
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
Stage 16: project-reorder
| project-reorder TimeGenerated, OperationName, Result, TargetAppName, TargetAppId, FailureReason, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, userAgent
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
FailureReason | contains |
| field:"FailureReason" kind:contains value:"Risky" |
OperationName | match |
| field:"OperationName" kind:match value:"Consent to application" |
Result | eq |
| field:"Result" kind:eq value:"failure" |
TargetResources | is_not_null | field:"azure_ad::target_resources" kind:is_not_null | |
TargetResources_0_modifiedProperties | is_not_null | field:"TargetResources_0_modifiedProperties" kind:is_not_null | |
displayName | eq |
| field:"displayName" kind:eq value:"MethodExecutionResult." |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
InitiatingUserPrincipalName | extend |
InitiatingAadUserId | extend |
InitiatingIPAddress | extend |
userAgent | extend |
TargetAppName | extend |
TargetAppId | extend |
TargetResources_0_modifiedProperties | extend |
TargetPropertyDisplayName | extend |
FailureReason | extend |
InitiatingAccountName | extend |
InitiatingAccountUPNSuffix | extend |