Correlate external Teams support contact with remote-assistance launches
Finding
The first search identifies users who receive suspicious external support contact and then launch remote-assistance tools.
This cross-domain correlation is more useful than hunting Teams messages or Quick Assist in isolation.
View query
Q-01First searchCorrelate external Teams support contact with remote-assistance launches
What this checks
Find users who received external support-themed Teams contact and then launched remote-assistance software within thirty minutes.
KQL
let correlation_window = 30m;
let organization_domains = dynamic(["example.com"]);
let support_terms = dynamic([
"helpdesk",
"help desk",
"it support",
"microsoft support",
"security",
"service desk"
]);
let teams =
MessageEvents
| where Timestamp >= ago(1d)
| extend Recipient=parse_json(RecipientDetails)
| mv-expand Recipient
| extend
VictimAccountObjectId=tostring(Recipient.RecipientObjectId),
VictimRecipientDisplayName=tostring(Recipient.RecipientDisplayName),
SenderDomain=tolower(extract(@"@([^>]+)$", 1, SenderEmailAddress))
| where isnotempty(VictimAccountObjectId)
| where isnotempty(SenderDomain) and SenderDomain !in~ (organization_domains)
| where SenderDisplayName has_any (support_terms)
| project
TeamTime=Timestamp,
SenderEmailAddress,
SenderDisplayName,
SenderDomain,
VictimRecipientDisplayName,
VictimAccountObjectId,
NetworkMessageId;
let remote_assist =
DeviceProcessEvents
| where Timestamp >= ago(1d)
| where FileName in~ ("QuickAssist.exe","AnyDesk.exe","TeamViewer.exe")
| where isnotempty(AccountObjectId)
| project
AssistTime=Timestamp,
DeviceId,
DeviceName,
AccountUpn,
UserObjectId=AccountObjectId,
AssistProcess=FileName,
AssistCommandLine=ProcessCommandLine,
AssistProcessUniqueId=ProcessUniqueId;
remote_assist
| join kind=inner teams on $left.UserObjectId == $right.VictimAccountObjectId
| where AssistTime between (TeamTime .. TeamTime + correlation_window)
| project TeamTime,AssistTime,DeviceName,AccountUpn,SenderEmailAddress,SenderDisplayName,SenderDomain,AssistProcess,AssistCommandLine,NetworkMessageId
| order by AssistTime descSPL
(
index=<teams_message_index> sourcetype=<defender_messageevents_sourcetype> earliest=-7d
)
OR
(
index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-7d
)
| eval
user_object_id=coalesce(user_object_id,AccountObjectId,RecipientObjectId),
sender=lower(coalesce(sender,SenderEmailAddress)),
sender_display=lower(coalesce(sender_display,SenderDisplayName)),
sender_domain=lower(replace(sender,"^.*@","")),
device=coalesce(device,DeviceName,host),
process_name=lower(coalesce(process_name,FileName)),
event_type=case(
isnotnull(SenderEmailAddress),"teams",
process_name IN ("quickassist.exe","anydesk.exe","teamviewer.exe"),"remote_assist",
true(),"other"
),
external_support=if(
event_type="teams"
AND sender_domain!="example.com"
AND (
like(sender_display,"%helpdesk%")
OR like(sender_display,"%help desk%")
OR like(sender_display,"%it support%")
OR like(sender_display,"%microsoft support%")
OR like(sender_display,"%security%")
OR like(sender_display,"%service desk%")
),1,0
)
| where event_type!="other"
| sort 0 user_object_id _time
| streamstats current=f
last(eval(if(event_type="teams" AND external_support=1,_time,null()))) as teams_time
last(eval(if(event_type="teams" AND external_support=1,sender,null()))) as teams_sender
last(eval(if(event_type="teams" AND external_support=1,sender_display,null()))) as teams_sender_display
by user_object_id
| where event_type="remote_assist" AND isnotnull(teams_time) AND _time>=teams_time AND _time<=teams_time+1800
| table _time teams_time user_object_id device teams_sender teams_sender_display process_name ProcessCommandLine
| sort - _timeWhat to look for
A population of collaboration-to-remote-access candidates requiring shell and endpoint review.
Technical details
Tested signal
External support pretext followed by Quick Assist / AnyDesk / TeamViewer.
Assumptions
- MessageEvents and DeviceProcessEvents can be linked through recipient/account object ID.
- Local organization domains are known.
Data requirements and relevant fields
- saas audit
Microsoft Defender XDR MessageEvents representing Microsoft Teams collaboration events with sender and recipient identity context.
TimestampSenderEmailAddressSenderDisplayNameRecipientDetailsNetworkMessageIdThreatTypesDeliveryAction
- process
Microsoft Defender for Endpoint process creation telemetry with user, stable process identity, parent context, path, command line, and hashes.
TimestampDeviceIdDeviceNameFileNameFolderPathProcessIdProcessUniqueIdProcessCommandLineProcessVersionInfoOriginalFileNameAccountUpnAccountObjectIdAccountNameSHA1SHA256InitiatingProcessFileNameInitiatingProcessCommandLineInitiatingProcessIdInitiatingProcessUniqueIdInitiatingProcessAccountUpnInitiatingProcessAccountObjectId
KQL schema
Validate Microsoft Defender for Office 365 / Teams message coverage, Defender for Endpoint deployment, field population, and local retention.
SPL schema
Replace index/sourcetype placeholders and normalize collaboration, process, network, and account fields to the local data model.
Limitations
- Approved outsourced support can produce the same pattern.
KQL uses Microsoft Defender XDR collaboration and endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.