Detection rules › Splunk

Multiple Failed Network Logon Attempts from Host (Windows Event Log)

Group by
_time, client_host, host, src_ip
Source
github.com/anvilogic-forge/armory

This use case detects a single source host with failed network (remote) authentication attempts from multiple user accounts in a short time period (default 2 minutes). This can be an indication of a password spraying attack from a compromised host.

MITRE ATT&CK coverage

TacticTechniques
Credential AccessT1110.003 Brute Force: Password Spraying

References

Event coverage

ProviderEventTitle
Security-AuditingEvent ID 4625An account failed to log on.

Rule body yaml

id: '35722.62685'
title: Multiple Failed Network Logon Attempts from Host
description: This use case detects a single source host with failed network (remote)
  authentication attempts from multiple user accounts in a short time period (default
  2 minutes). This can be an indication of a password spraying attack from a compromised
  host.
logic_format: Splunk
logic: '`get_endpoint_data` `get_endpoint_data_winevent` (TERM(EventCode=4625) OR
  "<EventID>4625<") Logon_Type=3 | regex src_ip!="-" | bin span=120s | stats values(*)
  as * by _time, host | eventstats dc(TargetUserName) AS unique_accounts values(TargetUserName)
  as tried_accounts by _time, src_ip, client_host | eventstats avg(unique_accounts)
  as comp_avg , stdev(unique_accounts) as comp_std by src_ip, client_host| eval upperBound=(comp_avg+comp_std*3)
  | eval isOutlier=if(unique_accounts > 10 and unique_accounts >= upperBound, 1, 0)
  | search isOutlier=1 | table _time, host, user, process, process_*, parent_*, unique_accounts,
  tried_accounts, comp_avg, comp_std, client_host '
techniques:
- credential-access:brute force
- credential-access:brute force:password spraying
technique_id:
- T1110
- T1110.003
data_category:
- Windows event logs
references:
- https://github.com/splunk/security_content/blob/main/detections/endpoint/multiple_users_remotely_failing_to_authenticate_from_host.yml

Stages and Predicates

Stage 1: search

`get_endpoint_data` `get_endpoint_data_winevent` (TERM(EventCode=4625) OR "<EventID>4625<") Logon_Type=3

Stage 2: regex

| regex src_ip!="-"

Stage 3: bucket

| bin span=120s

Stage 4: stats

| stats values(*) as * by _time, host

Stage 5: eventstats

| eventstats dc(TargetUserName) AS unique_accounts values(TargetUserName) as tried_accounts by _time, src_ip, client_host

Stage 6: eventstats

| eventstats avg(unique_accounts) as comp_avg , stdev(unique_accounts) as comp_std by src_ip, client_host

Stage 7: eval

| eval upperBound=(comp_avg+comp_std*3)

Stage 8: eval

| eval isOutlier=if(unique_accounts > 10 and unique_accounts >= upperBound, 1, 0)
isOutlier =
ifunique_accounts > 10 AND unique_accounts >= upperBound1
else0

Stage 9: search

| search isOutlier=1

Stage 10: table

| table _time, host, user, process, process_*, parent_*, unique_accounts, tried_accounts, comp_avg, comp_std, client_host

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
src_ipregex_match"-"

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
EventCodeeq
  • 4625 corpus 15 (splunk 11, chronicle 2, kusto 2)
Logon_Typeeq
  • 3 corpus 40 (splunk 13, sigma 12, elastic 9, kusto 6)
isOutliereq
  • 1 corpus 28 (splunk 28)

Search terms

Bare-string tokens in the SPL search body. Splunk matches each token against _raw (the untyped raw event text) anywhere it appears, not against a specific field. These don't surface in the Indicators table because they aren't predicates on a known field.

StageTerm
1TERM
1"<EventID>4625<"