Rare domains seen in Cloud Logs
Description
'This script identifies rare domain accounts accessing cloud resources by examining logs. You can lower the domainLimit value to see domains with fewer access attempts. For example, set domainLimit = 2 to see domains with 2 or fewer access attempts.'
Query · kql
// Provide customLimit value with default above domainLimit value so it will not block unless changed
let customLimit = 11;
let domainLimit = 10;
let domainLookback = union isfuzzy=true
(AuditLogs
| extend UserPrincipalName = tolower(tostring(TargetResources.[0].userPrincipalName))
// parse out AuditLog values for various locations where UPN could be
| extend UserPrincipalName = iff(isnotempty(UserPrincipalName),
UserPrincipalName,
iif((tostring(InitiatedBy.user.userPrincipalName)=='unknown'),
extract("Email: ([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+)", 1, tostring(parse_json(TargetResources)[0].displayName)),
InitiatedBy.user.userPrincipalName))
| where UserPrincipalName has "@" or UserPrincipalName startswith "NT AUTHORITY"
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| where isnotempty(RareDomain)
| summarize RareDomainCount = count() by Type, RareDomain,UserPrincipalName
| where RareDomainCount <= domainLimit
| extend AccountCustomEntity = UserPrincipalName
// remove comment from below if you would like to have a lower limit for RareDomainCount specific to AuditLog
//| where RareDomainCount <= customLimit
),
(OfficeActivity
| extend UserPrincipalName = tolower(UserId)
| where UserPrincipalName has "@" or UserPrincipalName startswith "NT AUTHORITY"
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| summarize RareDomainCount = count() by Type, RareDomain, UserPrincipalName
| where RareDomainCount <= domainLimit
| extend AccountCustomEntity = UserPrincipalName
// remove comment from below if you would like to have a lower limit for RareDomainCount specific to OfficeActivity
//| where RareDomainCount <= customLimit
),
(SigninLogs
| where UserPrincipalName has "@" or UserPrincipalName startswith "NT AUTHORITY"
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| summarize RareDomainCount = count() by Type, RareDomain
| where RareDomainCount <= domainLimit
// remove comment from below if you would like to have a lower limit for RareDomainCount specific to SigninLogs
//| where RareDomainCount <= customLimit
);
let AuditLogsRef = domainLookback | join (
AuditLogs
| extend UserPrincipalName = tolower(tostring(TargetResources.[0].userPrincipalName))
| extend UserPrincipalName = iff(isempty(UserPrincipalName), tostring(InitiatedBy.user.userPrincipalName), UserPrincipalName)
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| where isnotempty(RareDomain)
| summarize UPNRefCount = count() by TimeGenerated, Type, RareDomain, UserPrincipalName, OperationName, Category, Result
| extend AccountCustomEntity = UserPrincipalName
) on Type, RareDomain;
let OfficeActivityRef = domainLookback | join (
OfficeActivity
| extend UserPrincipalName = tolower(UserId)
| where UserPrincipalName has "@" or UserPrincipalName startswith "NT AUTHORITY"
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| summarize UPNRefCount = count() by TimeGenerated, Type, RareDomain, UserPrincipalName, OperationName = Operation, Category = OfficeWorkload, Result = ResultStatus
| extend AccountCustomEntity = UserPrincipalName
) on Type, RareDomain;
let SigninLogsRef = domainLookback | join (
SigninLogs
| extend UserPrincipalName = tolower(UserId)
| where UserPrincipalName has "@" or UserPrincipalName startswith "NT AUTHORITY"
| extend RareDomain = toupper(tostring(split(UserPrincipalName, "@")[-1]))
| summarize UPNRefCount = count() by TimeGenerated, Type, RareDomain, UserPrincipalName, OperationName, Category = AppDisplayName, Result = ResultType
| extend AccountCustomEntity = UserPrincipalName
) on Type, RareDomain;
let Results = union isfuzzy=true
AuditLogsRef,OfficeActivityRef,SigninLogsRef;
Results | project TimeGenerated, Type, RareDomain, UserPrincipalName, OperationName, Category, Result, UPNRefCount
| order by TimeGenerated asc
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName