Analytic rule catalog
MFA Fatigue OKTA
Back
| Id | c2697b81-7fe9-4f57-ba1d-de46c6f91f9c |
| Rulename | MFA Fatigue (OKTA) |
| Description | MFA fatigue attack is a cybersecurity threat where attackers exploit user exhaustion from multi-factor authentication prompts to trick them into approving multi-factor authentication prompts, potentially compromising their own security. The query identifies MFA fatigue attempts in Okta by correlating repeated Okta Verify push requests, denied pushes, and eventual successful MFA authentication within the same session. Ref: https://www.okta.com/blog/identity-security/mfa-fatigue-growing-security-concern/. |
| Severity | Medium |
| Tactics | CredentialAccess |
| Techniques | T1621 |
| Required data connectors | OktaSSO OktaSSOv2 |
| Kind | Scheduled |
| Query frequency | 1h |
| Query period | 1h |
| Trigger threshold | 0 |
| Trigger operator | gt |
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/MFAFatigue.yaml |
| Version | 1.1.3 |
| Arm template | c2697b81-7fe9-4f57-ba1d-de46c6f91f9c.json |
// Adjust threshold for MFA pushes to reduce noise
let PushThreshold = 10;
OktaSSO
| where ((eventType_s =="user.authentication.auth_via_mfa" and column_ifexists('debugContext_debugData_factor_s', '') == "OKTA_VERIFY_PUSH") or eventType_s == "system.push.send_factor_verify_push" or eventType_s == "user.mfa.okta_verify.deny_push")
| summarize IPAddress = make_set(client_ipAddress_s,100), City = make_set(client_geographicalContext_city_s,100),
successes = countif(eventType_s == "user.authentication.auth_via_mfa"),
denies = countif(eventType_s == "user.mfa.okta_verify.deny_push"),
pushes = countif(eventType_s == "system.push.send_factor_verify_push") by TimeGenerated, authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s
| summarize lasttime = max(TimeGenerated), firsttime = min(TimeGenerated),
successes = sum(successes), failures = sum(denies), pushes = sum(pushes) by authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s
| extend seconds = lasttime - firsttime
| where pushes > PushThreshold
| extend totalattempts = successes + failures
| extend finding = case(
failures == pushes and pushes > 1, "Authentication attempts not successful because multiple pushes denied",
totalattempts == 0, "Multiple pushes sent and ignored",
successes > 0 and pushes > 3, "Multiple pushes sent, eventual successful authentication!",
"Normal authentication pattern")
| project lasttime, firsttime, seconds, actor_alternateId_s, actor_displayName_s, authenticationContext_externalSessionId_s, pushes, successes, failures, totalattempts, finding, outcome_result_s
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/MFAFatigue.yaml
triggerThreshold: 0
id: c2697b81-7fe9-4f57-ba1d-de46c6f91f9c
kind: Scheduled
relevantTechniques:
- T1621
version: 1.1.3
tactics:
- CredentialAccess
queryPeriod: 1h
queryFrequency: 1h
alertDetailsOverride:
alertDescriptionFormat: Okta session {{authenticationContext_externalSessionId_s}} recorded {{pushes}} MFA pushes, over {{seconds}} seconds.
alertDisplayNameFormat: MFA fatigue suspected for user {{actor_displayName_s}} ({{actor_alternateId_s}})
severity: Medium
name: MFA Fatigue (OKTA)
customDetails:
Successes: successes
SessionId: authenticationContext_externalSessionId_s
Pushes: pushes
Denies: failures
Duration: seconds
TotalAttempts: totalattempts
requiredDataConnectors:
- connectorId: OktaSSO
dataTypes:
- Okta_CL
- connectorId: OktaSSOv2
dataTypes:
- OktaSSO
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
description: |
MFA fatigue attack is a cybersecurity threat where attackers exploit user exhaustion from multi-factor authentication prompts to trick them into approving multi-factor authentication prompts, potentially compromising their own security. The query identifies MFA fatigue attempts in Okta by correlating repeated Okta Verify push requests, denied pushes, and eventual successful MFA authentication within the same session.
Ref: https://www.okta.com/blog/identity-security/mfa-fatigue-growing-security-concern/.
status: Available
query: |
// Adjust threshold for MFA pushes to reduce noise
let PushThreshold = 10;
OktaSSO
| where ((eventType_s =="user.authentication.auth_via_mfa" and column_ifexists('debugContext_debugData_factor_s', '') == "OKTA_VERIFY_PUSH") or eventType_s == "system.push.send_factor_verify_push" or eventType_s == "user.mfa.okta_verify.deny_push")
| summarize IPAddress = make_set(client_ipAddress_s,100), City = make_set(client_geographicalContext_city_s,100),
successes = countif(eventType_s == "user.authentication.auth_via_mfa"),
denies = countif(eventType_s == "user.mfa.okta_verify.deny_push"),
pushes = countif(eventType_s == "system.push.send_factor_verify_push") by TimeGenerated, authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s
| summarize lasttime = max(TimeGenerated), firsttime = min(TimeGenerated),
successes = sum(successes), failures = sum(denies), pushes = sum(pushes) by authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s
| extend seconds = lasttime - firsttime
| where pushes > PushThreshold
| extend totalattempts = successes + failures
| extend finding = case(
failures == pushes and pushes > 1, "Authentication attempts not successful because multiple pushes denied",
totalattempts == 0, "Multiple pushes sent and ignored",
successes > 0 and pushes > 3, "Multiple pushes sent, eventual successful authentication!",
"Normal authentication pattern")
| project lasttime, firsttime, seconds, actor_alternateId_s, actor_displayName_s, authenticationContext_externalSessionId_s, pushes, successes, failures, totalattempts, finding, outcome_result_s
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/c2697b81-7fe9-4f57-ba1d-de46c6f91f9c')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/c2697b81-7fe9-4f57-ba1d-de46c6f91f9c')]",
"properties": {
"alertDetailsOverride": {
"alertDescriptionFormat": "Okta session {{authenticationContext_externalSessionId_s}} recorded {{pushes}} MFA pushes, over {{seconds}} seconds.",
"alertDisplayNameFormat": "MFA fatigue suspected for user {{actor_displayName_s}} ({{actor_alternateId_s}})"
},
"alertRuleTemplateName": "c2697b81-7fe9-4f57-ba1d-de46c6f91f9c",
"customDetails": {
"Denies": "failures",
"Duration": "seconds",
"Pushes": "pushes",
"SessionId": "authenticationContext_externalSessionId_s",
"Successes": "successes",
"TotalAttempts": "totalattempts"
},
"description": "MFA fatigue attack is a cybersecurity threat where attackers exploit user exhaustion from multi-factor authentication prompts to trick them into approving multi-factor authentication prompts, potentially compromising their own security. The query identifies MFA fatigue attempts in Okta by correlating repeated Okta Verify push requests, denied pushes, and eventual successful MFA authentication within the same session. \nRef: https://www.okta.com/blog/identity-security/mfa-fatigue-growing-security-concern/.\n",
"displayName": "MFA Fatigue (OKTA)",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "AccountName",
"identifier": "Name"
},
{
"columnName": "AccountUPNSuffix",
"identifier": "UPNSuffix"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/MFAFatigue.yaml",
"query": "// Adjust threshold for MFA pushes to reduce noise\nlet PushThreshold = 10;\nOktaSSO\n| where ((eventType_s ==\"user.authentication.auth_via_mfa\" and column_ifexists('debugContext_debugData_factor_s', '') == \"OKTA_VERIFY_PUSH\") or eventType_s == \"system.push.send_factor_verify_push\" or eventType_s == \"user.mfa.okta_verify.deny_push\") \n| summarize IPAddress = make_set(client_ipAddress_s,100), City = make_set(client_geographicalContext_city_s,100),\n successes = countif(eventType_s == \"user.authentication.auth_via_mfa\"),\n denies = countif(eventType_s == \"user.mfa.okta_verify.deny_push\"),\n pushes = countif(eventType_s == \"system.push.send_factor_verify_push\") by TimeGenerated, authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s \n| summarize lasttime = max(TimeGenerated), firsttime = min(TimeGenerated),\n successes = sum(successes), failures = sum(denies), pushes = sum(pushes) by authenticationContext_externalSessionId_s, actor_alternateId_s,actor_displayName_s, outcome_result_s \n| extend seconds = lasttime - firsttime\n| where pushes > PushThreshold\n| extend totalattempts = successes + failures\n| extend finding = case(\n failures == pushes and pushes > 1, \"Authentication attempts not successful because multiple pushes denied\",\n totalattempts == 0, \"Multiple pushes sent and ignored\",\n successes > 0 and pushes > 3, \"Multiple pushes sent, eventual successful authentication!\",\n \"Normal authentication pattern\")\n| project lasttime, firsttime, seconds, actor_alternateId_s, actor_displayName_s, authenticationContext_externalSessionId_s, pushes, successes, failures, totalattempts, finding, outcome_result_s\n| extend AccountName = tostring(split(actor_alternateId_s, \"@\")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, \"@\")[1])\n",
"queryFrequency": "PT1H",
"queryPeriod": "PT1H",
"severity": "Medium",
"status": "Available",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess"
],
"techniques": [
"T1621"
],
"templateVersion": "1.1.3",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}