← Back to SOC feed Coverage →

Anomolous Sign Ins Based on Time

kql MEDIUM Azure-Sentinel
T1078.004
IdentityInfoSigninLogs
backdoorhuntingmicrosoftofficial
This rule was pulled from an open-source repository and enriched with AI. Validate in a test environment before deploying to production.
View original rule at Azure-Sentinel →
Retrieved: 2026-06-02T11:00:00Z · Confidence: medium

Hunt Hypothesis

Adversaries may be using automated tools or scripts to perform excessive sign-in attempts during off-hours to evade detection. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential credential compromise or unauthorized access attempts.

KQL Query

let admins = (IdentityInfo
| where AssignedRoles contains "Admin"
| summarize by tolower(AccountUPN));
let ts_data = (SigninLogs
| where TimeGenerated > ago(14d)
| extend AccountUPN = tolower(UserPrincipalName)
| where AccountUPN in (admins)
| make-series count() on TimeGenerated step 1h by UserPrincipalName
| extend series_decompose(count_)
| extend NoLogons = count_);
let TimeSeriesAlerts=ts_data
| extend (anomalies, score, baseline) = series_decompose_anomalies(count_, 2.5, -1, 'linefit',0, 'ctukey', 3)
| mv-expand NoLogons to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double),score to typeof(double), baseline to typeof(long)
| where anomalies > 0
| where NoLogons > 15
| project UserPrincipalName, TimeGenerated, NoLogons, baseline, anomalies, score;
TimeSeriesAlerts
| join kind=inner (
SigninLogs
| summarize ResultTypeCount=count(),ResultTypes=make_set(ResultType), Locations=make_set(Location), Apps=make_set(AppDisplayName), Ips=make_set( IPAddress) by UserPrincipalName, bin(TimeGenerated, 1h)
) on UserPrincipalName, TimeGenerated
| summarize AnomolyTimes = make_set(TimeGenerated), Ips = make_set(Ips), Apps = make_set(Apps), sum(anomalies), Locations=make_set(Locations) by UserPrincipalName
| sort by sum_anomalies desc

Analytic Rule Definition

id: 8ed5b8f1-a43a-49dc-847c-e44d7a590c17
name: Anomolous Sign Ins Based on Time
description: |
  'Identifies anomolies in signin events based on the volume of signin events over time. Use this to identify suspicious authentication patterns such as spikes in activity or out of hours events.
  Ref : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor'
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs
  - connectorId: BehaviorAnalytics
    dataTypes:
      - IdentityInfo
tactics:
  - InitialAccess
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  let admins = (IdentityInfo
  | where AssignedRoles contains "Admin"
  | summarize by tolower(AccountUPN));
  let ts_data = (SigninLogs
  | where TimeGenerated > ago(14d)
  | extend AccountUPN = tolower(UserPrincipalName)
  | where AccountUPN in (admins)
  | make-series count() on TimeGenerated step 1h by UserPrincipalName
  | extend series_decompose(count_)
  | extend NoLogons = count_);
  let TimeSeriesAlerts=ts_data
  | extend (anomalies, score, baseline) = series_decompose_anomalies(count_, 2.5, -1, 'linefit',0, 'ctukey', 3)
  | mv-expand NoLogons to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double),score to typeof(double), baseline to typeof(long)
  | where anomalies > 0
  | where NoLogons > 15
  | project UserPrincipalName, TimeGenerated, NoLogons, baseline, anomalies, score;
  TimeSeriesAlerts
  | join kind=inner (
  SigninLogs
  | summarize ResultTypeCount=count(),ResultTypes=make_set(ResultType), Locations=make_set(Location), Apps=make_set(AppDisplayName), Ips=make_set( IPAddress) by UserPrincipalName, bin(TimeGenerated, 1h)
  ) on UserPrincipalName, TimeGenerated
  | summarize AnomolyTimes = make_set(TimeGenerated), Ips = make_set(Ips), Apps = make_set(Apps), sum(anomalies), Locations=make_set(Locations) by UserPrincipalName
  | sort by sum_anomalies desc
version: 1.0.1

Required Data Sources

Sentinel TableNotes
IdentityInfoEnsure this data connector is enabled
SigninLogsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Hunting Queries/MultipleDataSources/AnomolousSignInsBasedonTime.yaml