cloudflare/Azure-Sentinel
Publicmirrored fromhttps://github.com/cloudflare/Azure-Sentinel
Hunting Queries/SigninLogs/signinBurstFromMultipleLocations.txt
44lines · modecode
6 years ago
| 1 | // Name: Azure Active Directory sign-in burst from multiple locations |
| 2 | // |
| 3 | // Id: 745a22ec-fed8-49b9-9f62-4570b7709da4 |
| 4 | // |
| 5 | // Description: This query over Azure Active Directory sign-in activity highlights accounts associated |
| 6 | // with multiple authentications from different geographical locations in a short space of time. |
| 7 | // |
| 8 | // DataSource: #SigninLogs |
| 9 | // |
| 10 | // Tactics: #InitialAccess |
| 11 | // |
| 12 | let timeRange=ago(10d); |
| 13 | let signIns = SigninLogs |
| 14 | | where TimeGenerated >= timeRange |
| 15 | | extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"])) // , ";" , tostring(LocationDetails["geoCoordinates"])) |
| 16 | | where locationString != "//" |
| 17 | // filter out signins associated with top 100 signin locations |
| 18 | | join kind=anti (SigninLogs |
| 19 | | extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", |
| 20 | tostring(LocationDetails["city"])) // , ";" , tostring(LocationDetails["geoCoordinates"])) |
| 21 | | where locationString != "//" |
| 22 | | summarize count() by locationString |
| 23 | | order by count_ desc |
| 24 | | take 100) on locationString ; // TODO - make this threshold percentage-based |
| 25 | // We will perform a time window join to identify signins from multiple locations within a 10-minute period |
| 26 | let lookupWindow = 10m; |
| 27 | let lookupBin = lookupWindow / 2.0; // lookup bin = equal to 1/2 of the lookup window |
| 28 | signIns |
| 29 | | project-rename Start=TimeGenerated |
| 30 | | extend TimeKey = bin(Start, lookupBin) |
| 31 | | join kind = inner ( |
| 32 | signIns | project-rename End=TimeGenerated, EndLocationString=locationString |
| 33 | // TimeKey on the right side of the join - emulates this authentication appearing several times |
| 34 | | extend TimeKey = range(bin(End - lookupWindow, lookupBin), |
| 35 | bin(End, lookupBin), |
| 36 | lookupBin) |
| 37 | | mvexpand TimeKey to typeof(datetime) // translate TimeKey arrange range to a column |
| 38 | ) on Identity, TimeKey |
| 39 | | where End > Start |
| 40 | | project timeSpan = End - Start, Identity, locationString, EndLocationString,tostring(Start), tostring(End), UserPrincipalName |
| 41 | | where locationString != EndLocationString |
| 42 | | summarize by timeSpan, Identity, locationString, EndLocationString, Start, End, UserPrincipalName |
| 43 | | extend AccountCustomEntity = UserPrincipalName |
| 44 | | order by Identity |