Microsoft 365 password spray audit log
MANY DIFFERENT accounts failing to sign in from ONE address — password spray, as it appears in the Unified Audit Log.
What it detects
MANY DIFFERENT accounts failing to sign in from ONE address — password spray, as it appears in the Unified Audit Log.
The pack already had a spray rule, and it could not see this. entra_password_spray keys on native_event_id: 50126, the AADSTS failure code, which exists only in the Entra SIGN-IN log. In the Unified Audit Log the same attack arrives as UserLoginFailed with no numeric code at all — native_event_id there is the RecordType — so a tenant that exported audit logs instead of sign-in logs got silence. Same attack, different evidence shape, and the rule only knew one.
Counts DISTINCT USERS rather than failures, which is what separates spray from brute force: brute force is many attempts against one account, spray is one or two attempts against many. A per-address failure count cannot tell them apart and needs a high threshold to avoid one user with a stale password; counting distinct victims is both more precise and fires earlier — real tooling (MSOLSpray, o365spray) walks a user list one attempt at a time, exactly to stay under per-account lockout.
MITRE ATT&CK mapping
- T1110.003Brute Force: Password Spraying· Credential Access
False positives and triage
A shared egress address — VPN concentrator, office NAT, a mail gateway — pools unrelated users' failures and is the main false positive. Check the spread and the pacing: spray tools walk an alphabetical or list-ordered set of accounts at a machine-steady rate, while genuine failures behind a NAT cluster around a few repeat offenders at human intervals. Also check whether any account in the set later SUCCEEDED from the same address — that turns this from a nuisance into an intrusion, and is the first thing to answer.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 65%. Source: rules/cloud/m365_password_spray_audit_log.yaml, licensed under the Apache License 2.0.
id: cloud.identity.m365_password_spray_audit_log
version: 1.0.0
status: stable
severity: high
confidence: 0.65
platforms: [application]
mitre_techniques: [T1110.003]
description: |
MANY DIFFERENT accounts failing to sign in from ONE address — password spray,
as it appears in the Unified Audit Log.
The pack already had a spray rule, and it could not see this. `entra_password_spray`
keys on `native_event_id: 50126`, the AADSTS failure code, which exists only in
the Entra SIGN-IN log. In the Unified Audit Log the same attack arrives as
`UserLoginFailed` with no numeric code at all — `native_event_id` there is the
RecordType — so a tenant that exported audit logs instead of sign-in logs got
silence. Same attack, different evidence shape, and the rule only knew one.
Counts DISTINCT USERS rather than failures, which is what separates spray from
brute force: brute force is many attempts against one account, spray is one or
two attempts against many. A per-address failure count cannot tell them apart and
needs a high threshold to avoid one user with a stale password; counting distinct
victims is both more precise and fires earlier — real tooling (MSOLSpray,
o365spray) walks a user list one attempt at a time, exactly to stay under
per-account lockout.
match:
event_category: authentication
event_outcome: failure
event_action_any:
- UserLoginFailed
threshold:
count: 5
window_seconds: 3600
distinct: user_name
group_by: [source_ip]
correlation_keys: [source_ip]
false_positive_guidance: |
A shared egress address — VPN concentrator, office NAT, a mail gateway — pools
unrelated users' failures and is the main false positive. Check the spread and
the pacing: spray tools walk an alphabetical or list-ordered set of accounts at a
machine-steady rate, while genuine failures behind a NAT cluster around a few
repeat offenders at human intervals. Also check whether any account in the set
later SUCCEEDED from the same address — that turns this from a nuisance into an
intrusion, and is the first thing to answer.
Related detections
Run this rule on your own logs — offline
KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.
