Sample rules
Deprecated - Azure Entra Sign-in Brute Force Microsoft 365 Accounts by Repeat Source
- source: elastic
- technicques:
- T1110
Description
Identifies potential brute-force attempts against Microsoft 365 user accounts by detecting a high number of failed interactive or non-interactive login attempts within a 30-minute window from a single source. Attackers may attempt to brute force user accounts to gain unauthorized access to Microsoft 365 services via different services such as Exchange, SharePoint, or Teams.
Detection logic
from logs-azure.signinlogs*
| WHERE
event.dataset == "azure.signinlogs"
and event.category == "authentication"
and to_lower(azure.signinlogs.properties.resource_display_name) rlike "(.*)365(.*)"
and azure.signinlogs.category in ("NonInteractiveUserSignInLogs", "SignInLogs")
and event.outcome != "success"
// For tuning, review azure.signinlogs.properties.status.error_code
// https://learn.microsoft.com/en-us/entra/identity-platform/reference-error-codes
// keep only relevant fields
| keep event.dataset, event.category, azure.signinlogs.properties.resource_display_name, azure.signinlogs.category, event.outcome, azure.signinlogs.properties.user_principal_name, source.ip
// Count the number of unique targets per source IP
| stats
target_count = count_distinct(azure.signinlogs.properties.user_principal_name) by source.ip
// Filter for at least 10 distinct failed login attempts from a single source
| where target_count >= 10
Microsoft 365 Brute Force via Entra ID Sign-Ins
- source: elastic
- technicques:
- T1110
Description
Identifies potential brute-force attacks targeting Microsoft 365 user accounts by analyzing failed sign-in patterns in Microsoft Entra ID Sign-In Logs. This detection focuses on a high volume of failed interactive or non-interactive authentication attempts within a short time window, often indicative of password spraying, credential stuffing, or password guessing. Adversaries may use these techniques to gain unauthorized access to Microsoft 365 services such as Exchange Online, SharePoint, or Teams.
Detection logic
from logs-azure.signinlogs*
| eval
Esql.time_window_date_trunc = date_trunc(15 minutes, @timestamp),
Esql_priv.azure_signinlogs_properties_user_principal_name_lower = to_lower(azure.signinlogs.properties.user_principal_name),
Esql.azure_signinlogs_properties_incoming_token_type_lower = to_lower(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_app_display_name_lower = to_lower(azure.signinlogs.properties.app_display_name),
Esql.user_agent_original = user_agent.original
| where event.dataset == "azure.signinlogs"
and event.category == "authentication"
and azure.signinlogs.category in ("NonInteractiveUserSignInLogs", "SignInLogs")
and azure.signinlogs.properties.resource_display_name rlike "(.*)365|SharePoint|Exchange|Teams|Office(.*)"
and event.outcome == "failure"
and azure.signinlogs.properties.status.error_code != 50053
and azure.signinlogs.properties.status.error_code in (
50034, // UserAccountNotFound
50126, // InvalidUsernameOrPassword
50055, // PasswordExpired
50056, // InvalidPassword
50057, // UserDisabled
50064, // CredentialValidationFailure
50076, // MFARequiredButNotPassed
50079, // MFARegistrationRequired
50105, // EntitlementGrantsNotFound
70000, // InvalidGrant
70008, // ExpiredOrRevokedRefreshToken
70043, // BadTokenDueToSignInFrequency
80002, // OnPremisePasswordValidatorRequestTimedOut
80005, // OnPremisePasswordValidatorUnpredictableWebException
50144, // InvalidPasswordExpiredOnPremPassword
50135, // PasswordChangeCompromisedPassword
50142, // PasswordChangeRequiredConditionalAccess
120000, // PasswordChangeIncorrectCurrentPassword
120002, // PasswordChangeInvalidNewPasswordWeak
120020 // PasswordChangeFailure
)
and azure.signinlogs.properties.user_principal_name is not null
and azure.signinlogs.properties.user_principal_name != ""
and user_agent.original != "Mozilla/5.0 (compatible; MSAL 1.0) PKeyAuth/1.0"
| stats
Esql.azure_signinlogs_properties_authentication_requirement_values = values(azure.signinlogs.properties.authentication_requirement),
Esql.azure_signinlogs_properties_app_id_values = values(azure.signinlogs.properties.app_id),
Esql.azure_signinlogs_properties_app_display_name_values = values(azure.signinlogs.properties.app_display_name),
Esql.azure_signinlogs_properties_resource_id_values = values(azure.signinlogs.properties.resource_id),
Esql.azure_signinlogs_properties_resource_display_name_values = values(azure.signinlogs.properties.resource_display_name),
Esql.azure_signinlogs_properties_conditional_access_status_values = values(azure.signinlogs.properties.conditional_access_status),
Esql.azure_signinlogs_properties_device_detail_browser_values = values(azure.signinlogs.properties.device_detail.browser),
Esql.azure_signinlogs_properties_device_detail_device_id_values = values(azure.signinlogs.properties.device_detail.device_id),
Esql.azure_signinlogs_properties_device_detail_operating_system_values = values(azure.signinlogs.properties.device_detail.operating_system),
Esql.azure_signinlogs_properties_incoming_token_type_values = values(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_risk_state_values = values(azure.signinlogs.properties.risk_state),
Esql.azure_signinlogs_properties_session_id_values = values(azure.signinlogs.properties.session_id),
Esql.azure_signinlogs_properties_user_id_values = values(azure.signinlogs.properties.user_id),
Esql_priv.azure_signinlogs_properties_user_principal_name_values = values(azure.signinlogs.properties.user_principal_name),
Esql.azure_signinlogs_result_description_values = values(azure.signinlogs.result_description),
Esql.azure_signinlogs_result_signature_values = values(azure.signinlogs.result_signature),
Esql.azure_signinlogs_result_type_values = values(azure.signinlogs.result_type),
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct = count_distinct(Esql_priv.azure_signinlogs_properties_user_principal_name_lower),
Esql_priv.azure_signinlogs_properties_user_principal_name_lower_values = values(Esql_priv.azure_signinlogs_properties_user_principal_name_lower),
Esql.azure_signinlogs_result_description_count_distinct = count_distinct(azure.signinlogs.result_description),
Esql.azure_signinlogs_result_description_values = values(azure.signinlogs.result_description),
Esql.azure_signinlogs_properties_status_error_code_count_distinct = count_distinct(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_status_error_code_values = values(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_incoming_token_type_lower_values = values(Esql.azure_signinlogs_properties_incoming_token_type_lower),
Esql.azure_signinlogs_properties_app_display_name_lower_values = values(Esql.azure_signinlogs_properties_app_display_name_lower),
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.@timestamp.min = min(@timestamp),
Esql.@timestamp.max = max(@timestamp),
Esql.event_count = count()
by Esql.time_window_date_trunc
| eval
Esql.event_duration_seconds = date_diff("seconds", Esql.@timestamp.min, Esql.@timestamp.max),
Esql.event_bf_type = case(
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct >= 10
and Esql.event_count >= 30
and Esql.azure_signinlogs_result_description_count_distinct <= 3
and Esql.source_ip_count_distinct >= 5
and Esql.event_duration_seconds <= 600
and Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct > Esql.source_ip_count_distinct,
"credential_stuffing",
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct >= 15
and Esql.azure_signinlogs_result_description_count_distinct == 1
and Esql.event_count >= 15
and Esql.event_duration_seconds <= 1800,
"password_spraying",
(Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct == 1
and Esql.azure_signinlogs_result_description_count_distinct == 1
and Esql.event_count >= 30
and Esql.event_duration_seconds <= 300)
or (Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct <= 3
and Esql.source_ip_count_distinct > 30
and Esql.event_count >= 100),
"password_guessing",
"other"
)
| where Esql.event_bf_type != "other"
| keep
Esql.time_window_date_trunc,
Esql.event_bf_type,
Esql.event_duration_seconds,
Esql.event_count,
Esql.@timestamp.min,
Esql.@timestamp.max,
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct,
Esql_priv.azure_signinlogs_properties_user_principal_name_lower_values,
Esql.azure_signinlogs_result_description_count_distinct,
Esql.azure_signinlogs_result_description_values,
Esql.azure_signinlogs_properties_status_error_code_count_distinct,
Esql.azure_signinlogs_properties_status_error_code_values,
Esql.azure_signinlogs_properties_incoming_token_type_lower_values,
Esql.azure_signinlogs_properties_app_display_name_lower_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.azure_signinlogs_properties_authentication_requirement_values,
Esql.azure_signinlogs_properties_app_id_values,
Esql.azure_signinlogs_properties_app_display_name_values,
Esql.azure_signinlogs_properties_resource_id_values,
Esql.azure_signinlogs_properties_resource_display_name_values,
Esql.azure_signinlogs_properties_conditional_access_status_values,
Esql.azure_signinlogs_properties_device_detail_browser_values,
Esql.azure_signinlogs_properties_device_detail_device_id_values,
Esql.azure_signinlogs_properties_device_detail_operating_system_values,
Esql.azure_signinlogs_properties_incoming_token_type_values,
Esql.azure_signinlogs_properties_risk_state_values,
Esql.azure_signinlogs_properties_session_id_values,
Esql.azure_signinlogs_properties_user_id_values
Microsoft Entra ID Exccessive Account Lockouts Detected
- source: elastic
- technicques:
- T1110
Description
Identifies a high count of failed Microsoft Entra ID sign-in attempts as the result of the target user account being locked out. Adversaries may attempt to brute-force user accounts by repeatedly trying to authenticate with incorrect credentials, leading to account lockouts by Entra ID Smart Lockout policies.
Detection logic
from logs-azure.signinlogs*
| eval
Esql.time_window_date_trunc = date_trunc(30 minutes, @timestamp),
Esql_priv.azure_signinlogs_properties_user_principal_name_lower = to_lower(azure.signinlogs.properties.user_principal_name),
Esql.azure_signinlogs_properties_incoming_token_type_lower = to_lower(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_app_display_name_lower = to_lower(azure.signinlogs.properties.app_display_name)
| where event.dataset == "azure.signinlogs"
and event.category == "authentication"
and azure.signinlogs.category in ("NonInteractiveUserSignInLogs", "SignInLogs")
and event.outcome == "failure"
and azure.signinlogs.properties.authentication_requirement == "singleFactorAuthentication"
and azure.signinlogs.properties.status.error_code == 50053
and azure.signinlogs.properties.user_principal_name is not null
and azure.signinlogs.properties.user_principal_name != ""
and source.`as`.organization.name != "MICROSOFT-CORP-MSN-as-BLOCK"
| stats
Esql.azure_signinlogs_properties_authentication_requirement_values = values(azure.signinlogs.properties.authentication_requirement),
Esql.azure_signinlogs_properties_app_id_values = values(azure.signinlogs.properties.app_id),
Esql.azure_signinlogs_properties_app_display_name_values = values(azure.signinlogs.properties.app_display_name),
Esql.azure_signinlogs_properties_resource_id_values = values(azure.signinlogs.properties.resource_id),
Esql.azure_signinlogs_properties_resource_display_name_values = values(azure.signinlogs.properties.resource_display_name),
Esql.azure_signinlogs_properties_conditional_access_status_values = values(azure.signinlogs.properties.conditional_access_status),
Esql.azure_signinlogs_properties_device_detail_browser_values = values(azure.signinlogs.properties.device_detail.browser),
Esql.azure_signinlogs_properties_device_detail_device_id_values = values(azure.signinlogs.properties.device_detail.device_id),
Esql.azure_signinlogs_properties_device_detail_operating_system_values = values(azure.signinlogs.properties.device_detail.operating_system),
Esql.azure_signinlogs_properties_incoming_token_type_values = values(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_risk_state_values = values(azure.signinlogs.properties.risk_state),
Esql.azure_signinlogs_properties_session_id_values = values(azure.signinlogs.properties.session_id),
Esql.azure_signinlogs_properties_user_id_values = values(azure.signinlogs.properties.user_id),
Esql_priv.azure_signinlogs_properties_user_principal_name_values = values(azure.signinlogs.properties.user_principal_name),
Esql.azure_signinlogs_result_description_values = values(azure.signinlogs.result_description),
Esql.azure_signinlogs_result_signature_values = values(azure.signinlogs.result_signature),
Esql.azure_signinlogs_result_type_values = values(azure.signinlogs.result_type),
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct = count_distinct(Esql_priv.azure_signinlogs_properties_user_principal_name_lower),
Esql_priv.azure_signinlogs_properties_user_principal_name_lower_values = values(Esql_priv.azure_signinlogs_properties_user_principal_name_lower),
Esql.azure_signinlogs_result_description_count_distinct = count_distinct(azure.signinlogs.result_description),
Esql.azure_signinlogs_properties_status_error_code_count_distinct = count_distinct(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_status_error_code_values = values(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_incoming_token_type_lower_values = values(Esql.azure_signinlogs_properties_incoming_token_type_lower),
Esql.azure_signinlogs_properties_app_display_name_lower_values = values(Esql.azure_signinlogs_properties_app_display_name_lower),
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.@timestamp.min = min(@timestamp),
Esql.@timestamp.max = max(@timestamp),
Esql.event_count = count()
by Esql.time_window_date_trunc
| where Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct >= 15 and Esql.event_count >= 20
| keep
Esql.time_window_date_trunc,
Esql.event_count,
Esql.@timestamp.min,
Esql.@timestamp.max,
Esql.azure_signinlogs_properties_user_principal_name_lower_count_distinct,
Esql_priv.azure_signinlogs_properties_user_principal_name_lower_values,
Esql.azure_signinlogs_result_description_count_distinct,
Esql.azure_signinlogs_result_description_values,
Esql.azure_signinlogs_properties_status_error_code_count_distinct,
Esql.azure_signinlogs_properties_status_error_code_values,
Esql.azure_signinlogs_properties_incoming_token_type_lower_values,
Esql.azure_signinlogs_properties_app_display_name_lower_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.azure_signinlogs_properties_authentication_requirement_values,
Esql.azure_signinlogs_properties_app_id_values,
Esql.azure_signinlogs_properties_app_display_name_values,
Esql.azure_signinlogs_properties_resource_id_values,
Esql.azure_signinlogs_properties_resource_display_name_values,
Esql.azure_signinlogs_properties_conditional_access_status_values,
Esql.azure_signinlogs_properties_device_detail_browser_values,
Esql.azure_signinlogs_properties_device_detail_device_id_values,
Esql.azure_signinlogs_properties_device_detail_operating_system_values,
Esql.azure_signinlogs_properties_incoming_token_type_values,
Esql.azure_signinlogs_properties_risk_state_values,
Esql.azure_signinlogs_properties_session_id_values,
Esql.azure_signinlogs_properties_user_id_values,
Esql_priv.azure_signinlogs_properties_user_principal_name_values,
Esql.azure_signinlogs_result_description_values,
Esql.azure_signinlogs_result_signature_values,
Esql.azure_signinlogs_result_type_values
Microsoft Entra ID Sign-In Brute Force Activity
- source: elastic
- technicques:
- T1110
Description
Identifies potential brute-force attacks targeting user accounts by analyzing failed sign-in patterns in Microsoft Entra ID Sign-In Logs. This detection focuses on a high volume of failed interactive or non-interactive authentication attempts within a short time window, often indicative of password spraying, credential stuffing, or password guessing. Adversaries may use these techniques to gain unauthorized access to applications integrated with Entra ID or to compromise valid user accounts.
Detection logic
from logs-azure.signinlogs*
// Define a time window for grouping and maintain the original event timestamp
| eval Esql.time_window_date_trunc = date_trunc(15 minutes, @timestamp)
// Filter relevant failed authentication events with specific error codes
| where event.dataset == "azure.signinlogs"
and event.category == "authentication"
and azure.signinlogs.category in ("NonInteractiveUserSignInLogs", "SignInLogs")
and event.outcome == "failure"
and azure.signinlogs.properties.authentication_requirement == "singleFactorAuthentication"
and azure.signinlogs.properties.status.error_code in (
50034, // UserAccountNotFound
50126, // InvalidUsernameOrPassword
50055, // PasswordExpired
50056, // InvalidPassword
50057, // UserDisabled
50064, // CredentialValidationFailure
50076, // MFARequiredButNotPassed
50079, // MFARegistrationRequired
50105, // EntitlementGrantsNotFound
70000, // InvalidGrant
70008, // ExpiredOrRevokedRefreshToken
70043, // BadTokenDueToSignInFrequency
80002, // OnPremisePasswordValidatorRequestTimedOut
80005, // OnPremisePasswordValidatorUnpredictableWebException
50144, // InvalidPasswordExpiredOnPremPassword
50135, // PasswordChangeCompromisedPassword
50142, // PasswordChangeRequiredConditionalAccess
120000, // PasswordChangeIncorrectCurrentPassword
120002, // PasswordChangeInvalidNewPasswordWeak
120020 // PasswordChangeFailure
)
and azure.signinlogs.properties.user_principal_name is not null and azure.signinlogs.properties.user_principal_name != ""
and user_agent.original != "Mozilla/5.0 (compatible; MSAL 1.0) PKeyAuth/1.0"
and source.`as`.organization.name != "MICROSOFT-CORP-MSN-as-BLOCK"
| stats
Esql.azure_signinlogs_properties_authentication_requirement_values = values(azure.signinlogs.properties.authentication_requirement),
Esql.azure_signinlogs_properties_app_id_values = values(azure.signinlogs.properties.app_id),
Esql.azure_signinlogs_properties_app_display_name_values = values(azure.signinlogs.properties.app_display_name),
Esql.azure_signinlogs_properties_resource_id_values = values(azure.signinlogs.properties.resource_id),
Esql.azure_signinlogs_properties_resource_display_name_values = values(azure.signinlogs.properties.resource_display_name),
Esql.azure_signinlogs_properties_conditional_access_status_values = values(azure.signinlogs.properties.conditional_access_status),
Esql.azure_signinlogs_properties_device_detail_browser_values = values(azure.signinlogs.properties.device_detail.browser),
Esql.azure_signinlogs_properties_device_detail_device_id_values = values(azure.signinlogs.properties.device_detail.device_id),
Esql.azure_signinlogs_properties_device_detail_operating_system_values = values(azure.signinlogs.properties.device_detail.operating_system),
Esql.azure_signinlogs_properties_incoming_token_type_values = values(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_risk_state_values = values(azure.signinlogs.properties.risk_state),
Esql.azure_signinlogs_properties_session_id_values = values(azure.signinlogs.properties.session_id),
Esql.azure_signinlogs_properties_user_id_values = values(azure.signinlogs.properties.user_id),
Esql_priv.azure_signinlogs_properties_user_principal_name_values = values(azure.signinlogs.properties.user_principal_name),
Esql.azure_signinlogs_result_description_values = values(azure.signinlogs.result_description),
Esql.azure_signinlogs_result_signature_values = values(azure.signinlogs.result_signature),
Esql.azure_signinlogs_result_type_values = values(azure.signinlogs.result_type),
Esql.azure_signinlogs_properties_user_id_count_distinct = count_distinct(azure.signinlogs.properties.user_id),
Esql.azure_signinlogs_properties_user_id_list = values(azure.signinlogs.properties.user_id),
Esql.azure_signinlogs_result_description_values_all = values(azure.signinlogs.result_description),
Esql.azure_signinlogs_result_description_count_distinct = count_distinct(azure.signinlogs.result_description),
Esql.azure_signinlogs_properties_status_error_code_values = values(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_status_error_code_count_distinct = count_distinct(azure.signinlogs.properties.status.error_code),
Esql.azure_signinlogs_properties_incoming_token_type_values_all = values(azure.signinlogs.properties.incoming_token_type),
Esql.azure_signinlogs_properties_app_display_name_values_all = values(azure.signinlogs.properties.app_display_name),
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_geo_country_name_values = values(source.geo.country_name),
Esql.source_geo_country_name_count_distinct = count_distinct(source.geo.country_name),
Esql.source_as_organization_name_count_distinct = count_distinct(source.`as`.organization.name),
Esql.timestamp_first_seen = min(@timestamp),
Esql.timestamp_last_seen = max(@timestamp),
Esql.event_count = count()
by Esql.time_window_date_trunc
| eval
Esql.duration_seconds = date_diff("seconds", Esql.timestamp_first_seen, Esql.timestamp_last_seen),
Esql.brute_force_type = case(
Esql.azure_signinlogs_properties_user_id_count_distinct >= 10 and Esql.event_count >= 30 and Esql.azure_signinlogs_result_description_count_distinct <= 3
and Esql.source_ip_count_distinct >= 5
and Esql.duration_seconds <= 600
and Esql.azure_signinlogs_properties_user_id_count_distinct > Esql.source_ip_count_distinct,
"credential_stuffing",
Esql.azure_signinlogs_properties_user_id_count_distinct >= 15 and Esql.azure_signinlogs_result_description_count_distinct == 1 and Esql.event_count >= 15 and Esql.duration_seconds <= 1800,
"password_spraying",
(Esql.azure_signinlogs_properties_user_id_count_distinct == 1 and Esql.azure_signinlogs_result_description_count_distinct == 1 and Esql.event_count >= 30 and Esql.duration_seconds <= 300)
or (Esql.azure_signinlogs_properties_user_id_count_distinct <= 3 and Esql.source_ip_count_distinct > 30 and Esql.event_count >= 100),
"password_guessing",
"other"
)
| keep
Esql.time_window_date_trunc,
Esql.brute_force_type,
Esql.duration_seconds,
Esql.event_count,
Esql.timestamp_first_seen,
Esql.timestamp_last_seen,
Esql.azure_signinlogs_properties_user_id_count_distinct,
Esql.azure_signinlogs_properties_user_id_list,
Esql.azure_signinlogs_result_description_values_all,
Esql.azure_signinlogs_result_description_count_distinct,
Esql.azure_signinlogs_properties_status_error_code_count_distinct,
Esql.azure_signinlogs_properties_status_error_code_values,
Esql.azure_signinlogs_properties_incoming_token_type_values_all,
Esql.azure_signinlogs_properties_app_display_name_values_all,
Esql.source_ip_values,
Esql.source_ip_count_distinct,
Esql.source_as_organization_name_values,
Esql.source_geo_country_name_values,
Esql.source_geo_country_name_count_distinct,
Esql.source_as_organization_name_count_distinct,
Esql.azure_signinlogs_properties_authentication_requirement_values,
Esql.azure_signinlogs_properties_app_id_values,
Esql.azure_signinlogs_properties_app_display_name_values,
Esql.azure_signinlogs_properties_resource_id_values,
Esql.azure_signinlogs_properties_resource_display_name_values,
Esql.azure_signinlogs_properties_conditional_access_status_values,
Esql.azure_signinlogs_properties_device_detail_browser_values,
Esql.azure_signinlogs_properties_device_detail_device_id_values,
Esql.azure_signinlogs_properties_device_detail_operating_system_values,
Esql.azure_signinlogs_properties_incoming_token_type_values,
Esql.azure_signinlogs_properties_risk_state_values,
Esql.azure_signinlogs_properties_session_id_values,
Esql.azure_signinlogs_properties_user_id_values,
Esql_priv.azure_signinlogs_properties_user_principal_name_values,
Esql.azure_signinlogs_result_description_values,
Esql.azure_signinlogs_result_signature_values,
Esql.azure_signinlogs_result_type_values
| where Esql.brute_force_type != "other"
Deprecated - Potential Password Spraying of Microsoft 365 User Accounts
- source: elastic
- technicques:
- T1110
Description
Identifies a high number (25) of failed Microsoft 365 user authentication attempts from a single IP address within 30 minutes, which could be indicative of a password spraying attack. An adversary may attempt a password spraying attack to obtain unauthorized access to user accounts.
Detection logic
event.dataset:o365.audit and event.provider:(Exchange or AzureActiveDirectory) and event.category:authentication and
event.action:("UserLoginFailed" or "PasswordLogonInitialAuthUsingPassword")
Potential Microsoft 365 User Account Brute Force
- source: elastic
- technicques:
- T1110
Description
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.
Detection logic
from logs-o365.audit-*
| mv_expand event.category
| eval
Esql.time_window_date_trunc = date_trunc(5 minutes, @timestamp),
Esql_priv.o365_audit_UserId_lower = to_lower(o365.audit.UserId),
Esql.o365_audit_LogonError = o365.audit.LogonError,
Esql.o365_audit_ExtendedProperties_RequestType_lower = to_lower(o365.audit.ExtendedProperties.RequestType)
| where
event.dataset == "o365.audit" and
event.category == "authentication" and
event.provider in ("AzureActiveDirectory", "Exchange") and
event.action in ("UserLoginFailed", "PasswordLogonInitialAuthUsingPassword") and
Esql.o365_audit_ExtendedProperties_RequestType_lower rlike "(oauth.*||.*login.*)" and
Esql.o365_audit_LogonError != "IdsLocked" and
Esql.o365_audit_LogonError not in (
"EntitlementGrantsNotFound",
"UserStrongAuthEnrollmentRequired",
"UserStrongAuthClientAuthNRequired",
"InvalidReplyTo",
"SsoArtifactExpiredDueToConditionalAccess",
"PasswordResetRegistrationRequiredInterrupt",
"SsoUserAccountNotFoundInResourceTenant",
"UserStrongAuthExpired",
"CmsiInterrupt"
) and
Esql_priv.o365_audit_UserId_lower != "not available" and
o365.audit.Target.Type in ("0", "2", "6", "10")
| stats
Esql.o365_audit_UserId_lower_count_distinct = count_distinct(Esql_priv.o365_audit_UserId_lower),
Esql_priv.o365_audit_UserId_lower_values = values(Esql_priv.o365_audit_UserId_lower),
Esql.o365_audit_LogonError_values = values(Esql.o365_audit_LogonError),
Esql.o365_audit_LogonError_count_distinct = count_distinct(Esql.o365_audit_LogonError),
Esql.o365_audit_ExtendedProperties_RequestType_values = values(Esql.o365_audit_ExtendedProperties_RequestType_lower),
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_geo_country_name_values = values(source.geo.country_name),
Esql.source_geo_country_name_count_distinct = count_distinct(source.geo.country_name),
Esql.source_as_organization_name_count_distinct = count_distinct(source.`as`.organization.name),
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),
Esql.brute_force_type = case(
Esql.o365_audit_UserId_lower_count_distinct >= 15 and Esql.o365_audit_LogonError_count_distinct == 1 and Esql.event_count >= 10 and Esql.event_duration_seconds <= 1800, "password_spraying",
Esql.o365_audit_UserId_lower_count_distinct >= 8 and Esql.event_count >= 15 and Esql.o365_audit_LogonError_count_distinct <= 3 and Esql.source_ip_count_distinct <= 5 and Esql.event_duration_seconds <= 600, "credential_stuffing",
Esql.o365_audit_UserId_lower_count_distinct == 1 and Esql.o365_audit_LogonError_count_distinct == 1 and Esql.event_count >= 20 and Esql.event_duration_seconds <= 300, "password_guessing",
"other"
)
| keep
Esql.time_window_date_trunc,
Esql.o365_audit_UserId_lower_count_distinct,
Esql_priv.o365_audit_UserId_lower_values,
Esql.o365_audit_LogonError_values,
Esql.o365_audit_LogonError_count_distinct,
Esql.o365_audit_ExtendedProperties_RequestType_values,
Esql.source_ip_values,
Esql.source_ip_count_distinct,
Esql.source_as_organization_name_values,
Esql.source_geo_country_name_values,
Esql.source_geo_country_name_count_distinct,
Esql.source_as_organization_name_count_distinct,
Esql.timestamp_first_seen,
Esql.timestamp_last_seen,
Esql.event_duration_seconds,
Esql.event_count,
Esql.brute_force_type
| where Esql.brute_force_type != "other"
O365 Excessive Single Sign-On Logon Errors
- source: elastic
- technicques:
- T1110
Description
Identifies accounts with a high number of single sign-on (SSO) logon errors. Excessive logon errors may indicate an attempt to brute force a password or SSO token.
Detection logic
event.dataset:o365.audit and event.provider:AzureActiveDirectory and event.category:authentication and o365.audit.LogonError:"SsoArtifactInvalidOrExpired"
AWS Management Console Brute Force of Root User Identity
- source: elastic
- technicques:
- T1110
Description
Identifies a high number of failed authentication attempts to the AWS management console for the Root user identity. An adversary may attempt to brute force the password for the Root user identity, as it has complete access to all services and resources for the AWS account.
Detection logic
event.dataset:aws.cloudtrail and event.provider:signin.amazonaws.com and event.action:ConsoleLogin and aws.cloudtrail.user_identity.type:Root and event.outcome:failure
Okta Brute Force or Password Spraying Attack
- source: elastic
- technicques:
- T1110
Description
Identifies a high number of failed Okta user authentication attempts from a single IP address, which could be indicative of a brute force or password spraying attack. An adversary may attempt a brute force or password spraying attack to obtain unauthorized access to user accounts.
Detection logic
event.dataset:okta.system and event.category:authentication and event.outcome:failure