mirror of
https://github.com/marcredhat/kql
synced 2026-06-08 13:23:58 +00:00
33 lines
1.4 KiB
PowerQuery
33 lines
1.4 KiB
PowerQuery
// Rule: 15_slow_brute_force
|
|
// High volume of failed signins from one IP across many users
|
|
//
|
|
// Source KQL: see ../kql/15_slow_brute_force.kql
|
|
//
|
|
// HOW TO RUN
|
|
// curl POST {sdl}/api/powerQuery with this body, OR paste in
|
|
// the SDL console. Set startTime = '2h' (or wider) so the API
|
|
// scans the freshly-ingested epochs that contain the events.
|
|
//
|
|
// Time anchor at export: NOW = 2026-05-31T20:10:05+00:00
|
|
// Recent-window cutoff: 2026-05-31T18:10:05+00:00
|
|
// (`ts_epoch_ms` below is that cutoff expressed in ms.
|
|
// Re-run harness/export_rules.py to refresh after regenerating
|
|
// sample_data/events.jsonl.)
|
|
//
|
|
// Fields referenced: FailedAttempts, IPAddress, RECENT_MS, ResultType, SigninLogs, UniqueUsers, UserPrincipalName
|
|
//
|
|
// EDITING NOTE
|
|
// Every line that starts with `|` is a pipeline stage. Each `|`
|
|
// is REQUIRED. If you delete one (e.g. while changing a literal
|
|
// on the same line as a stage), SDL re-parses the keyword that
|
|
// follows as a search term and rejects the query with errors
|
|
// like `'estimate_distinct' is a grouping function`.
|
|
|
|
event_type='SigninLogs'
|
|
| filter ts_epoch_ms >= 1780251005000
|
|
| filter ResultType in (50053,50126,50055,50057,50155,50105,50133,50005,50076,50079,50173,50158,50072,50074,53003,53000,53001,50129)
|
|
| group FailedAttempts = count(),
|
|
UniqueUsers = estimate_distinct(UserPrincipalName)
|
|
by IPAddress
|
|
| filter FailedAttempts > 5 AND UniqueUsers > 5
|