2024-10-15 // Dylan Evans
New External Teams Chat Recipient Detection
Microsoft SentinelDetects newly added external recipients in Microsoft Teams chat threads who were not previously engaged with internal senders.
New External Teams Chat Recipient Detection
Overview
This detection identifies suspicious new external recipients in Microsoft Teams chat threads who were previously unknown to internal senders, potentially indicating phishing or credential harvesting attempts. The query compares recent chat activity with historical message recipients to flag anomalies where an external sender suddenly engages with a recipient not seen before.
Query
let LookbackPeriod = 7d; //define the period to check for known external senders
let RecentPeriod = 1d; //define the period to check for new external senders
let internalDomains = IdentityInfo
| distinct Domain = tostring(split(AccountUpn, "@")[1]); //define internal user domains
let ExternalRecipientsLastWeek =
MessageEvents
| where Timestamp between (ago(LookbackPeriod + RecentPeriod) .. ago(RecentPeriod))
| mv-expand RecipientDetails
| extend Recipient = parse_json(RecipientDetails)
| extend RecipientSmtpAddress = tostring(Recipient.RecipientSmtpAddress)
| where not(SenderEmailAddress has_any (internalDomains)) //only return check messages where the sender of the message is external
| summarize by RecipientSmtpAddress;
let ExternalRecipientsToday =
MessageEvents
| where Timestamp >= ago(RecentPeriod)
| mv-expand RecipientDetails
| extend Recipient = parse_json(RecipientDetails)
| extend RecipientSmtpAddress = tostring(Recipient.RecipientSmtpAddress)
| where not(RecipientSmtpAddress has_any (internalDomains))
| where SenderEmailAddress has_any (internalDomains)
| where ThreadType == "chat" //only check chat messages, remove this line to check all teams events
| project Timestamp, Subject, ThreadName, SenderEmailAddress, RecipientSmtpAddress;
ExternalRecipientsToday
| join kind=anti (ExternalRecipientsLastWeek) on RecipientSmtpAddress
| project Timestamp, Subject, ThreadName, SenderEmailAddress, NewExternalRecipient = RecipientSmtpAddress;
Logic Explanation
The query works in two phases:
- Historical Analysis: It first identifies all external senders (non-internal domains) who sent messages within a 7-day lookback period.
- Recent Comparison: It then checks Teams chat messages from the last day, filtering for internal sender emails and external recipients not previously seen.
The anti-join operation highlights new external recipients (
NewExternalRecipient) in today’s chats that weren’t part of prior external engagement.
Tuning Notes
False positives may occur if legitimate new team members join with external email domains (e.g., contractors) but haven’t sent messages yet.
- Suggestion: Exclude known vendor/partner domains from
internalDomainsby adding them to a whitelist.
- Suggestion: Exclude known vendor/partner domains from
ThreadType filtering restricts detection to chats; removing it could flag broader Teams events, including emails or meetings.
- Suggestion: Keep the filter if only chat-based lateral movement is critical.
RecipientSmtpAddress parsing may fail for malformed addresses (e.g., missing @). Adding a
where RecipientSmtpAddress !isnullcheck could improve reliability.- Suggestion: Add this to ensure valid addresses are processed.
References
- Microsoft Teams Security: Teams Chat Message Events
- MITRE ATT&CK: Phishing via Email (T1578)