Elastic medium stable kql
Entra ID Sign-in Brute Force Attempted (Microsoft 365)
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 data_stream.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 False Positives
- ⚠ Automated processes that attempt to authenticate using expired credentials or have misconfigured authentication settings may lead to false positives.
Field Validations
Loading…
Comments (0)
Loading comments...