User State changed from Guest to Member


Description

'Detects when a guest account in a tenant is converted to a member of the tenant. Monitoring guest accounts and the access they are provided is important to detect potential account abuse. Accounts converted to members should be investigated to ensure the activity was legitimate. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins'

Query · kql

AuditLogs
  | where OperationName =~ "Update user"
  | where Result =~ "success"
  | mv-expand TargetResources
  | mv-expand TargetResources.modifiedProperties
  | where TargetResources_modifiedProperties.displayName =~ "TargetId.UserType"
  | extend UpdatingAppName = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
  | extend UpdatingServicePrincipalId = tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalId)
  | extend UpdatingUserPrincipalName = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
  | extend UpdatingUserAadUserId = tostring(parse_json(tostring(InitiatedBy.user)).id)
  | extend UpdatingUserIPAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
  | extend UpdatingUser = iif(isnotempty(UpdatingServicePrincipalId), UpdatingServicePrincipalId, UpdatingUserPrincipalName)
  | extend UpdatedUserPrincipalName = tostring(TargetResources.userPrincipalName)
  | project-reorder TimeGenerated, UpdatedUserPrincipalName, UpdatingUser
  | where parse_json(tostring(TargetResources_modifiedProperties.newValue)) =~ "\"Member\"" and parse_json(tostring(TargetResources_modifiedProperties.oldValue)) =~ "\"Guest\""
  | extend InitiatingAccountName = tostring(split(UpdatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(UpdatingUserPrincipalName, "@")[1])
  | extend TargetAccountName = tostring(split(UpdatedUserPrincipalName, "@")[0]), TargetAccountUPNSuffix = tostring(split(UpdatedUserPrincipalName, "@")[1])
Raw source User State changed from Guest to Member · KQL
Esc
Published by Azure/Azure-Sentinel ↗, licensed under MIT ↗. Reproduced here unmodified.
id: a09a0b8e-30fe-4ebf-94a0-cffe50f579cd
name: User State changed from Guest to Member
description: |
  'Detects when a guest account in a tenant is converted to a member of the tenant.
    Monitoring guest accounts and the access they are provided is important to detect potential account abuse.
    Accounts converted to members should be investigated to ensure the activity was legitimate.
    Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Persistence
relevantTechniques:
  - T1098
tags:
  - AADSecOpsGuide
query: |
  AuditLogs
    | where OperationName =~ "Update user"
    | where Result =~ "success"
    | mv-expand TargetResources
    | mv-expand TargetResources.modifiedProperties
    | where TargetResources_modifiedProperties.displayName =~ "TargetId.UserType"
    | extend UpdatingAppName = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
    | extend UpdatingServicePrincipalId = tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalId)
    | extend UpdatingUserPrincipalName = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
    | extend UpdatingUserAadUserId = tostring(parse_json(tostring(InitiatedBy.user)).id)
    | extend UpdatingUserIPAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
    | extend UpdatingUser = iif(isnotempty(UpdatingServicePrincipalId), UpdatingServicePrincipalId, UpdatingUserPrincipalName)
    | extend UpdatedUserPrincipalName = tostring(TargetResources.userPrincipalName)
    | project-reorder TimeGenerated, UpdatedUserPrincipalName, UpdatingUser
    | where parse_json(tostring(TargetResources_modifiedProperties.newValue)) =~ "\"Member\"" and parse_json(tostring(TargetResources_modifiedProperties.oldValue)) =~ "\"Guest\""
    | extend InitiatingAccountName = tostring(split(UpdatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(UpdatingUserPrincipalName, "@")[1])
    | extend TargetAccountName = tostring(split(UpdatedUserPrincipalName, "@")[0]), TargetAccountUPNSuffix = tostring(split(UpdatedUserPrincipalName, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: UpdatingAppName
      - identifier: AadUserId
        columnName: UpdatingServicePrincipalId
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UpdatingUserPrincipalName
      - identifier: Name
        columnName: InitiatingAccountName
      - identifier: UPNSuffix
        columnName: InitiatingAccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: UpdatingUserAadUserId
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UpdatedUserPrincipalName
      - identifier: Name
        columnName: TargetAccountName
      - identifier: UPNSuffix
        columnName: TargetAccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: UpdatingUserIPAddress
version: 1.1.0
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - Others", "Identity" ]

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.