Potential Microsoft 365 User Account Brute Force
editPotential Microsoft 365 User Account Brute Force
editIdentifies brute-force authentication activity targeting Microsoft 365 user accounts using failed sign-in patterns that match password spraying, credential stuffing, or password guessing behavior. Adversaries may attempt brute-force authentication with credentials obtained from previous breaches, leaks, marketplaces or guessable passwords.
Rule type: esql
Rule indices: None
Severity: medium
Risk score: 47
Runs every: 5m
Searches indices from: now-9m (Date Math format, see also Additional look-back time)
Maximum alerts per execution: 100
References:
- https://learn.microsoft.com/en-us/security/operations/incident-response-playbook-password-spray
- https://learn.microsoft.com/en-us/purview/audit-log-detailed-properties
- https://securityscorecard.com/research/massive-botnet-targets-m365-with-stealthy-password-spraying-attacks/
- https://github.com/0xZDH/Omnispray
- https://github.com/0xZDH/o365spray
Tags:
- Domain: Cloud
- Domain: SaaS
- Data Source: Microsoft 365
- Data Source: Microsoft 365 Audit Logs
- Use Case: Identity and Access Audit
- Use Case: Threat Detection
- Tactic: Credential Access
- Resources: Investigation Guide
Version: 412
Rule authors:
- Elastic
- Willem D’Haese
- Austin Songer
Rule license: Elastic License v2
Investigation guide
editTriage and Analysis
Investigating Potential Microsoft 365 User Account Brute Force
Identifies brute-force authentication activity targeting Microsoft 365 user accounts using failed sign-in patterns that match password spraying, credential stuffing, or password guessing behavior. Adversaries may attempt brute-force authentication with credentials obtained from previous breaches, leaks, marketplaces or guessable passwords.
Investigation Steps
-
Review
user_id_list: Enumerates the user accounts targeted. Look for naming patterns or privilege levels (e.g., admins). -
Check
login_errors: A consistent error such as"InvalidUserNameOrPassword"confirms a spray-style attack using one or a few passwords. -
Examine
ip_listandsource_orgs: Determine if the traffic originates from a known corporate VPN, datacenter, or suspicious ASN like hosting providers or anonymizers. -
Review
countriesandunique_country_count: Geographic anomalies (e.g., login attempts from unexpected regions) may indicate malicious automation. -
Validate
total_attemptsvsduration_seconds: A high frequency of login attempts over a short period may suggest automation rather than manual logins. -
Cross-reference with successful logins: Pivot to surrounding sign-in logs (
azure.signinlogs) or risk detections (identityprotection) for any account that eventually succeeded. - Check for multi-factor challenges or bypasses: Determine if any of the accounts were protected or if the attack bypassed MFA.
False Positive Analysis
- IT administrators using automation tools (e.g., PowerShell) during account provisioning may trigger false positives if login attempts cluster.
- Penetration testing or red team simulations may resemble spray activity.
- Infrequent, low-volume login testing tools like ADFS testing scripts can exhibit similar patterns.
Response Recommendations
- Initiate an internal incident ticket and inform the affected identity/IT team.
- Temporarily disable impacted user accounts if compromise is suspected.
- Investigate whether any login attempts succeeded after the spray window.
- Block the offending IPs or ASN temporarily via firewall or conditional access policies.
- Rotate passwords for all targeted accounts and audit for password reuse.
- Enforce or verify MFA is enabled for all user accounts.
- Consider deploying account lockout or progressive delay mechanisms if not already enabled.
Rule query
editFROM logs-o365.audit-*
| MV_EXPAND event.category
| EVAL
time_window = DATE_TRUNC(5 minutes, @timestamp),
user_id = TO_LOWER(o365.audit.UserId),
ip = source.ip,
login_error = o365.audit.LogonError,
request_type = TO_LOWER(o365.audit.ExtendedProperties.RequestType),
asn_org = source.`as`.organization.name,
country = source.geo.country_name,
event_time = @timestamp
| WHERE event.dataset == "o365.audit"
AND event.category == "authentication"
AND event.provider IN ("AzureActiveDirectory", "Exchange")
AND event.action IN ("UserLoginFailed", "PasswordLogonInitialAuthUsingPassword")
AND request_type RLIKE "(oauth.*||.*login.*)"
AND login_error != "IdsLocked"
AND login_error NOT IN (
"EntitlementGrantsNotFound", "UserStrongAuthEnrollmentRequired", "UserStrongAuthClientAuthNRequired",
"InvalidReplyTo", "SsoArtifactExpiredDueToConditionalAccess", "PasswordResetRegistrationRequiredInterrupt",
"SsoUserAccountNotFoundInResourceTenant", "UserStrongAuthExpired", "CmsiInterrupt"
)
AND user_id != "not available"
AND o365.audit.Target.Type IN ("0", "2", "6", "10")
| STATS
unique_users = COUNT_DISTINCT(user_id),
user_id_list = VALUES(user_id),
login_errors = VALUES(login_error),
unique_login_errors = COUNT_DISTINCT(login_error),
request_types = VALUES(request_type),
ip_list = VALUES(ip),
unique_ips = COUNT_DISTINCT(ip),
source_orgs = VALUES(asn_org),
countries = VALUES(country),
unique_country_count = COUNT_DISTINCT(country),
unique_asn_orgs = COUNT_DISTINCT(asn_org),
first_seen = MIN(event_time),
last_seen = MAX(event_time),
total_attempts = COUNT()
BY time_window
| EVAL
duration_seconds = DATE_DIFF("seconds", first_seen, last_seen),
bf_type = CASE(
unique_users >= 15 AND unique_login_errors == 1 AND total_attempts >= 10 AND duration_seconds <= 1800, "password_spraying",
unique_users >= 8 AND total_attempts >= 15 AND unique_login_errors <= 3 AND unique_ips <= 5 AND duration_seconds <= 600, "credential_stuffing",
unique_users == 1 AND unique_login_errors == 1 AND total_attempts >= 20 AND duration_seconds <= 300, "password_guessing",
"other"
)
| KEEP
time_window, unique_users, user_id_list, login_errors, unique_login_errors,
request_types, ip_list, unique_ips, source_orgs, countries,
unique_country_count, unique_asn_orgs, first_seen, last_seen,
duration_seconds, total_attempts, bf_type
| WHERE
bf_type != "other"
Framework: MITRE ATT&CKTM
-
Tactic:
- Name: Credential Access
- ID: TA0006
- Reference URL: https://attack.mitre.org/tactics/TA0006/
-
Technique:
- Name: Brute Force
- ID: T1110
- Reference URL: https://attack.mitre.org/techniques/T1110/
-
Sub-technique:
- Name: Password Guessing
- ID: T1110.001
- Reference URL: https://attack.mitre.org/techniques/T1110/001/
-
Sub-technique:
- Name: Password Spraying
- ID: T1110.003
- Reference URL: https://attack.mitre.org/techniques/T1110/003/
-
Sub-technique:
- Name: Credential Stuffing
- ID: T1110.004
- Reference URL: https://attack.mitre.org/techniques/T1110/004/