Detection rules › Splunk
Detect Excessive User Account Lockouts
The following analytic identifies user accounts experiencing an excessive number of lockouts within a short timeframe. It leverages the 'Change' data model, specifically focusing on events where the result indicates a lockout. This activity is significant as it may indicate a brute-force attack or misconfiguration, both of which require immediate attention. If confirmed malicious, this behavior could lead to account compromise, unauthorized access, and potential lateral movement within the network.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | T1078.003 Valid Accounts: Local Accounts |
| Persistence | T1078.003 Valid Accounts: Local Accounts |
| Privilege Escalation | T1078.003 Valid Accounts: Local Accounts |
| Stealth | T1078.003 Valid Accounts: Local Accounts |
Rule body splunk
name: Detect Excessive User Account Lockouts
id: 95a7f9a5-6096-437e-a19e-86f42ac609bd
version: 15
creation_date: '2020-04-29'
modification_date: '2026-05-13'
author: David Dorsey, Splunk
status: production
type: Anomaly
description: The following analytic identifies user accounts experiencing an excessive number of lockouts within a short timeframe. It leverages the 'Change' data model, specifically focusing on events where the result indicates a lockout. This activity is significant as it may indicate a brute-force attack or misconfiguration, both of which require immediate attention. If confirmed malicious, this behavior could lead to account compromise, unauthorized access, and potential lateral movement within the network.
data_source: []
search: |-
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime FROM datamodel=Change.All_Changes
WHERE All_Changes.result="*lock*"
BY All_Changes.user All_Changes.result
| `drop_dm_object_name("All_Changes")`
| `drop_dm_object_name("Account_Management")`
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| search count > 5
| `detect_excessive_user_account_lockouts_filter`
how_to_implement: ou must ingest your Windows security event logs in the `Change` datamodel under the nodename is `Account_Management`, for this search to execute successfully. Please consider updating the cron schedule and the count of lockouts you want to monitor, according to your environment.
known_false_positives: It is possible that a legitimate user is experiencing an issue causing multiple account login failures leading to lockouts.
references: []
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"
intermediate_findings:
entities:
- field: user
type: user
score: 20
message: Excessive user account lockouts for $user$ in a short period of time
analytic_story:
- Active Directory Password Spraying
- Scattered Lapsus$ Hunters
asset_type: Windows
mitre_attack_id:
- T1078.003
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
category: endpoint
security_domain: access
tests:
- name: True Positive Test
attack_data:
- data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1078.002/account_lockout/windows-xml-1.log
source: XmlWinEventLog:Security
sourcetype: XmlWinEventLog
test_type: unit
Stages and Predicates
Stage 1: tstats
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime FROM datamodel=Change.All_Changes
WHERE All_Changes.result="*lock*"
BY All_Changes.user All_Changes.result
Stage 2: search
| `drop_dm_object_name("All_Changes")`
Stage 3: search
| `drop_dm_object_name("Account_Management")`
Stage 4: search
| `security_content_ctime(firstTime)`
Stage 5: search
| `security_content_ctime(lastTime)`
Stage 6: search
| search count > 5
Stage 7: search
| `detect_excessive_user_account_lockouts_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.
| Field | Kind | Values |
|---|---|---|
All_Changes.result | eq |
|
count | gt |
|