Detection rules › Kusto

Password Spray

Author
Cyb3rMonk
Source
github.com/Cyb3r-Monk/Threat-Hunting-and-Detection

Below queries detect password spray attacks using sliding window count plugin. Because of implementation of the sliding window, queries work better than the bin() usage, but may create duplicate alerts. Grouping can be used in such cases. Sentinel Query:

MITRE ATT&CK coverage

TacticTechniques
Credential AccessNo specific technique

References

Event coverage

Rule body kusto

// Author       : Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
//
// Link to original post:
// https://posts.bluraven.io/advanced-kql-for-threat-hunting-window-functions-part-2-dce3e321f54b
//
// Description  : Detect if there are more than 2 distinct users seen from the same IP in a 3h window.
//
// Query parameters:
//
let start = ago(12h);
let end = now();
let lookbackWindow = 3h;
let bin = 1h;
let threshold = 2;
SecurityEvent
| where EventID in (4624, 4625)
| where IpAddress !in ("127.0.0.1", "::1", "-")
| evaluate sliding_window_counts(TargetUserName, TimeGenerated, start, end, lookbackWindow, bin, IpAddress)
| sort by IpAddress, TimeGenerated asc
| where Dcount >= 2

// Author       : Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
//
// Link to original post:
// https://posts.bluraven.io/advanced-kql-for-threat-hunting-window-functions-part-2-dce3e321f54b
//
// Description  : Detect if there are more than 2 distinct users seen from the same IP in a 3h window.
//
// Query parameters:
//
let start = ago(12h);
let end = now();
let lookbackWindow = 3h;
let bin = 1h;
let threshold = 2;
DeviceLogonEvents
| where Timestamp > ago(lookbackWindow)
| where RemoteIP !in ("127.0.0.1","::1","-") and isnotempty(RemoteIP)
| evaluate sliding_window_counts(AccountName, Timestamp, start, end, lookbackWindow, bin, RemoteIP)
| where Dcount > threshold

Stages and Predicates

Parameters

let start = ago(12h);
let end = now();
let lookbackWindow = 3h;
let bin = 1h;
let threshold = 2;

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID in (4624, 4625)

Stage 3: where

| where IpAddress !in ("127.0.0.1", "::1", "-")

Stage 4: evaluate

| evaluate sliding_window_counts(TargetUserName, TimeGenerated, start, end, lookbackWindow, bin, IpAddress)

Stage 5: sort

| sort by IpAddress, TimeGenerated asc

Stage 6: where

| where Dcount >= 2

Exclusions

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

FieldKindExcluded values
IpAddressin-, 127.0.0.1, ::1

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
Dcountge
  • 2 transforms: cased
EventIDin
  • 4624 transforms: cased corpus 25 (splunk 13, kusto 8, chronicle 4)
  • 4625 transforms: cased corpus 15 (splunk 11, chronicle 2, kusto 2)