Multiple Microsoft 365 User Account Lockouts in Short Time Window

Detects a burst of Microsoft 365 user account lockouts within a short 5-minute window. A high number of IdsLocked login errors across multiple user accounts may indicate brute-force attempts for the same users resulting in lockouts.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2025/05/10"
  3integration = ["o365"]
  4maturity = "production"
  5min_stack_version = "8.17.0"
  6min_stack_comments = "Elastic ES|QL values aggregation is more performant in 8.16.5 and above."
  7updated_date = "2025/05/10"
  8
  9[rule]
 10author = ["Elastic"]
 11description = """
 12Detects a burst of Microsoft 365 user account lockouts within a short 5-minute window. A high number of IdsLocked login
 13errors across multiple user accounts may indicate brute-force attempts for the same users resulting in lockouts.
 14"""
 15from = "now-9m"
 16language = "esql"
 17license = "Elastic License v2"
 18name = "Multiple Microsoft 365 User Account Lockouts in Short Time Window"
 19note = """## Triage and Analysis
 20
 21### Investigating Multiple Microsoft 365 User Account Lockouts in Short Time Window
 22
 23Detects a burst of Microsoft 365 user account lockouts within a short 5-minute window. A high number of IdsLocked login errors across multiple user accounts may indicate brute-force attempts for the same users resulting in lockouts.
 24
 25This rule uses ES|QL aggregations and thus has dynamically generated fields. Correlation of the values in the alert document may need to be performed to the original sign-in and Graph events for further context.
 26
 27### Investigation Steps
 28
 29- Review the `user_id_list`: Are specific naming patterns targeted (e.g., admin, helpdesk)?
 30- Examine `ip_list` and `source_orgs`: Look for suspicious ISPs or hosting providers.
 31- Check `duration_seconds`: A very short window with a high lockout rate often indicates automation.
 32- Confirm lockout policy thresholds with IAM or Entra ID admins. Did the policy trigger correctly?
 33- Use the `first_seen` and `last_seen` values to pivot into related authentication or audit logs.
 34- Correlate with any recent detection of password spraying or credential stuffing activity.
 35- Review the `request_type` field to identify which authentication methods were used (e.g., OAuth, SAML, etc.).
 36- Check for any successful logins from the same IP or ASN after the lockouts.
 37
 38### False Positive Analysis
 39
 40- Automated systems with stale credentials may cause repeated failed logins.
 41- Legitimate bulk provisioning or scripted tests could unintentionally cause account lockouts.
 42- Red team exercises or penetration tests may resemble the same lockout pattern.
 43- Some organizations may have a high volume of lockouts due to user behavior or legacy systems.
 44
 45### Response Recommendations
 46
 47- Notify affected users and confirm whether activity was expected or suspicious.
 48- Lock or reset credentials for impacted accounts.
 49- Block the source IP(s) or ASN temporarily using conditional access or firewall rules.
 50- Strengthen lockout and retry delay policies if necessary.
 51- Review the originating application(s) involved via `request_types`.
 52"""
 53references = [
 54    "https://learn.microsoft.com/en-us/security/operations/incident-response-playbook-password-spray",
 55    "https://learn.microsoft.com/en-us/purview/audit-log-detailed-properties",
 56    "https://securityscorecard.com/research/massive-botnet-targets-m365-with-stealthy-password-spraying-attacks/",
 57    "https://github.com/0xZDH/Omnispray",
 58    "https://github.com/0xZDH/o365spray",
 59]
 60risk_score = 47
 61rule_id = "de67f85e-2d43-11f0-b8c9-f661ea17fbcc"
 62severity = "medium"
 63tags = [
 64    "Domain: Cloud",
 65    "Domain: SaaS",
 66    "Data Source: Microsoft 365",
 67    "Data Source: Microsoft 365 Audit Logs",
 68    "Use Case: Threat Detection",
 69    "Use Case: Identity and Access Audit",
 70    "Tactic: Credential Access",
 71    "Resources: Investigation Guide",
 72]
 73timestamp_override = "event.ingested"
 74type = "esql"
 75
 76query = '''
 77FROM logs-o365.audit-*
 78
 79| MV_EXPAND event.category
 80| EVAL
 81    time_window = DATE_TRUNC(5 minutes, @timestamp),
 82    user_id = TO_LOWER(o365.audit.UserId),
 83    ip = source.ip,
 84    login_error = o365.audit.LogonError,
 85    request_type = TO_LOWER(o365.audit.ExtendedProperties.RequestType),
 86    asn_org = source.`as`.organization.name,
 87    country = source.geo.country_name,
 88    event_time = @timestamp
 89
 90| WHERE event.dataset == "o365.audit"
 91  AND event.category == "authentication"
 92  AND event.provider IN ("AzureActiveDirectory", "Exchange")
 93  AND event.action IN ("UserLoginFailed", "PasswordLogonInitialAuthUsingPassword")
 94  AND request_type RLIKE "(oauth.*||.*login.*)"
 95  AND login_error == "IdsLocked"
 96  AND user_id != "not available"
 97  AND o365.audit.Target.Type IN ("0", "2", "6", "10")
 98  AND asn_org != "MICROSOFT-CORP-MSN-AS-BLOCK"
 99
100| STATS
101    unique_users = COUNT_DISTINCT(user_id),
102    user_id_list = VALUES(user_id),
103    ip_list = VALUES(ip),
104    unique_ips = COUNT_DISTINCT(ip),
105    source_orgs = VALUES(asn_org),
106    countries = VALUES(country),
107    unique_country_count = COUNT_DISTINCT(country),
108    unique_asn_orgs = COUNT_DISTINCT(asn_org),
109    request_types = VALUES(request_type),
110    first_seen = MIN(event_time),
111    last_seen = MAX(event_time),
112    total_lockout_responses = COUNT()
113  BY time_window
114
115| EVAL
116    duration_seconds = DATE_DIFF("seconds", first_seen, last_seen)
117
118| KEEP
119    time_window, unique_users, user_id_list, ip_list,
120    unique_ips, source_orgs, countries, unique_country_count,
121    unique_asn_orgs, request_types, first_seen, last_seen,
122    total_lockout_responses, duration_seconds
123
124| WHERE
125    unique_users >= 10 AND
126    total_lockout_responses >= 10 AND
127    duration_seconds <= 300
128'''
129
130
131[[rule.threat]]
132framework = "MITRE ATT&CK"
133[[rule.threat.technique]]
134id = "T1110"
135name = "Brute Force"
136reference = "https://attack.mitre.org/techniques/T1110/"
137
138
139[rule.threat.tactic]
140id = "TA0006"
141name = "Credential Access"
142reference = "https://attack.mitre.org/tactics/TA0006/"

