LoFP LoFP / it is common to see a spike of legitimate failed authentication events on monday mornings.

Techniques

Sample rules

Detect Distributed Password Spray Attempts

Description

This analytic employs the 3-sigma approach to identify distributed password spray attacks. A distributed password spray attack is a type of brute force attack where the attacker attempts a few common passwords against many different accounts, connecting from multiple IP addresses to avoid detection. By utilizing the Authentication Data Model, this detection is effective for all CIM-mapped authentication events, providing comprehensive coverage and enhancing security against these attacks.

Detection logic


| tstats `security_content_summariesonly` dc(Authentication.user) AS unique_accounts dc(Authentication.src) as unique_src count(Authentication.user) as total_failures from datamodel=Authentication.Authentication where Authentication.action="failure" by Authentication.action, Authentication.signature_id, sourcetype, _time  span=2m 
| `drop_dm_object_name("Authentication")` ```fill out time buckets for 0-count events during entire search length``` 
| appendpipe [
| timechart limit=0 span=5m count 
| table _time] 
| fillnull value=0 unique_accounts, unique_src ``` remove duplicate & empty time buckets``` 
| sort - total_failures 
| dedup _time ``` Create aggregation field & apply to all null events``` 
| eval counter=sourcetype+"__"+signature_id 
| eventstats values(counter) as fnscounter 
| eval counter=coalesce(counter,fnscounter) ``` 3-sigma detection logic ``` 
| eventstats avg(unique_accounts) as comp_avg_user , stdev(unique_accounts) as comp_std_user avg(unique_src) as comp_avg_src , stdev(unique_src) as comp_std_src by counter 
| eval upperBoundUser=(comp_avg_user+comp_std_user*3), upperBoundsrc=(comp_avg_src+comp_std_src*3) 
| eval isOutlier=if((unique_accounts > 30 and unique_accounts >= upperBoundUser) and (unique_src > 30 and unique_accounts >= upperBoundsrc), 1, 0) 
| replace "::ffff:*" with * in src 
| where isOutlier=1 
| foreach * [ eval <<FIELD>> = if(<<FIELD>>="null",null(),<<FIELD>>)] 
| table _time, action, unique_src, unique_accounts, total_failures, sourcetype, signature_id 
| sort - total_failures 
| `detect_distributed_password_spray_attempts_filter`