Detection rules › Splunk

Azure AD Multiple Denied MFA Requests For User

Status
production
Severity
medium
Group by
"status.additionalDetails", _time, aws::recipientAccountId, signature, user, vendor_product
Author
Mauricio Velazco, Splunk
Source
github.com/splunk/security_content

The following analytic detects an unusually high number of denied Multi-Factor Authentication (MFA) requests for a single user within a 10-minute window, specifically when more than nine MFA prompts are declined. It leverages Azure Active Directory (Azure AD) sign-in logs, focusing on "Sign-in activity" events with error code 500121 and additional details indicating "MFA denied; user declined the authentication." This behavior is significant as it may indicate a targeted attack or account compromise attempt, with the user actively declining unauthorized access. If confirmed malicious, it could lead to data exfiltration, lateral movement, or further malicious activities.

MITRE ATT&CK coverage

Rules detecting the same action

Other rules on this platform that filter on the same API call or operation.

Rule body splunk

name: Azure AD Multiple Denied MFA Requests For User
id: d0895c20-de71-4fd2-b56c-3fcdb888eba1
version: 13
creation_date: '2023-11-16'
modification_date: '2026-05-13'
author: Mauricio Velazco, Splunk
status: production
type: TTP
description: The following analytic detects an unusually high number of denied Multi-Factor Authentication (MFA) requests for a single user within a 10-minute window, specifically when more than nine MFA prompts are declined. It leverages Azure Active Directory (Azure AD) sign-in logs, focusing on "Sign-in activity" events with error code 500121 and additional details indicating "MFA denied; user declined the authentication." This behavior is significant as it may indicate a targeted attack or account compromise attempt, with the user actively declining unauthorized access. If confirmed malicious, it could lead to data exfiltration, lateral movement, or further malicious activities.
data_source:
    - Azure Active Directory Sign-in activity
search: |-
    `azure_monitor_aad` category=SignInLogs operationName="Sign-in activity"
      | rename properties.* as *
      | search status.errorCode=500121 status.additionalDetails="MFA denied; user declined the authentication"
      | bucket span=10m _time
      | rename userAgent as user_agent
      | fillnull
      | stats count min(_time) as firstTime max(_time) as lastTime values(dest) as dest values(user_agent) as user_agent values(src) as src
        BY user status.additionalDetails vendor_account
           vendor_product signature _time
      | where count > 9
      | `security_content_ctime(firstTime)`
      | `security_content_ctime(lastTime)`
      | `azure_ad_multiple_denied_mfa_requests_for_user_filter`
how_to_implement: You must install the latest version of Splunk Add-on for Microsoft Cloud Services from Splunkbase (https://splunkbase.splunk.com/app/3110/#/details). You must be ingesting Azure Active Directory events into your Splunk environment through an EventHub. This analytic was written to be used with the azure:monitor:aad sourcetype leveraging the Signin log category.
known_false_positives: Multiple denifed MFA requests in a short period of span may also be a sign of authentication errors. Investigate and filter as needed.
references:
    - https://www.mandiant.com/resources/blog/russian-targeting-gov-business
    - https://arstechnica.com/information-technology/2022/03/lapsus-and-solar-winds-hackers-both-use-the-same-old-trick-to-bypass-mfa/
    - https://therecord.media/russian-hackers-bypass-2fa-by-annoying-victims-with-repeated-push-notifications/
    - https://attack.mitre.org/techniques/T1621/
    - https://attack.mitre.org/techniques/T1078/004/
    - https://www.cisa.gov/sites/default/files/publications/fact-sheet-implement-number-matching-in-mfa-applications-508c.pdf
drilldown_searches:
    - name: View the detection results for - "$user$"
      search: '%original_detection_search% | search  user = "$user$"'
      earliest_offset: $info_min_time$
      latest_offset: $info_max_time$
    - name: View risk events for the last 7 days for - "$user$"
      search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$user$") | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
      earliest_offset: 7d
      latest_offset: "0"
finding:
    title: User $user$ denied more than 9 MFA requests in a timespan of 10 minutes.
    entity:
        field: user
        type: user
        score: 50
analytic_story:
    - Azure Active Directory Account Takeover
asset_type: Azure Active Directory
mitre_attack_id:
    - T1621
product:
    - Splunk Enterprise
    - Splunk Enterprise Security
    - Splunk Cloud
category: cloud
security_domain: identity
tests:
    - name: True Positive Test
      attack_data:
        - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1621/azure_ad_multiple_denied_mfa_requests/azure_ad_multiple_denied_mfa_requests.log
          source: Azure AD
          sourcetype: azure:monitor:aad
      test_type: unit

Stages and Predicates

Stage 1: search

`azure_monitor_aad` category=SignInLogs operationName="Sign-in activity"

Stage 2: rename

| rename properties.* as *

Stage 3: search

| search status.errorCode=500121 status.additionalDetails="MFA denied; user declined the authentication"

Stage 4: bucket

| bucket span=10m _time

Stage 5: rename

| rename userAgent as user_agent

Stage 6: fillnull

| fillnull

Stage 7: stats

| stats count min(_time) as firstTime max(_time) as lastTime values(dest) as dest values(user_agent) as user_agent values(src) as src
    BY user status.additionalDetails vendor_account
       vendor_product signature _time

Stage 8: where

| where count > 9

Stage 9: search

| `security_content_ctime(firstTime)`

Stage 10: search

| `security_content_ctime(lastTime)`

Stage 11: search

| `azure_ad_multiple_denied_mfa_requests_for_user_filter`

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
categoryeq
  • SignInLogs
countgt
  • 9
operationNameeq
  • "Sign-in activity"
sourcetypeeq
  • azure:monitor:aad
status.additionalDetailseq
  • "MFA denied; user declined the authentication"
status.errorCodeeq
  • 500121