Anomaly of MailItemAccess by Other Users Mailbox [Nobelium]
Description
This query looks for users accessing multiple other users' mailboxes, or accessing multiple folders in another user's mailbox. This query is inspired by an Azure Sentinel detection. Reference - https://github.com/Azure/Azure-Sentinel/blob/master/Hunting%20Queries/OfficeActivity/AnomolousUserAccessingOtherUsersMailbox.yaml
Query · kql
// Adjust this value to exclude historical activity as known good
let LookBack = 30d;
// Adjust this value to change hunting timeframe
let TimeFrame = 14d;
// Adjust this value to alter how many mailbox (other than their own) a user needs to access before being included in results
let UserThreshold = 1;
// Adjust this value to alter how many mailbox folders in other's email accounts a users needs to access before being included in results.
let FolderThreshold = 5;
let relevantMailItems = materialize (
CloudAppEvents
| where Timestamp > ago(LookBack)
| where ActionType == "MailItemsAccessed"
| where RawEventData['ResultStatus'] == "Succeeded"
| extend UserId = tostring(RawEventData['UserId'])
| extend MailboxOwnerUPN = tostring(RawEventData['MailboxOwnerUPN'])
| where tolower(UserId) != tolower(MailboxOwnerUPN)
| extend Folders = RawEventData['Folders']
| where isnotempty(Folders)
| mv-expand parse_json(Folders)
| extend foldersPath = tostring(Folders.Path)
| where isnotempty(foldersPath)
| extend ClientInfoString = RawEventData['ClientInfoString']
| extend MailBoxGuid = RawEventData['MailboxGuid']
| extend ClientIP = iif(IPAddress startswith "[", extract("\\[([^\\]]*)", 1, IPAddress), IPAddress)
| project Timestamp, ClientIP, UserId, MailboxOwnerUPN, tostring(ClientInfoString), foldersPath, tostring(MailBoxGuid)
);
let relevantMailItemsBaseLine =
relevantMailItems
| where Timestamp between(ago(LookBack) .. ago(TimeFrame))
| distinct MailboxOwnerUPN, UserId;
let relevantMailItemsHunting =
relevantMailItems
| where Timestamp between(ago(TimeFrame) .. now())
| distinct ClientIP, UserId, MailboxOwnerUPN, ClientInfoString, foldersPath, MailBoxGuid;
relevantMailItemsBaseLine
| join kind=rightanti relevantMailItemsHunting
on MailboxOwnerUPN, UserId
| summarize FolderCount = dcount(tostring(foldersPath)),
UserCount = dcount(MailBoxGuid),
foldersPathSet = make_set(foldersPath),
ClientInfoStringSet = make_set(ClientInfoString),
ClientIPSet = make_set(ClientIP),
MailBoxGuidSet = make_set(MailBoxGuid),
MailboxOwnerUPNSet = make_set(MailboxOwnerUPN)
by UserId
| where UserCount > UserThreshold or FolderCount > FolderThreshold
| extend Reason = case(
UserCount > UserThreshold and FolderCount > FolderThreshold, "Both User and Folder Threshold Exceeded",
FolderCount > FolderThreshold and UserCount < UserThreshold, "Folder Count Threshold Exceeded",
"User Threshold Exceeded"
)
| sort by UserCount desc