Query Details

HUNT 09 AAD Prov Cycle Duration Outliers

Query

id: aa1f0009-2009-4209-9209-aadprov-hunt09
name: HUNT-09 Cycle Duration Outliers vs 7d Baseline
description: |
  Provisioning cycles whose DurationMs is > 3x the per-job 7-day median.
  Long cycles can indicate connector throttling under abuse, an attacker
  performing extra work mid-cycle (membership lookups, attribute brute force),
  or schema-drift slowdowns. Short cycles can indicate aborted runs.
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AADProvisioningLogs
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562
query: |
  let Baseline =
      AADProvisioningLogs
      | where TimeGenerated between (ago(7d) .. ago(1d))
      | where isnotempty(CycleId) and isnotnull(DurationMs)
      | summarize MedianDuration = percentile(DurationMs, 50) by JobId
      | where MedianDuration > 0;
  AADProvisioningLogs
  | where TimeGenerated > ago(1d)
  | where isnotempty(CycleId) and isnotnull(DurationMs)
  | extend SPName = tostring(parse_json(ServicePrincipal).Name)
  | summarize
      RecentDuration = avg(DurationMs),
      EventCount     = count(),
      LastSeen       = max(TimeGenerated)
    by CycleId, JobId, SPName
  | join kind=inner (Baseline) on JobId
  | extend Ratio = RecentDuration / MedianDuration
  | where Ratio >= 3.0 or Ratio <= 0.25
  | project CycleId, JobId, SPName, RecentDuration, MedianDuration, Ratio,
            EventCount, LastSeen
  | order by Ratio desc

Explanation

This query is designed to identify unusual provisioning cycles in Azure Active Directory by comparing the duration of recent cycles to a baseline established over the past seven days. Here's a simplified breakdown:

  1. Baseline Calculation:

    • The query first calculates a baseline by looking at provisioning logs from the past 7 days (excluding the last day).
    • It computes the median duration of provisioning cycles for each job.
  2. Recent Data Analysis:

    • It then examines provisioning logs from the last day.
    • For each cycle, it calculates the average duration, counts the number of events, and notes the last time the cycle was seen.
    • It also extracts the name of the service principal involved.
  3. Comparison and Filtering:

    • The query joins the recent data with the baseline data based on the job ID.
    • It calculates the ratio of the recent cycle duration to the median duration from the baseline.
    • It filters for cycles where the duration is either significantly longer (3 times the median) or significantly shorter (less than 25% of the median).
  4. Output:

    • The final output includes details of the cycle ID, job ID, service principal name, recent and median durations, the ratio of these durations, event count, and the last seen time.
    • The results are ordered by the ratio, highlighting the most significant outliers.

This analysis helps identify potential issues such as throttling, unauthorized activities, or aborted runs by flagging cycles with abnormal durations.

Details

David Alonso profile picture

David Alonso

Released: June 1, 2026

Tables

AADProvisioningLogs

Keywords

AzureActiveDirectoryAADProvisioningLogsCycleIdDurationMsJobIdServicePrincipalTimeGenerated

Operators

letbetweenagoisnotemptyisnotnullsummarizepercentilebywhereextendtostringparse_jsonjoinkindonprojectorder bydesc

Actions