forked from Azure/Azure-Sentinel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnomalousUserAppSigninLocationIncrease-detection.yaml
More file actions
63 lines (61 loc) · 3.16 KB
/
AnomalousUserAppSigninLocationIncrease-detection.yaml
File metadata and controls
63 lines (61 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
id: 7cb8f77d-c52f-4e46-b82f-3cf2e106224a
name: Anomalous sign-in location by user account and authenticating application
description: |
'This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active
Directory application and picks out the most anomalous change in location profile for a user within an
individual application. An alert is generated for recent sign-ins that have location counts that are anomalous
over last day but also over the last 7-day and 14-day periods.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |
let lookBack_long = 14d;
let lookBack_med = 7d;
let lookBack = 1d;
SigninLogs
| where TimeGenerated >= startofday(ago(lookBack_long))
| extend locationString = strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";")
| project TimeGenerated, AppDisplayName , UserPrincipalName, locationString
// Create time series
| make-series dLocationCount = dcount(locationString) on TimeGenerated in range(startofday(ago(lookBack_long)),now(), 1d)
by UserPrincipalName, AppDisplayName
// Compute best fit line for each entry
| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dLocationCount)
// Chart the 3 most interesting lines
// A 0-value slope corresponds to an account being completely stable over time for a given Azure Active Directory application
| where Slope > 0.3
| top 50 by Slope desc
| join kind = leftsemi (
SigninLogs
| where TimeGenerated >= startofday(ago(lookBack_med))
| extend locationString = strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";")
| project TimeGenerated, AppDisplayName , UserPrincipalName, locationString
| make-series dLocationCount = dcount(locationString) on TimeGenerated in range(startofday(ago(lookBack_med)) ,now(), 1d)
by UserPrincipalName, AppDisplayName
| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dLocationCount)
| top 50 by Slope desc
| where Slope > 0.3
) on UserPrincipalName, AppDisplayName
| join kind = leftsemi (
SigninLogs
| where TimeGenerated >= startofday(ago(lookBack))
| extend locationString = strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";")
| project TimeGenerated, AppDisplayName , UserPrincipalName, locationString
| make-series dLocationCount = dcount(locationString) on TimeGenerated in range(startofday(ago(lookBack)) ,now(), 1d)
by UserPrincipalName, AppDisplayName
| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dLocationCount)
| top 50 by Slope desc
// Higher threshold requirement on last day anomaly
| where Slope > 5
) on UserPrincipalName, AppDisplayName
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName