Adversaries may be exploiting newly created or reactivated accounts to gain unauthorized access, leveraging these accounts to move laterally or exfiltrate data. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential compromise of dormant accounts that could be used as entry points for advanced threats.
KQL Query
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = starttime - 14d;
let midtime = starttime - 7d;
let SigninsSummary = SigninLogs
| where TimeGenerated between(starttime..endtime)
// successful sign-in only
| where ResultType == 0
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), SigninLogs_ItemIds = make_set(_ItemId), loginCountToday=count() by UserPrincipalName, UserId, UserType, IPAddress
| join kind=leftanti (
SigninLogs
// historical successful sign-in
| where TimeGenerated between(lookback..starttime)
| where ResultType == 0
| summarize by UserId
) on UserId;
// need to help BehaviorAnalytics query to limit only to Signins we are interested in
let onlyInactive = SigninsSummary | summarize make_set(UserPrincipalName);
let SigninsWithUEBA =
BehaviorAnalytics
| where TimeGenerated between(starttime..endtime)
| where ActionType in ('Sign-in','InteractiveLogon')
| where UserPrincipalName in~ (onlyInactive)
| extend ActivityInsights = parse_xml(ActivityInsights)
// only looked where FirstTimeUser items are True
| where ActivityInsights matches regex '\"FirstTimeUser([A-Za-z0-9]+)\":\"True\"'
// only exclude when Uncommon Among Peers is false as this helps remove expected first time usage, exception is we always show FirstTimeUserConnectedFromCountry == True
// also always keep InvestigationPriority if 1 or more
| where (not(ActivityInsights.FirstTimeUserUsedApp == 'True' and ActivityInsights.AppUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
| where (not(ActivityInsights.FirstTimeUserConnectedViaBrowser == 'True' and ActivityInsights.BrowserUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
| where (not(ActivityInsights.FirstTimeUserAccessedResource == 'True' and ActivityInsights.ResourceUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
// for ISP, it makes more sense to exclude if Uncommon in Tenant or Uncommon among peers is false.
| where (not(ActivityInsights.FirstTimeUserConnectedViaISP == 'True' and (ActivityInsights.ISPUncommonlyUsedInTenant == 'False' or ActivityInsights.ISPUncommonlyUsedAmongPeers == 'False')) or InvestigationPriority > 0)
| extend UEBA_Insights = pack_dictionary("TimeGenerated", TimeGenerated, "ActivityInsights", ActivityInsights, "UsersInsights", UsersInsights, "DevicesInsights", DevicesInsights)
| summarize UEBA_ItemIds = make_set(_ItemId), UEBA_SourceRecordIds = make_set(SourceRecordId), UEBA_Insights = make_set(UEBA_Insights) by
UEBA_UserPrincipalName = UserPrincipalName, JoinedWithType = Type, UEBA_ActionType = ActionType, UEBA_SourceIPAddress = SourceIPAddress, UEBA_SourceIPLocation = SourceIPLocation, UEBA_InvestigationPriority = InvestigationPriority
| extend UEBA_Info = pack_dictionary("UEBA_Insights", UEBA_Insights, "UEBA_ItemIds", UEBA_ItemIds, "UEBA_SourceRecordIds", UEBA_SourceRecordIds)
| project-away UEBA_ItemIds, UEBA_SourceRecordIds, UEBA_Insights
| join kind=inner (
SigninsSummary
) on $left.UEBA_UserPrincipalName == $right.UserPrincipalName, $left.UEBA_SourceIPAddress == $right.IPAddress
| project-reorder StartTime, EndTime, UserPrincipalName, UserId, IPAddress, UserType, loginCountToday, JoinedWithType
;
SigninsWithUEBA
| join kind= leftanti (
// filter out newly created user accounts from last 7 days
AuditLogs
| where TimeGenerated between(midtime..endtime)
| where OperationName == "Add user"
| summarize by NewUserId = tostring(TargetResources[0].id)
) on $left.UserId == $right.NewUserId
| extend timestamp = StartTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
id: 847c2652-547d-4d5f-9b71-d2f8d81eac62
name: Inactive or new account signins
description: |
'Query for new sign-ins from stale/inactive accounts. UEBA filters based on ActivityInsights. Results for accounts created in the last 7 days are filtered out.'
description_detailed: |
'Query for accounts seen signing in for the first time. These could be associated with stale/inactive accounts that ought to have been deleted
but were not and may have been subsequently compromised.
UEBA is used to filter out based on ActivityInsights where we see certain First Time User events identified as true.
Results for user accounts created in the last 7 days are filtered out.'
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
- AuditLogs
- connectorId: BehaviorAnalytics
dataTypes:
- BehaviorAnalytics
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = starttime - 14d;
let midtime = starttime - 7d;
let SigninsSummary = SigninLogs
| where TimeGenerated between(starttime..endtime)
// successful sign-in only
| where ResultType == 0
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), SigninLogs_ItemIds = make_set(_ItemId), loginCountToday=count() by UserPrincipalName, UserId, UserType, IPAddress
| join kind=leftanti (
SigninLogs
// historical successful sign-in
| where TimeGenerated between(lookback..starttime)
| where ResultType == 0
| summarize by UserId
) on UserId;
// need to help BehaviorAnalytics query to limit only to Signins we are interested in
let onlyInactive = SigninsSummary | summarize make_set(UserPrincipalName);
let SigninsWithUEBA =
BehaviorAnalytics
| where TimeGenerated between(starttime..endtime)
| where ActionType in ('Sign-in','InteractiveLogon')
| where UserPrincipalName in~ (onlyInactive)
| extend ActivityInsights = parse_xml(ActivityInsights)
// only looked where FirstTimeUser items are True
| where ActivityInsights matches regex '\"FirstTimeUser([A-Za-z0-9]+)\":\"True\"'
// only exclude when Uncommon Among Peers is false as this helps remove expected first time usage, exception is we always show FirstTimeUserConnectedFromCountry == True
// also always keep InvestigationPriority if 1 or more
| where (not(ActivityInsights.FirstTimeUserUsedApp == 'True' and ActivityInsights.AppUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
| where (not(ActivityInsights.FirstTimeUserConnectedViaBrowser == 'True' and ActivityInsights.BrowserUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
| where (not(ActivityInsights.FirstTimeUserAccessedResource == 'True' and ActivityInsights.ResourceUncommonlyUsedAmongPeers == 'False') or InvestigationPriority > 0)
// for ISP, it makes more sense to exclude if Uncommon in Tenant or Uncommon among pee
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
BehaviorAnalytics | Ensure this data connector is enabled |
SigninLogs | Ensure this data connector is enabled |
Scenario: Scheduled System Maintenance Job
Description: A legitimate scheduled job (e.g., Azure DevOps pipeline, Jenkins CI/CD, or AWS Lambda) runs under a new service account and triggers a sign-in.
Filter/Exclusion: Exclude sign-ins from known system or service accounts (e.g., svc-azure-devops, jenkins, lambda-execution-role) using the accountType or userPrincipalName field.
Scenario: Admin Task Using a Temporary Service Account
Description: An admin creates a temporary account (e.g., temp-admin-20240515) to perform a one-time task (e.g., migrating data, configuring a service), which results in a sign-in.
Filter/Exclusion: Exclude sign-ins from accounts created within the last 7 days using the accountCreatedTime field, or apply a custom tag like temp-account to these accounts.
Scenario: User Sign-in After a Long Absence (Not Stale)
Description: A user who was previously active but took a long leave (e.g., 6 months) returns and signs in, triggering the rule.
Filter/Exclusion: Exclude sign-ins from users who have been active in the last 90 days using the lastSignInTime field, or use a custom field like userActivityStatus.
Scenario: Automated Backup or Sync Process
Description: A backup tool (e.g., Veeam, Acronis, or Azure Backup) runs under a dedicated backup account and signs in to access data.
Filter/Exclusion: Exclude sign-ins from backup accounts (e.g., backup-service-account) using the userPrincipalName or accountType field.
**Scenario: User Sign-in via Multi-Factor Authentication (MFA