Suspicious linking of existing user to external User
Id | 22a320c2-e1e5-4c74-a35b-39fc9cdcf859 |
Rulename | Suspicious linking of existing user to external User |
Description | This query will detect when an attempt is made to update an existing user and link it to an guest or external identity. These activities are unusual and such linking of external identities should be investigated. In some cases you may see internal Entra ID sync accounts (Sync_) do this which may be benign |
Severity | Medium |
Tactics | PrivilegeEscalation |
Techniques | T1078.004 |
Required data connectors | AzureActiveDirectory |
Kind | Scheduled |
Query frequency | 1d |
Query period | 1d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/SuspiciousLinkingofExternalIdtoExistingUsers.yaml |
Version | 1.1.0 |
Arm template | 22a320c2-e1e5-4c74-a35b-39fc9cdcf859.json |
AuditLogs
| where OperationName=~ "Update user"
| where Result =~ "success"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend displayName = tostring(TargetResources_modifiedProperties.displayName),
TargetUPN_oldValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))[0]),
TargetUPN_newValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))[0])
| where displayName == "UserPrincipalName" and TargetUPN_oldValue !has "#EXT" and TargetUPN_newValue has "#EXT"
| 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 InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| summarize arg_max(TimeGenerated, *) by CorrelationId
| project-reorder TimeGenerated, InitiatedBy, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, TargetUPN_oldValue, TargetUPN_newValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(TargetUPN_oldValue, "@")[0]), TargetUPNSuffix = tostring(split(TargetUPN_oldValue, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetUPN_oldValue
- identifier: Name
columnName: TargetAccountName
- identifier: UPNSuffix
columnName: TargetUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
name: Suspicious linking of existing user to external User
tactics:
- PrivilegeEscalation
severity: Medium
triggerThreshold: 0
relevantTechniques:
- T1078.004
id: 22a320c2-e1e5-4c74-a35b-39fc9cdcf859
version: 1.1.0
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/SuspiciousLinkingofExternalIdtoExistingUsers.yaml
queryFrequency: 1d
triggerOperator: gt
query: |
AuditLogs
| where OperationName=~ "Update user"
| where Result =~ "success"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend displayName = tostring(TargetResources_modifiedProperties.displayName),
TargetUPN_oldValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))[0]),
TargetUPN_newValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))[0])
| where displayName == "UserPrincipalName" and TargetUPN_oldValue !has "#EXT" and TargetUPN_newValue has "#EXT"
| 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 InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| summarize arg_max(TimeGenerated, *) by CorrelationId
| project-reorder TimeGenerated, InitiatedBy, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, TargetUPN_oldValue, TargetUPN_newValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(TargetUPN_oldValue, "@")[0]), TargetUPNSuffix = tostring(split(TargetUPN_oldValue, "@")[1])
tags:
- GuestorExternalIdentities
description: |
' This query will detect when an attempt is made to update an existing user and link it to an guest or external identity. These activities are unusual and such linking of external
identities should be investigated. In some cases you may see internal Entra ID sync accounts (Sync_) do this which may be benign'
metadata:
source:
kind: Community
categories:
domains:
- Security - Others
- Identity
author:
name: Microsoft Security Research
support:
tier: Community
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryPeriod: 1d
kind: Scheduled
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/22a320c2-e1e5-4c74-a35b-39fc9cdcf859')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/22a320c2-e1e5-4c74-a35b-39fc9cdcf859')]",
"properties": {
"alertRuleTemplateName": "22a320c2-e1e5-4c74-a35b-39fc9cdcf859",
"customDetails": null,
"description": "' This query will detect when an attempt is made to update an existing user and link it to an guest or external identity. These activities are unusual and such linking of external \nidentities should be investigated. In some cases you may see internal Entra ID sync accounts (Sync_) do this which may be benign'\n",
"displayName": "Suspicious linking of existing user to external User",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "InitiatingAppName",
"identifier": "Name"
},
{
"columnName": "InitiatingAppServicePrincipalId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "InitiatingUserPrincipalName",
"identifier": "FullName"
},
{
"columnName": "InitiatingAccountName",
"identifier": "Name"
},
{
"columnName": "InitiatingAccountUPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "InitiatingAadUserId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "TargetUPN_oldValue",
"identifier": "FullName"
},
{
"columnName": "TargetAccountName",
"identifier": "Name"
},
{
"columnName": "TargetUPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "InitiatingIPAddress",
"identifier": "Address"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/SuspiciousLinkingofExternalIdtoExistingUsers.yaml",
"query": "AuditLogs\n| where OperationName=~ \"Update user\" \n| where Result =~ \"success\" \n| mv-expand TargetResources \n| mv-expand TargetResources.modifiedProperties \n| extend displayName = tostring(TargetResources_modifiedProperties.displayName), \nTargetUPN_oldValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))[0]), \nTargetUPN_newValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))[0])\n| where displayName == \"UserPrincipalName\" and TargetUPN_oldValue !has \"#EXT\" and TargetUPN_newValue has \"#EXT\"\n| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)\n| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)\n| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))\n| summarize arg_max(TimeGenerated, *) by CorrelationId\n| project-reorder TimeGenerated, InitiatedBy, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, TargetUPN_oldValue, TargetUPN_newValue\n| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, \"@\")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, \"@\")[1])\n| extend TargetAccountName = tostring(split(TargetUPN_oldValue, \"@\")[0]), TargetUPNSuffix = tostring(split(TargetUPN_oldValue, \"@\")[1])\n",
"queryFrequency": "P1D",
"queryPeriod": "P1D",
"severity": "Medium",
"subTechniques": [
"T1078.004"
],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"PrivilegeEscalation"
],
"tags": [
"GuestorExternalIdentities"
],
"techniques": [
"T1078"
],
"templateVersion": "1.1.0",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}