CodeCommitsIssuesPull requestsActionsInsightsSecurity
891566ba25da6149c543e9c127dbf8311dc78311

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Hunting Queries/SigninLogs/AnomalousUserAppSigninLocationIncreaseDetail.txt

38lines · modecode

1// Name: anomalous sign-in location by user account and authenticating application - with sign-in details
2//
3// Id: 7f6e8f14-62fa-4ce6-a490-c07f1d9888ba
4//
5// Description: This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active
6// Directory application and picks out the most anomalous change in location profile for a user within an
7// individual application. The intent is to hunt for user account compromise, possibly via a specific application
8// vector.
9// This variation of the query joins the results back onto the original sign-in data to allow review of the
10// location set with each identified user in tabular form.
11//
12// DataSource: #SigninLogs
13//
14// Tactics: #InitialAccess
15//
16let timeRange=ago(14d);
17SigninLogs
18// Forces Log Analytics to recognize that the query should be run over full time range
19| where TimeGenerated >= timeRange
20| extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";")
21| project TimeGenerated, AppDisplayName , UserPrincipalName, locationString
22// Create time series
23| make-series dLocationCount = dcount(locationString) on TimeGenerated in range(timeRange,now(), 1d)
24by UserPrincipalName, AppDisplayName
25// Compute best fit line for each entry
26| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dLocationCount)
27// Chart the 3 most interesting lines
28// A 0-value slope corresponds to an account being completely stable over time for a given Azure Active Directory application
29| top 3 by Slope desc
30// Extract the set of locations for each top user:
31| join kind=inner (SigninLogs
32| where TimeGenerated >= timeRange
33| extend locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";")// , tostring(LocationDetails["geoCoordinates"]))
34| summarize locationList = makeset(locationString), threeDayWindowLocationCount=dcount(locationString) by AppDisplayName , UserPrincipalName, timerange=bin(TimeGenerated, 3d)) on AppDisplayName, UserPrincipalName
35| order by UserPrincipalName, timerange asc
36| project timerange, AppDisplayName , UserPrincipalName, threeDayWindowLocationCount, locationList
37| order by AppDisplayName, UserPrincipalName, timerange asc
38| extend AccountCustomEntity = UserPrincipalName