Mail Bombing Followed By External Teams Contact And Remote Access Execution
Query
let HuntLookback = 30d;
let MailBurstWindow = 15m;
let TeamsFollowupWindow = 2h;
let EndpointFollowupWindow = 4h;
let MinimumBurstMessages = 100;
let MinimumDistinctSenders = 20;
let OrgDomains = EmailEvents
| where EmailDirection == "Inbound"
| distinct RecipientDomain;
let MailBombs =
EmailEvents
| where Timestamp >= ago(HuntLookback)
| where EmailDirection =~ "Inbound"
| extend UserEmail = tolower(RecipientEmailAddress)
| summarize
FloodStart = min(Timestamp),
FloodEnd = max(Timestamp),
BurstMessageCount = count(),
DistinctSenders = dcount(SenderFromAddress),
DistinctSubjects = dcount(Subject)
by UserEmail, FloodBin = bin(Timestamp, MailBurstWindow)
| where BurstMessageCount >= MinimumBurstMessages
and DistinctSenders >= MinimumDistinctSenders;
let ExternalTeamsMessages =
MessageEvents
| where Timestamp >= ago(HuntLookback)
| mv-expand RecipientDetails
| extend
SenderEmail = tolower(SenderEmailAddress),
RecipientEmail = tolower(tostring(RecipientDetails.RecipientSmtpAddress))
| extend
SenderDomain = tolower(extract(@"@([^@]+)$", 1, SenderEmail)),
RecipientDomain = tolower(extract(@"@([^@]+)$", 1, RecipientEmail))
| where isnotempty(SenderDomain) and isnotempty(RecipientDomain)
| where SenderDomain !in (OrgDomains) and RecipientDomain in (OrgDomains)
| project
UserEmail = RecipientEmail,
TeamsTime = Timestamp,
ExternalSender = SenderEmail,
ExternalSenderDomain = SenderDomain,
TeamsMessageId;
let MailThenTeams =
MailBombs
| join kind=inner ExternalTeamsMessages on UserEmail
| where TeamsTime >= FloodStart and TeamsTime <= FloodEnd + TeamsFollowupWindow
| summarize
TeamsTime = min(TeamsTime),
ExternalSender = take_any(ExternalSender),
ExternalSenderDomain = take_any(ExternalSenderDomain),
TeamsMessageId = take_any(TeamsMessageId)
by UserEmail, FloodBin, FloodStart, FloodEnd, BurstMessageCount, DistinctSenders, DistinctSubjects;
let SuspiciousEndpointActivity =
DeviceProcessEvents
| where Timestamp >= ago(HuntLookback)
| where isnotempty(AccountUpn)
| extend
UserEmail = tolower(AccountUpn),
CommandLine = tolower(ProcessCommandLine),
ProcessName = tolower(FileName),
ParentName = tolower(InitiatingProcessFileName),
GrandparentName = tolower(InitiatingProcessParentFileName)
| extend
LaunchedFromExplorer = ParentName == "explorer.exe" or GrandparentName == "explorer.exe",
HasEncodedOrHiddenExecution = CommandLine matches regex @"(?i)(\s-enc(odedcommand)?\b|\s-w(indowstyle)?\s+hidden\b|frombase64string)",
HasRemoteFetch = CommandLine matches regex @"(?i)(https?://|downloadstring|invoke-webrequest|\biwr\b|\b(curl|wget|bitsadmin|certutil)\b)",
IsScriptOrShell = ProcessName in~ ("powershell.exe", "pwsh.exe", "cmd.exe", "mshta.exe", "wscript.exe", "cscript.exe", "curl.exe"),
IsRemoteSupportTool = ProcessName in~ (
"quickassist.exe", "anydesk.exe", "teamviewer.exe", "screenconnect.client.exe",
"rustdesk.exe", "ateraagent.exe", "splashtop.exe", "bomgar-scc.exe", "logmein.exe"
)
| where IsRemoteSupportTool
or (LaunchedFromExplorer and IsScriptOrShell and (HasEncodedOrHiddenExecution or HasRemoteFetch))
| project
UserEmail,
EndpointTime = Timestamp,
DeviceName,
DeviceId,
ProcessFileName = FileName,
ProcessCommandLine,
InitiatingProcessFileName,
InitiatingProcessParentFileName,
IsRemoteSupportTool,
HasEncodedOrHiddenExecution,
HasRemoteFetch;
MailThenTeams
| join kind=inner SuspiciousEndpointActivity on UserEmail
| where EndpointTime >= TeamsTime and EndpointTime <= TeamsTime + EndpointFollowupWindow
| extend ChainConfidence = case(
IsRemoteSupportTool and (HasEncodedOrHiddenExecution or HasRemoteFetch), "High",
IsRemoteSupportTool or (HasEncodedOrHiddenExecution and HasRemoteFetch), "High",
"Elevated")
| project
ChainConfidence,
UserEmail,
FloodStart,
FloodEnd,
BurstMessageCount,
DistinctSenders,
DistinctSubjects,
TeamsTime,
ExternalSender,
ExternalSenderDomain,
TeamsMessageId,
EndpointTime,
DeviceName,
DeviceId,
ProcessFileName,
ProcessCommandLine,
InitiatingProcessFileName,
InitiatingProcessParentFileName,
IsRemoteSupportTool,
HasEncodedOrHiddenExecution,
HasRemoteFetch
| order by iff(ChainConfidence == "High", 0, 1) asc, FloodStart desc, EndpointTime descAbout this query
Explanation
This query is designed to detect a specific type of social engineering attack that unfolds in three stages:
-
Mail Bombing: The attacker sends a large number of emails to a user within a short time frame (15 minutes), using multiple distinct senders. This is identified as a "mail bomb" if the user receives at least 100 emails from 20 different senders.
-
External Teams Contact: After the mail bombing, the attacker contacts the user via Microsoft Teams from an external domain. This contact occurs between the start of the email flood and up to two hours after it ends.
-
Remote Access Execution: Following the Teams contact, the user executes a remote access tool or a suspicious script on their device within four hours. This could involve known remote support tools or scripts executed in a way that suggests malicious intent, such as using encoded commands or fetching remote content.
The query assigns a "ChainConfidence" level to each detected sequence, indicating the likelihood of malicious activity. It also provides details about the email flood, the external Teams contact, and the endpoint process activity. The query uses specific thresholds and time windows, which can be adjusted based on the organization's typical email volume. Legitimate use of remote tools by trusted partners can be excluded to reduce false positives.