← Back to SOC feed Coverage →

Failed host logons but success logon to AzureAD

kql MEDIUM Azure-Sentinel
T1078T1110
AADNonInteractiveUserSignInLogsSecurityEventSigninLogsSyslogWindowsEvent
microsoftofficial
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-03-25T03:06:09Z · Confidence: medium

Hunt Hypothesis

Adversaries may be using failed logon attempts to remote hosts as a reconnaissance tactic to identify valid credentials or system vulnerabilities before attempting a successful logon to AzureAD. SOC teams should proactively hunt for this behavior to detect potential credential compromise or reconnaissance activities targeting AzureAD resources.

KQL Query

//Adjust this threshold to fit environment
let signin_threshold = 5; 
//Make a list of IPs with failed Windows host logins above threshold
let win_fails = 
SecurityEvent
| where EventID == 4625
| where LogonType in (10, 7, 3)
| where IpAddress != "-"
| summarize count() by IpAddress
| where count_ > signin_threshold
| summarize make_list(IpAddress);
let wef_fails =
WindowsEvent
| where EventID == 4625
| extend LogonType = tostring(EventData.LogonType)
| where LogonType in (10, 7, 3)
| extend IpAddress = tostring(EventData.IpAddress)
| where IpAddress != "-"
| summarize count() by IpAddress
| where count_ > signin_threshold
| summarize make_list(IpAddress);
//Make a list of IPs with failed *nix host logins above threshold
let nix_fails = 
Syslog
| where Facility contains 'auth' and ProcessName != 'sudo' and SyslogMessage has 'from' and not(SyslogMessage has_any ('Disconnecting', 'Disconnected', 'Accepted', 'disconnect', @'[preauth]'))
| extend SourceIP = extract("(([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.(([0-9]{1,3})))",1,SyslogMessage)
| where SourceIP != "" and SourceIP != "127.0.0.1"
| summarize count() by SourceIP
| where count_ > signin_threshold
| summarize make_list(SourceIP);
//See if any of the IPs with failed host logins hve had a sucessful Azure AD login
let aadFunc = (tableName:string){
table(tableName)
| where ResultType in ("0", "50125", "50140")
| where IPAddress in (win_fails) or IPAddress in (nix_fails) or IPAddress in (wef_fails)
| extend Reason=  "Multiple failed host logins from IP address with successful Azure AD login"
| extend timestamp = TimeGenerated, Type = Type
| extend AccountName = tostring(split(UserPrincipalName, "@")[0]), AccountUPNSuffix = tostring(split(UserPrincipalName, "@")[1])
};
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
union isfuzzy=true aadSignin, aadNonInt

Analytic Rule Definition

id:  1ce5e766-26ab-4616-b7c8-3b33ae321e80
name: Failed host logons but success logon to AzureAD
description: |
  'Identifies a list of IP addresses with a minimum number(default of 5) of failed logon attempts to remote hosts.
  Uses that list to identify any successful logons to Microsoft Entra ID from these IPs within the same timeframe.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
     - SigninLogs
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AADNonInteractiveUserSignInLogs
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: Syslog
    dataTypes:
      - Syslog 
  - connectorId: WindowsSecurityEvents
    dataTypes: 
      - SecurityEvents 
  - connectorId: WindowsForwardedEvents
    dataTypes: 
      - WindowsEvent 
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - CredentialAccess
relevantTechniques:
  - T1078
  - T1110
  
query: |
  //Adjust this threshold to fit environment
  let signin_threshold = 5; 
  //Make a list of IPs with failed Windows host logins above threshold
  let win_fails = 
  SecurityEvent
  | where EventID == 4625
  | where LogonType in (10, 7, 3)
  | where IpAddress != "-"
  | summarize count() by IpAddress
  | where count_ > signin_threshold
  | summarize make_list(IpAddress);
  let wef_fails =
  WindowsEvent
  | where EventID == 4625
  | extend LogonType = tostring(EventData.LogonType)
  | where LogonType in (10, 7, 3)
  | extend IpAddress = tostring(EventData.IpAddress)
  | where IpAddress != "-"
  | summarize count() by IpAddress
  | where count_ > signin_threshold
  | summarize make_list(IpAddress);
  //Make a list of IPs with failed *nix host logins above threshold
  let nix_fails = 
  Syslog
  | where Facility contains 'auth' and ProcessName != 'sudo' and SyslogMessage has 'from' and not(SyslogMessage has_any ('Disconnecting', 'Disconnected', 'Accepted', 'disconnect', @'[preauth]'))
  | extend SourceIP = extract("(([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.(([0-9]{1,3})))",1,SyslogMessage)
  | where SourceIP != "" and SourceIP != "127.0.0.1"
  | summarize count() by SourceIP
  | where count_ > signin_threshold
  | summarize make_list(SourceIP);
  //See if any of the IPs with failed host logins hve had a sucessful Azure AD login
  let aadFunc = (tableName:string){
  table(tableName)
  | where ResultType in ("0", "50125", "50140")
  | where IPAddress in (win_fails) or IPAddress in (nix_fails) or IPAddress in (wef_fails)
  | extend Reason=  "Multiple failed host logins from IP address with successful Azure AD login"
  | extend timestamp = TimeGenerated, Type = Type
  | extend AccountName = tostring(split(UserPrincipalName, "@")[0]), AccountUPNSuffix = tostring(split(UserPrincipalName, "@")[1])
  };
  let aadSignin = aadFunc("SigninLogs");
  let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
  union isfuzzy=true aadSignin, aadNonInt
entityMappings:
  - ent

Required Data Sources

Sentinel TableNotes
AADNonInteractiveUserSignInLogsEnsure this data connector is enabled
SecurityEventEnsure this data connector is enabled
SigninLogsEnsure this data connector is enabled
SyslogEnsure this data connector is enabled
WindowsEventEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Detections/MultipleDataSources/HostAADCorrelation.yaml