Query Details

Device Join Type Anomaly

Query

id: 5a6f1c3e-2a1b-4c9e-9f01-11a2b3c4d507
name: Intune - Device join type anomaly for user
description: |
  Detects a user whose new device registers with a join type (AzureAD Joined / Hybrid /
  Registered / BYOD) not previously observed for that user in the last 30 days. Useful for
  catching unauthorized BYO/registered devices injected into the tenant.
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - Persistence
relevantTechniques:
  - T1098.005
query: |
  let NetworkAllowlist = _GetWatchlist('NetworkAllowlist') | project IPRange = tostring(SearchKey);
  let AllowedRanges = toscalar(NetworkAllowlist | summarize make_list(IPRange));
  let baseline =
      SigninLogs
      | where TimeGenerated between (ago(30d) .. ago(1h))
      | extend TrustType = tostring(DeviceDetail.trustType), UPN = tolower(UserPrincipalName)
      | where isnotempty(TrustType)
      | summarize KnownTypes = make_set(TrustType, 10) by UPN;
  SigninLogs
  | where TimeGenerated > ago(1h)
  | extend TrustType = tostring(DeviceDetail.trustType),
           DeviceId = tostring(DeviceDetail.deviceId),
           DeviceName = tostring(DeviceDetail.displayName),
           UPN = tolower(UserPrincipalName)
  | where isnotempty(TrustType) and ResultType == 0
  | where not(ipv4_is_in_any_range(tostring(IPAddress), AllowedRanges))
  | join kind=leftouter baseline on UPN
  | where isnull(KnownTypes) or not(set_has_element(KnownTypes, TrustType))
  | project TimeGenerated, UPN, TrustType, KnownTypes, DeviceId, DeviceName, IPAddress, AppDisplayName
  | extend AccountCustomEntity = UPN, HostCustomEntity = DeviceName, IPCustomEntity = IPAddress
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled

Explanation

This query is designed to detect anomalies in the types of devices a user registers with in an organization's Azure Active Directory environment. Here's a simple breakdown of what it does:

  1. Purpose: It identifies users who register a new device with a join type (such as AzureAD Joined, Hybrid, Registered, or BYOD) that hasn't been seen for that user in the past 30 days. This can help spot unauthorized devices being added to the network.

  2. Severity: The alert is classified as medium severity, indicating a moderate level of concern.

  3. Data Source: It uses data from Azure Active Directory's SigninLogs.

  4. Frequency and Period: The query runs every hour and looks back over the past 14 days of data.

  5. Logic:

    • It first establishes a baseline of known device join types for each user over the past 30 days.
    • It then checks for any new sign-ins in the last hour where the device join type is not in the user's known types.
    • It excludes any sign-ins from IP addresses that are in an allowed range (as defined by a watchlist).
  6. Output: If a new, unrecognized device join type is detected, it outputs details such as the time of the event, user principal name (UPN), device ID, device name, IP address, and application display name.

  7. Entity Mappings: The query maps the detected anomalies to entities like Account, Host, and IP for further analysis or alerting.

  8. Version and Status: This is version 1.0.0 of the query and is currently available for use.

Overall, this query helps in maintaining security by identifying potentially unauthorized devices trying to access the network.

Details

David Alonso profile picture

David Alonso

Released: April 22, 2026

Tables

SigninLogs

Keywords

IntuneDeviceUserAzureADSigninLogsNetworkIPAddressAccountHostIP

Operators

letprojecttoscalarsummarizemake_listbetweenagoextendtostringtolowerisnotemptymake_setbywhereand==notipv4_is_in_any_rangejoinkindonisnullset_has_elementorprojectextend

Actions