Query Details
**[IC] - KQL Techniques for Email URL Redirect Hunting**
#### MITRE ATT&CK Technique(s)
| Technique ID | Title |
| --- | --- |
| T1566.002 | Phishing: Spearphishing Link |
| Author | Sergio Albea (07/12/2025) |
| --- | --- |
**Description:** This KQL Query helps to understand all the URL Redirections from URLs received by Email using the UrlChainId identifier on KQL that groups together all URLs that belong to the same “click/redirect chain”.
When an message contains a URL, that URL may redirect through several intermediate URLs (trackers, shorteners, phishing, etc.) before land on the final site. KQL builds a URL chain from the original URL in the email through each redirect hop.
All URLs that are part of a single chain share the same UrlChainId and for each hop. On the other hand, UrlChainPosition register the position of every URL, the original one = value 0 and the other redirections tagged with next numbers(1, 2, etc. )
The following query includes different options to classify the insights into four categories:
- Tracking Domains
- Redirecting to Different Countries
- Redirecting to Different Domains
- Number of Redirections
```
// Sergio Albea 07/12/2025 ©️
let TrackingDomains = dynamic(["click/","bit.ly","bitly.com","tinyurl.com","goo.gl","t.co","ow.ly","is.gd","buff.ly","lnk.click","lnk.to","mjt.lu","mailjet.com","list-manage.com","mailchimp.com","mcsv.net","mailgun.org","sendgrid.net","sendgrid.com","createsend.com","createsend1.com","rs6.net","campaignsapp.com","mlsend.com","sendinblue.com","sibautomation.com","mailerlite.com","hs-sites.com","hscta.net","hubspot.com","hubspotlinks.com","mkto.com","mktg.com","pardot.com","eloqua.com","eloquaservice.com","activehosted.com","acems.ac","getvero.com","iterable.com","inflection.io","bnc.lt","app.link","substack.com","substackcdn.com","getrevue.co","shop.app","shopifyemail.com","klaviyo-mail.com","klaviyo.com","knowbe4.com","kb4.io","phishme.com","cofense.com"]);
EmailEvents
| where Timestamp > ago(1d)
| extend IPSender = iff(isnotempty( SenderIPv4),SenderIPv4,SenderIPv6)
| extend GeoIPData = tostring(geo_info_from_ip_address(IPSender).country)
| join kind=inner ( EmailUrlInfo | where isnotempty(UrlChainId)) on NetworkMessageId
// Pivot URLs by position
| summarize
UrlPos_0 = anyif(Url, UrlChainPosition == 0),UrlPos_1= anyif(Url, UrlChainPosition == 1),UrlPos_2= anyif(Url, UrlChainPosition == 2),UrlPos_3 = anyif(Url, UrlChainPosition == 3),
IP_Url_0 = anyif(IPSender, UrlChainPosition == 0),IP_Url_1= anyif(IPSender, UrlChainPosition == 1),IP_Url_2= anyif(IPSender, UrlChainPosition == 2),IP_Url_3= anyif(IPSender, UrlChainPosition == 3),
C_Url_0 = anyif(GeoIPData, UrlChainPosition == 0),C_Url_1= anyif(GeoIPData, UrlChainPosition == 1),C_Url_2= anyif(GeoIPData, UrlChainPosition == 2),C_Url_3= anyif(GeoIPData, UrlChainPosition == 3),
URL_Redirections = dcount(UrlChainPosition),Senders=dcount(SenderFromAddress),Recipients = dcount(RecipientEmailAddress),IP_Country= make_set(strcat(SenderIPv4, " ", GeoIPData)) by UrlChainId,ThreatTypes
| where isnotempty(UrlPos_0)
| extend Tracking_Marketing_URL0 = (iff(UrlPos_0 has_any (TrackingDomains),"Yes","Not")),Tracking_Marketing_URL1 =(iff(UrlPos_1 has_any (TrackingDomains),"Yes","Not")),Tracking_Marketing_URL2 = (iff(UrlPos_2 has_any (TrackingDomains),"Yes","Not")),Tracking_Marketing_URL3 = (iff(UrlPos_3 has_any (TrackingDomains),"Yes","Not"))
| summarize by Senders,URL_Redirections,UrlPos_0,IP_Url_0,C_Url_0,Tracking_Marketing_URL0, UrlPos_1,IP_Url_1,C_Url_1,Tracking_Marketing_URL1, UrlPos_2,IP_Url_2,C_Url_2,Tracking_Marketing_URL2, UrlPos_3,IP_Url_3,C_Url_3,Tracking_Marketing_URL3,Recipients,tostring(IP_Country),UrlChainId,ThreatTypes
| extend Domain_URL0 = tostring(parse_url(UrlPos_0).Host), Domain_URL1 = tostring(parse_url(UrlPos_1).Host), Domain_URL2 = tostring(parse_url(UrlPos_2).Host), Domain_URL3 = tostring(parse_url(UrlPos_3).Host)
| extend Info="ℹ️",0_ = "0️⃣",1_ = "1️⃣",2_ = "2️⃣",3_ ="3️⃣" //Icons
//Search for specific URL | extend URL = "office" | where UrlPos_0 contains URL or UrlPos_1 contains URL or UrlPos_2 contains URL or UrlPos_3 contains URL
//Search for URL on distinct countries | where (C_Url_0 !has C_Url_1 or C_Url_0 !has C_Url_2 or C_Url_0 !has C_Url_3 or C_Url_1 !has C_Url_2 or C_Url_1 !has C_Url_3 or C_Url_2 !has C_Url_3)
//Search for URL that contains specific countries | where (C_Url_0 !in ("Switzerland","Germany")) or (C_Url_1 in ("Russia","Singapore"))
//Search for URL on distinct domains | where (Domain_URL0 !has Domain_URL1 or Domain_URL0 !has Domain_URL1 or Domain_URL0 !has Domain_URL3 or Domain_URL1 !has Domain_URL2 or Domain_URL1 !has Domain_URL3 or Domain_URL2 !has Domain_URL3)
//Search for number of redirections | where URL_Redirections > 2
| project Info,URL_Redirections,ThreatTypes,Senders, Recipients,0_,Domain_URL0,UrlPos_0, IP_Url_0,C_Url_0, Tracking_Marketing_URL0,1_,Domain_URL1,UrlPos_1,IP_Url_1,C_Url_1,Tracking_Marketing_URL1,2_,Domain_URL2,UrlPos_2,IP_Url_2,C_Url_2, Tracking_Marketing_URL2,3_,Domain_URL3,UrlPos_3,IP_Url_3,C_Url_3,Tracking_Marketing_URL3
| order by ThreatTypes
```
This KQL (Kusto Query Language) script is designed to analyze email events to identify and understand URL redirections that occur when a user clicks on a link in an email. The query focuses on detecting potential phishing attempts and tracking activities by examining the chain of URLs that a single click might traverse.
Here's a simplified breakdown of what the query does:
Data Collection: It starts by collecting email events from the last day, focusing on those that contain URLs with a UrlChainId. This identifier groups URLs that are part of the same redirection chain.
URL Redirection Analysis: The query examines each URL in the redirection chain, noting their positions (e.g., original URL, first redirect, second redirect, etc.). It also captures the sender's IP address and geographical location.
Classification: The URLs are classified into four categories:
Summarization: The query summarizes the data, providing insights into the sender, recipient, number of redirections, and whether any URLs are associated with tracking domains.
Filtering Options: The script includes commented-out sections that allow users to filter results based on specific criteria, such as URLs containing certain keywords, redirections across different countries or domains, and chains with a specific number of redirections.
Output: The final output is a table that presents the summarized information, including the domains and positions of URLs in the chain, sender and recipient details, and any identified threat types.
Overall, this query helps security analysts detect and investigate potential phishing attacks by analyzing the behavior of URLs in email communications.

Sergio Albea
Released: December 8, 2025
Tables
Keywords
Operators