Query Details

HUNT 11 M365 Teams Guest Message Links 30d

Query

// Hunt    : M365 - Teams Messages with External Links Sent by Guests (30d)
// Purpose : Enumerate all Teams messages containing external URLs sent by guest
//           users over 30 days. Supports phishing campaign investigation,
//           C2 link distribution analysis, and guest account compromise review.
// Tables  : OfficeActivity
// Period  : P30D
//==========================================================================================

let LookbackDays = 30d;
let SuspiciousUrlPatterns = dynamic([
    "bit.ly", "tinyurl", "t.co", "ow.ly", "goo.gl",
    "ngrok.io", "loca.lt", "serveo.net",
    "pastebin", "hastebin", "repl.it", "glitch.me"
]);

OfficeActivity
| where TimeGenerated > ago(LookbackDays)
| where RecordType == "MicrosoftTeams"
| where Operation in ("MessageCreatedHasLink", "MessageCreated")
| where UserId has "#EXT#"      // guest accounts only
| extend MessageText   = coalesce(tostring(ExtraProperties[0].Value), tostring(ItemName))
| extend ChannelLower  = tolower(ChannelName)
| extend
    IsSuspiciousUrl = MessageText has_any (SuspiciousUrlPatterns),
    GuestDomain     = tostring(extract(@"#EXT#@(.+)", 1, UserId))
| summarize
    MessageCount     = count(),
    SuspiciousLinks  = countif(IsSuspiciousUrl),
    Teams            = make_set(TeamName, 10),
    Channels         = make_set(ChannelName, 10),
    URLSample        = make_set(MessageText, 10),
    ClientIPs        = make_set(ClientIP, 5),
    FirstMessage     = min(TimeGenerated),
    LastMessage      = max(TimeGenerated)
    by UserId, GuestDomain
| sort by SuspiciousLinks desc, MessageCount desc
| project
    UserId,
    GuestDomain,
    MessageCount,
    SuspiciousLinks,
    Teams,
    Channels,
    URLSample,
    ClientIPs,
    FirstMessage,
    LastMessage

Explanation

This query is designed to identify and analyze Microsoft Teams messages that contain external URLs sent by guest users over the past 30 days. Here's a simplified breakdown of what the query does:

  1. Time Frame: It looks at data from the last 30 days.

  2. Suspicious URLs: It defines a list of suspicious URL patterns, such as shortened links (e.g., bit.ly, tinyurl) and other potentially risky domains.

  3. Data Source: The query examines the OfficeActivity table, focusing on records related to Microsoft Teams messages.

  4. Guest Users: It filters for messages sent by guest users, identified by the presence of "#EXT#" in their user ID.

  5. Message Analysis:

    • It extracts the message text and converts channel names to lowercase for consistency.
    • It checks if the message text contains any of the suspicious URL patterns.
    • It extracts the domain of the guest user for further analysis.
  6. Summary Statistics:

    • It counts the total number of messages and those containing suspicious links for each guest user.
    • It compiles a list of up to 10 different Teams and Channels where these messages were sent.
    • It provides a sample of up to 10 message texts and up to 5 client IP addresses associated with these messages.
    • It records the time of the first and last message sent by each guest user.
  7. Sorting and Output:

    • The results are sorted by the number of suspicious links and total message count in descending order.
    • The final output includes user ID, guest domain, message counts, suspicious link counts, associated Teams and Channels, sample URLs, client IPs, and the time range of the messages.

This query is useful for investigating potential phishing campaigns, command-and-control (C2) link distribution, and reviewing possible guest account compromises in Microsoft Teams.

Details

David Alonso profile picture

David Alonso

Released: March 18, 2026

Tables

OfficeActivity

Keywords

TeamsMessagesExternalLinksGuestsPhishingCampaignInvestigationC2LinkDistributionGuestAccountCompromiseOfficeActivity

Operators

letdynamicagoinhascoalescetostringtolowerhas_anyextractsummarizecountcountifmake_setminmaxbysortdescproject

Actions