Detection rules › Kusto
Brute force attack against user credentials (Uses Authentication Normalization)
Identifies evidence of brute force activity against a user based on multiple authentication failures and at least one successful authentication within a given time window. Note that the query does not enforce any sequence, and does not require the successful authentication to occur last. The default failure threshold is 10, success threshold is 1, and the default time window is 20 minutes. To use this analytics rule, make sure you have deployed the ASIM normalization parsers
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Credential Access | T1110 Brute Force |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Security-Auditing | Event ID 4624 | An account was successfully logged on. |
| Security-Auditing | Event ID 4625 | An account failed to log on. |
| Security-Auditing | Event ID 4634 | An account was logged off. |
Rule body kusto
id: a6c435a2-b1a0-466d-b730-9f8af69262e8
name: Brute force attack against user credentials (Uses Authentication Normalization)
description: |
'Identifies evidence of brute force activity against a user based on multiple authentication failures and at least one successful authentication within a given time window.
Note that the query does not enforce any sequence, and does not require the successful authentication to occur last.
The default failure threshold is 10, success threshold is 1, and the default time window is 20 minutes.
To use this analytics rule, make sure you have deployed the [ASIM normalization parsers](https://aka.ms/ASimAuthentication)'
severity: Medium
requiredDataConnectors: []
queryFrequency: 20m
queryPeriod: 20m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1110
tags:
- Id: 28b42356-45af-40a6-a0b4-a554cdfd5d8a
version: 1.0.0
- Schema: ASIMAuthentication
SchemaVersion: 0.1.0
query: |
let failureCountThreshold = 10;
let successCountThreshold = 1;
// let authenticationWindow = 20m; // Implicit in the analytic rule query period
imAuthentication
| where TargetUserType != "NonInteractive"
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
IpAddresses = make_set (SrcDvcIpAddr, 100),
ReportedBy = make_set (strcat (EventVendor, "/", EventProduct), 100),
FailureCount = countif(EventResult=='Failure'),
SuccessCount = countif(EventResult=='Success')
by
TargetUserId, TargetUsername, TargetUserType
| where FailureCount >= failureCountThreshold and SuccessCount >= successCountThreshold
| extend
IpAddresses = strcat_array(IpAddresses, ", "),
ReportedBy = strcat_array(ReportedBy, ", ")
| extend
Name = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 0)[0])
, TargetUsername
),
UPNSuffix = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 1)[0])
, ""
)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetUserName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
customDetails:
IpAddresses: IpAddresses
ReportedBy: ReportedBy
version: 1.2.5
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Ofer Shezaf
support:
tier: Community
categories:
domains: [ "Security - Others", "Identity" ]
Stages and Predicates
Parameters
let failureCountThreshold = 10;
let successCountThreshold = 1;
Stage 1: source
imAuthentication
Stage 2: where
| where TargetUserType != "NonInteractive"
Stage 3: summarize
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
IpAddresses = make_set (SrcDvcIpAddr, 100),
ReportedBy = make_set (strcat (EventVendor, "/", EventProduct), 100),
FailureCount = countif(EventResult=='Failure'),
SuccessCount = countif(EventResult=='Success')
by
TargetUserId, TargetUsername, TargetUserType
Stage 4: where
| where FailureCount >= failureCountThreshold and SuccessCount >= successCountThreshold
Stage 5: extend
| extend
IpAddresses = strcat_array(IpAddresses, ", "),
ReportedBy = strcat_array(ReportedBy, ", ")
Stage 6: extend
| extend
Name = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 0)[0])
, TargetUsername
),
UPNSuffix = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 1)[0])
, ""
)
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.
| Field | Kind | Values |
|---|---|---|
FailureCount | ge |
|
SuccessCount | ge |
|
TargetUserType | ne |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
EndTime | summarize |
FailureCount | summarize |
IpAddresses | extend |
ReportedBy | extend |
StartTime | summarize |
SuccessCount | summarize |
TargetUserId | summarize |
TargetUserType | summarize |
TargetUsername | summarize |
Name | extend |
UPNSuffix | extend |