Triage and Analysis

Investigating Multiple Microsoft 365 User Account Lockouts in Short Time Window

Detects a burst of Microsoft 365 user account lockouts within a short 5-minute window. A high number of IdsLocked login errors across multiple user accounts may indicate brute-force attempts for the same users resulting in lockouts.

This rule uses ES|QL aggregations and thus has dynamically generated fields. Correlation of the values in the alert document may need to be performed to the original sign-in and Graph events for further context.

Investigation Steps

  • Review the user_id_list: Are specific naming patterns targeted (e.g., admin, helpdesk)?
  • Examine ip_list and source_orgs: Look for suspicious ISPs or hosting providers.
  • Check duration_seconds: A very short window with a high lockout rate often indicates automation.
  • Confirm lockout policy thresholds with IAM or Entra ID admins. Did the policy trigger correctly?
  • Use the first_seen and last_seen values to pivot into related authentication or audit logs.
  • Correlate with any recent detection of password spraying or credential stuffing activity.
  • Review the request_type field to identify which authentication methods were used (e.g., OAuth, SAML, etc.).
  • Check for any successful logins from the same IP or ASN after the lockouts.

False Positive Analysis

  • Automated systems with stale credentials may cause repeated failed logins.
  • Legitimate bulk provisioning or scripted tests could unintentionally cause account lockouts.
  • Red team exercises or penetration tests may resemble the same lockout pattern.
  • Some organizations may have a high volume of lockouts due to user behavior or legacy systems.

Response Recommendations

  • Notify affected users and confirm whether activity was expected or suspicious.
  • Lock or reset credentials for impacted accounts.
  • Block the source IP(s) or ASN temporarily using conditional access or firewall rules.
  • Strengthen lockout and retry delay policies if necessary.
  • Review the originating application(s) involved via request_types.

References

Related rules

to-top