diff --git a/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml b/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml index 2edd8b372d1..383bb71d6d0 100644 --- a/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml +++ b/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml @@ -2,7 +2,7 @@ creation_date = "2020/11/30" integration = ["o365"] maturity = "production" -updated_date = "2024/05/24" +updated_date = "2024/07/01" [rule] author = ["Elastic", "Willem D'Haese", "Austin Songer"] @@ -16,34 +16,65 @@ false_positives = [ positives. """, ] -from = "now-30m" -index = ["filebeat-*", "logs-o365*"] -language = "kuery" +from = "now-9m" +language = "esql" license = "Elastic License v2" name = "Attempts to Brute Force a Microsoft 365 User Account" note = """## Setup The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" -references = ["https://blueteamblog.com/7-ways-to-monitor-your-office-365-logs-using-siem"] -risk_score = 73 +references = [ + "https://blueteamblog.com/7-ways-to-monitor-your-office-365-logs-using-siem", + "https://learn.microsoft.com/en-us/purview/audit-log-detailed-properties" + ] +risk_score = 47 rule_id = "26f68dba-ce29-497b-8e13-b4fde1db5a2d" -severity = "high" +severity = "medium" tags = [ "Domain: Cloud", + "Domain: SaaS", "Data Source: Microsoft 365", "Use Case: Identity and Access Audit", "Tactic: Credential Access", ] timestamp_override = "event.ingested" -type = "threshold" +type = "esql" query = ''' -event.dataset:o365.audit and event.provider:(AzureActiveDirectory or Exchange) and - event.category:authentication and event.action:(UserLoginFailed or PasswordLogonInitialAuthUsingPassword) and - not o365.audit.LogonError:(UserAccountNotFound or EntitlementGrantsNotFound or UserStrongAuthEnrollmentRequired or - UserStrongAuthClientAuthNRequired or InvalidReplyTo or SsoArtifactExpiredDueToConditionalAccess or - PasswordResetRegistrationRequiredInterrupt or SsoUserAccountNotFoundInResourceTenant or - UserStrongAuthExpired) +from logs-o365.audit-* +| MV_EXPAND event.category +| WHERE event.dataset == "o365.audit" + AND event.category == "authentication" + + // filter only on Entra ID or Exchange audit logs in O365 integration + AND event.provider in ("AzureActiveDirectory", "Exchange") + + // filter only for UserLoginFailed or partial failures + AND event.action in ("UserLoginFailed", "PasswordLogonInitialAuthUsingPassword") + + // ignore specific logon errors + AND not o365.audit.LogonError in ( + "EntitlementGrantsNotFound", + "UserStrongAuthEnrollmentRequired", + "UserStrongAuthClientAuthNRequired", + "InvalidReplyTo", + "SsoArtifactExpiredDueToConditionalAccess", + "PasswordResetRegistrationRequiredInterrupt", + "SsoUserAccountNotFoundInResourceTenant", + "UserStrongAuthExpired", + "CmsiInterrupt" +) + // filters out non user or application logins based on target + AND o365.audit.Target.Type in ("0", "2", "3", "5", "6", "10") + + // filters only for logins from user or application, ignoring oauth:token + AND to_lower(o365.audit.ExtendedProperties.RequestType) rlike "(.*)login(.*)" + +| STATS + // count the number of failed login attempts target per user + login_attempt_counts = COUNT(*) by o365.audit.Target.ID, o365.audit.LogonError + +| WHERE login_attempt_counts > 10 ''' @@ -59,8 +90,3 @@ reference = "https://attack.mitre.org/techniques/T1110/" id = "TA0006" name = "Credential Access" reference = "https://attack.mitre.org/tactics/TA0006/" - -[rule.threshold] -field = ["user.id"] -value = 10 -