Adversaries may modify application redirect URLs to exfiltrate data or redirect users to malicious sites, leveraging compromised credentials or misconfigured applications. SOC teams should proactively hunt for such changes in Azure Sentinel to identify potential credential theft or phishing campaigns early.
KQL Query
AuditLogs
| where Category =~ "ApplicationManagement"
| where Result =~ "success"
| where OperationName =~ 'Update Application'
| where TargetResources has "AppAddress"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| where TargetResources_modifiedProperties.displayName =~ "AppAddress"
| extend Key = tostring(TargetResources_modifiedProperties.displayName)
| extend NewValue = TargetResources_modifiedProperties.newValue
| extend OldValue = TargetResources_modifiedProperties.oldValue
| where isnotempty(Key) and isnotempty(NewValue)
| project-reorder Key, NewValue, OldValue
| extend NewUrls = extract_all('"Address":([^,]*)', tostring(NewValue))
| extend OldUrls = extract_all('"Address":([^,]*)', tostring(OldValue))
| extend AddedUrls = set_difference(NewUrls, OldUrls)
| where array_length(AddedUrls) > 0
| extend UserAgent = iif(tostring(AdditionalDetails[0].key) == "User-Agent", tostring(AdditionalDetails[0].value), "")
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| 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 AddedBy = iif(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName)
| extend TargetAppName = tostring(TargetResources.displayName)
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, TargetAppName, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, AddedUrls, AddedBy, UserAgent
id: a1080fc1-13d1-479b-8340-255f0290d96c
name: Application Redirect URL Update
description: |
'Detects the redirect URL of an app being changed.
Applications associated with URLs not controlled by the organization can pose a security risk.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#application-configuration-changes'
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 Category =~ "ApplicationManagement"
| where Result =~ "success"
| where OperationName =~ 'Update Application'
| where TargetResources has "AppAddress"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| where TargetResources_modifiedProperties.displayName =~ "AppAddress"
| extend Key = tostring(TargetResources_modifiedProperties.displayName)
| extend NewValue = TargetResources_modifiedProperties.newValue
| extend OldValue = TargetResources_modifiedProperties.oldValue
| where isnotempty(Key) and isnotempty(NewValue)
| project-reorder Key, NewValue, OldValue
| extend NewUrls = extract_all('"Address":([^,]*)', tostring(NewValue))
| extend OldUrls = extract_all('"Address":([^,]*)', tostring(OldValue))
| extend AddedUrls = set_difference(NewUrls, OldUrls)
| where array_length(AddedUrls) > 0
| extend UserAgent = iif(tostring(AdditionalDetails[0].key) == "User-Agent", tostring(AdditionalDetails[0].value), "")
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| 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 AddedBy = iif(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName)
| extend TargetAppName = tostring(TargetResources.displayName)
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, TargetAppName, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, AddedUrls, AddedBy, UserAgent
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: AddedUrls
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: Scheduled Job Updates Redirect URL
Description: A scheduled job (e.g., Azure DevOps pipeline or Azure Automation) updates the redirect URL of an application as part of a CI/CD process.
Filter/Exclusion: process.name:*AzureDevOps* OR process.name:*AzureAutomation* OR process.name:*Powershell* with specific job identifiers.
Scenario: Admin Task to Reconfigure App Settings
Description: An administrator manually updates the redirect URL of an enterprise application (e.g., Microsoft 365 App, Okta, or Azure AD app) during routine configuration.
Filter/Exclusion: user.name:*admin* OR user.name:*IT* OR process.name:*PowerShell* with specific admin scripts or tools.
Scenario: Third-Party Integration Update
Description: A third-party service (e.g., Salesforce, ServiceNow, or Zendesk) updates its redirect URL via an API integration, which is part of the organization’s service management setup.
Filter/Exclusion: process.name:*Salesforce* OR process.name:*ServiceNow* OR process.name:*Zendesk* OR process.name:*API* with known integration tools.
Scenario: Internal Tool for URL Testing or Debugging
Description: An internal testing tool (e.g., Postman, curl, or a custom script) is used to test or debug redirect URLs in a controlled environment.
Filter/Exclusion: process.name:*Postman* OR process.name:*curl* OR process.name:*PowerShell* with specific test scripts or IP ranges.
Scenario: Multi-Factor Authentication (MFA) Provider Configuration
Description: An MFA provider (e.g., Azure MFA, Okta