CodeCommitsIssuesPull requestsActionsInsightsSecurity
891566ba25da6149c543e9c127dbf8311dc78311

Branches

Tags

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

Clone

HTTPS

Download ZIP

Hunting Queries/MultipleDataSources/RareDomainsInCloudLogs.txt

89lines · modepreview

// 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 asc