Analytic rule catalog
Failed Logins from Unknown or Invalid User
Back
| Id | 884be6e7-e568-418e-9c12-89229865ffde |
| Rulename | Failed Logins from Unknown or Invalid User |
| Description | This rule alerts when an unknown or invalid user generates more than 15 failed Okta management console login attempts from the same IP address within 5 minutes. |
| Severity | Medium |
| Tactics | CredentialAccess |
| Techniques | T1110.001 |
| 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/FailedLoginsFromUnknownOrInvalidUser.yaml |
| Version | 1.1.2 |
| Arm template | 884be6e7-e568-418e-9c12-89229865ffde.json |
// Adjust threshold for failed logins to reduce noise. This can be customized based on the organization's typical login patterns.
let FailureThreshold = 15;
// Adjust list of allowed users to reduce false positives. This can include service accounts, known test accounts, or any other accounts that are expected to generate failed login attempts.
let AllowedUsers = dynamic([]);
let FailedLogins = OktaSSO
| where eventType_s =~ "user.session.start" and outcome_reason_s =~ "VERIFICATION_ERROR"
| where isnotempty(actor_alternateId_s) and actor_alternateId_s !in (AllowedUsers)
| summarize count() by actor_alternateId_s, client_ipAddress_s, bin(TimeGenerated, 5m)
| where count_ > FailureThreshold
| project client_ipAddress_s, actor_alternateId_s;
OktaSSO
| join kind=inner (FailedLogins) on client_ipAddress_s, actor_alternateId_s
| where eventType_s =~ "user.session.start" and outcome_reason_s =~ "VERIFICATION_ERROR"
| summarize FailedLoginCount = count(), City = take_any(column_ifexists('client_geographicalContext_city_s', "")), Country = take_any(column_ifexists('client_geographicalContext_country_s', "")), LastSeen = max(column_ifexists('TimeGenerated', now())) by actor_alternateId_s, client_ipAddress_s
| sort by LastSeen desc
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
requiredDataConnectors:
- dataTypes:
- Okta_CL
connectorId: OktaSSO
- dataTypes:
- OktaSSO
connectorId: OktaSSOv2
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/FailedLoginsFromUnknownOrInvalidUser.yaml
version: 1.1.2
status: Available
alertDetailsOverride:
alertDescriptionFormat: Account {{actor_alternateId_s}} generated {{FailedLoginCount}} failed logins from IP {{client_ipAddress_s}} in the last 5 minutes.
alertDisplayNameFormat: 'Failed logins from unknown or invalid user: {{actor_alternateId_s}} from IP {{client_ipAddress_s}}'
customDetails:
City: City
FailedLoginCount: FailedLoginCount
Country: Country
queryFrequency: 1h
query: |
// Adjust threshold for failed logins to reduce noise. This can be customized based on the organization's typical login patterns.
let FailureThreshold = 15;
// Adjust list of allowed users to reduce false positives. This can include service accounts, known test accounts, or any other accounts that are expected to generate failed login attempts.
let AllowedUsers = dynamic([]);
let FailedLogins = OktaSSO
| where eventType_s =~ "user.session.start" and outcome_reason_s =~ "VERIFICATION_ERROR"
| where isnotempty(actor_alternateId_s) and actor_alternateId_s !in (AllowedUsers)
| summarize count() by actor_alternateId_s, client_ipAddress_s, bin(TimeGenerated, 5m)
| where count_ > FailureThreshold
| project client_ipAddress_s, actor_alternateId_s;
OktaSSO
| join kind=inner (FailedLogins) on client_ipAddress_s, actor_alternateId_s
| where eventType_s =~ "user.session.start" and outcome_reason_s =~ "VERIFICATION_ERROR"
| summarize FailedLoginCount = count(), City = take_any(column_ifexists('client_geographicalContext_city_s', "")), Country = take_any(column_ifexists('client_geographicalContext_country_s', "")), LastSeen = max(column_ifexists('TimeGenerated', now())) by actor_alternateId_s, client_ipAddress_s
| sort by LastSeen desc
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
tactics:
- CredentialAccess
relevantTechniques:
- T1110.001
id: 884be6e7-e568-418e-9c12-89229865ffde
triggerThreshold: 0
triggerOperator: gt
name: Failed Logins from Unknown or Invalid User
queryPeriod: 1h
severity: Medium
entityMappings:
- fieldMappings:
- columnName: AccountName
identifier: Name
- columnName: AccountUPNSuffix
identifier: UPNSuffix
entityType: Account
- fieldMappings:
- columnName: client_ipAddress_s
identifier: Address
entityType: IP
kind: Scheduled
description: |
This rule alerts when an unknown or invalid user generates more than 15 failed Okta management console login attempts from the same IP address within 5 minutes.
{
"$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/884be6e7-e568-418e-9c12-89229865ffde')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/884be6e7-e568-418e-9c12-89229865ffde')]",
"properties": {
"alertDetailsOverride": {
"alertDescriptionFormat": "Account {{actor_alternateId_s}} generated {{FailedLoginCount}} failed logins from IP {{client_ipAddress_s}} in the last 5 minutes.",
"alertDisplayNameFormat": "Failed logins from unknown or invalid user: {{actor_alternateId_s}} from IP {{client_ipAddress_s}}"
},
"alertRuleTemplateName": "884be6e7-e568-418e-9c12-89229865ffde",
"customDetails": {
"City": "City",
"Country": "Country",
"FailedLoginCount": "FailedLoginCount"
},
"description": "This rule alerts when an unknown or invalid user generates more than 15 failed Okta management console login attempts from the same IP address within 5 minutes.\n",
"displayName": "Failed Logins from Unknown or Invalid User",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "AccountName",
"identifier": "Name"
},
{
"columnName": "AccountUPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "client_ipAddress_s",
"identifier": "Address"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/FailedLoginsFromUnknownOrInvalidUser.yaml",
"query": "// Adjust threshold for failed logins to reduce noise. This can be customized based on the organization's typical login patterns.\nlet FailureThreshold = 15;\n// Adjust list of allowed users to reduce false positives. This can include service accounts, known test accounts, or any other accounts that are expected to generate failed login attempts.\nlet AllowedUsers = dynamic([]);\nlet FailedLogins = OktaSSO\n| where eventType_s =~ \"user.session.start\" and outcome_reason_s =~ \"VERIFICATION_ERROR\"\n| where isnotempty(actor_alternateId_s) and actor_alternateId_s !in (AllowedUsers)\n| summarize count() by actor_alternateId_s, client_ipAddress_s, bin(TimeGenerated, 5m)\n| where count_ > FailureThreshold\n| project client_ipAddress_s, actor_alternateId_s;\nOktaSSO\n| join kind=inner (FailedLogins) on client_ipAddress_s, actor_alternateId_s\n| where eventType_s =~ \"user.session.start\" and outcome_reason_s =~ \"VERIFICATION_ERROR\"\n| summarize FailedLoginCount = count(), City = take_any(column_ifexists('client_geographicalContext_city_s', \"\")), Country = take_any(column_ifexists('client_geographicalContext_country_s', \"\")), LastSeen = max(column_ifexists('TimeGenerated', now())) by actor_alternateId_s, client_ipAddress_s\n| sort by LastSeen desc\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": [
"T1110.001"
],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess"
],
"techniques": [
"T1110"
],
"templateVersion": "1.1.2",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}