from logs-o365.audit-*
| mv_expand event.category
| eval
Esql.time_window_date_trunc = date_trunc(5 minutes, @timestamp)
| where
event.dataset == "o365.audit" and
event.category == "authentication" and
event.provider in ("AzureActiveDirectory", "Exchange") and
event.action in ("UserLoginFailed", "PasswordLogonInitialAuthUsingPassword") and
to_lower(o365.audit.ExtendedProperties.RequestType) rlike "(oauth.*||.*login.*)" and
o365.audit.LogonError == "IdsLocked" and
to_lower(o365.audit.UserId) != "not available" and
o365.audit.Target.Type in ("0", "2", "6", "10") and
source.`as`.organization.name != "MICROSOFT-CORP-MSN-as-BLOCK"
| stats
Esql_priv.o365_audit_UserId_count_distinct = count_distinct(to_lower(o365.audit.UserId)),
Esql_priv.o365_audit_UserId_values = values(to_lower(o365.audit.UserId)),
Esql.source_ip_values = values(source.ip),
Esql.source_ip_count_distinct = count_distinct(source.ip),
Esql.source_as_organization_name_values = values(source.`as`.organization.name),
Esql.source_as_organization_name_count_distinct = count_distinct(source.`as`.organization.name),
Esql.source_geo_country_name_values = values(source.geo.country_name),
Esql.source_geo_country_name_count_distinct = count_distinct(source.geo.country_name),
Esql.o365_audit_ExtendedProperties_RequestType_values = values(to_lower(o365.audit.ExtendedProperties.RequestType)),
Esql.timestamp_first_seen = min(@timestamp),
Esql.timestamp_last_seen = max(@timestamp),
Esql.event_count = count(*)
by Esql.time_window_date_trunc
| eval
Esql.event_duration_seconds = date_diff("seconds", Esql.timestamp_first_seen, Esql.timestamp_last_seen)
| keep
Esql.time_window_date_trunc,
Esql_priv.o365_audit_UserId_count_distinct,
Esql_priv.o365_audit_UserId_values,
Esql.source_ip_values,
Esql.source_ip_count_distinct,
Esql.source_as_organization_name_values,
Esql.source_as_organization_name_count_distinct,
Esql.source_geo_country_name_values,
Esql.source_geo_country_name_count_distinct,
Esql.o365_audit_ExtendedProperties_RequestType_values,
Esql.timestamp_first_seen,
Esql.timestamp_last_seen,
Esql.event_count,
Esql.event_duration_seconds
| where
Esql_priv.o365_audit_UserId_count_distinct >= 10 and
Esql.event_count >= 10 and
Esql.event_duration_seconds <= 300
Install detection rules in Elastic Security
Detect Multiple Microsoft 365 User Account Lockouts in Short Time Window in the Elastic Security detection engine by installing this rule into your Elastic Stack.
To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(opens in a new tab or window).