Guest users being converted to member accounts may indicate an adversary attempting to elevate privileges by granting full access to a compromised account. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential lateral movement or persistence tactics early.
KQL Query
let timeframe = 1d;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName =~ "Update user"
| where Result =~ "success"
| mv-expand ModProp = TargetResources[0].modifiedProperties
| where tostring(ModProp.displayName) =~ "UserType"
| extend OldUserType = tostring(ModProp.oldValue)
| extend NewUserType = tostring(ModProp.newValue)
| where OldUserType has "Guest" and NewUserType has "Member"
| extend TargetUpn = tostring(TargetResources[0].userPrincipalName)
| extend TargetId = tostring(TargetResources[0].id)
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(TargetUpn has "@",
tostring(split(TargetUpn, "@")[0]), TargetUpn)
| extend AccountUPNSuffix = iff(TargetUpn has "@",
tostring(split(TargetUpn, "@")[1]), "")
| project
TimeGenerated,
TargetUpn,
AccountName,
AccountUPNSuffix,
TargetId,
OldUserType,
NewUserType,
Actor,
ActorIp,
CorrelationId
| sort by TimeGenerated desc
id: d7684f21-18c0-4597-b79f-1ae5f2c7ab86
name: Guest user account type changed to member
description: Identifies Entra ID user accounts converted from Guest to Member type, which grants full member-level access and may indicate an attacker elevating a compromised guest account to persistent tenant access.
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
tactics:
- Persistence
relevantTechniques:
- T1098
query: |
let timeframe = 1d;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName =~ "Update user"
| where Result =~ "success"
| mv-expand ModProp = TargetResources[0].modifiedProperties
| where tostring(ModProp.displayName) =~ "UserType"
| extend OldUserType = tostring(ModProp.oldValue)
| extend NewUserType = tostring(ModProp.newValue)
| where OldUserType has "Guest" and NewUserType has "Member"
| extend TargetUpn = tostring(TargetResources[0].userPrincipalName)
| extend TargetId = tostring(TargetResources[0].id)
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(TargetUpn has "@",
tostring(split(TargetUpn, "@")[0]), TargetUpn)
| extend AccountUPNSuffix = iff(TargetUpn has "@",
tostring(split(TargetUpn, "@")[1]), "")
| project
TimeGenerated,
TargetUpn,
AccountName,
AccountUPNSuffix,
TargetId,
OldUserType,
NewUserType,
Actor,
ActorIp,
CorrelationId
| sort by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetUpn
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ActorIp
version: 1.0.0
metadata:
source:
kind: Community
author:
name: descambiado
support:
tier: Community
categories:
domains: [ "Security - Threat Protection", "Identity" ]
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: Scheduled job to convert guest users to members for onboarding
Filter/Exclusion: Check for the presence of a known onboarding script or job (e.g., Azure Automation Runbook or Power Automate flow) that modifies user types. Use a filter like:
(user_type_change_from_guest_to_member) AND (process_name != "AzureAutomationWorker" OR process_name != "PowerAutomateJob")
Scenario: Admin manually adds a guest user as a member during user provisioning
Filter/Exclusion: Filter out events where the user is added by a known admin or service account (e.g., [email protected] or [email protected]). Use:
(user_type_change_from_guest_to_member) AND (user_principal_name != "[email protected]" AND user_principal_name != "[email protected]")
Scenario: Azure AD Connect sync updates user type during directory synchronization
Filter/Exclusion: Exclude changes made by Azure AD Connect during sync. Use a filter like:
(user_type_change_from_guest_to_member) AND (source_system != "AzureADConnect")
Scenario: User migration from guest to member during a tenant merger or acquisition
Filter/Exclusion: Identify migration tasks (e.g., AzureMigrateTool.exe or Microsoft365MigrationTool) and exclude changes initiated by these tools:
(user_type_change_from_guest_to_member) AND (process_name != "AzureMigrateTool.exe" AND process_name != "Microsoft365MigrationTool.exe")
Scenario: User is temporarily promoted to member for access to a shared resource
Filter/Exclusion: Filter out changes made by a known shared