// Name: Rare domains seen in Cloud Logs
// Description: This will identify rare domain accounts accessing or attempting to access cloud resources by examining the AuditLogs, OfficeActivity and SigninLogs
// Rare does not mean malicious, but it may be something you would be interested in investigating further
// Additionally, it is possible that there may be many domains if you have allowed access by 3rd party domain accounts.
// Lower the domainLimit value as needed. For example, if you only want to see domains that have an access attempt count of 2 or less,
// then set domainLimit = 2 below. If you need to set it lower only for a given log, then use customLimit in the same way and uncomment that line in the script.
//
// Id: 66fb97d1-55c3-4268-ac22-b9742d0fdccc
//
// DataSource: #AuditLogs, #SigninLogs, #OfficeActivity
//
// Tactics: #InitialAccess, #Discovery, #LateralMovement
//
// Provide customLimit value with default above domainLimit value so it will not block unless changed
let customLimit = 11;
let domainLimit = 10;
let lookback = 14d;
let domainLookback = union isfuzzy=true
(AuditLogs
| where TimeGenerated >= ago(lookback)
| 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
| 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
| where TimeGenerated >= ago(lookback)
| 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
| 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 TimeGenerated >= ago(lookback)
| 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
| where TimeGenerated >= ago(lookback)
| 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
| where TimeGenerated >= ago(lookback)
| 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
| where TimeGenerated >= ago(lookback)
| 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
| extend AccountCustomEntity = UserPrincipalName
| order by TimeGenerated asccloudflare/Azure-Sentinel
Publicmirrored fromhttps://github.com/cloudflare/Azure-Sentinel
Hunting Queries/MultipleDataSources/RareDomainsInCloudLogs.txt
89lines · modepreview
6 years ago