Kusto Query LanguageMicrosoft Defender XDRMicrosoft SentinelSECURE

Detect QR Code-Based Phishing with KQL in Microsoft Defender XDR

QR code phishing is on the rise. Threat actors are embedding malicious URLs inside QR codes in emails, bypassing traditional email filters and luring users into scanning the codes with mobile devices. Since QR codes don’t reveal the actual URL until scanned, they provide attackers with a clever way to obscure their intentions.

Using Microsoft Defender for Office 365, we can uncover these attacks with a Kusto Query Language (KQL) script that specifically looks for QR code-originated URLs. The query correlates data across EmailUrlInfo, EmailAttachmentInfo, and EmailEvents tables, tying together the origin, delivery status, and any associated threat indicators.

Risk

Phishing remains one of the most effective tools in the threat actor’s arsenal. Embedding QR codes in emails has become an increasingly popular tactic, allowing attackers to sneak past traditional defenses and entice recipients into opening malicious links.

The challenge with QR codes is that they’re visually ambiguous — users can’t easily verify what’s embedded in them until it’s too late. When combined with enticing messages or spoofed branding, they can lead to credential theft, malware infections, and unauthorized access to corporate systems.

Query

Microsoft Sentinel

Kusto
EmailUrlInfo
| where UrlLocation == "QRCode"
| join kind=innerunique (
EmailAttachmentInfo
)
on $left.NetworkMessageId == $right.NetworkMessageId
| join kind=innerunique (
EmailEvents
| where EmailDirection == "Inbound"
| where DeliveryAction == "Delivered"
| project-rename EmailEventsThreatTypes = ThreatTypes
| extend EmailEventsThreatTypes = iff(isempty(ConfidenceLevel), "QRCode", EmailEventsThreatTypes)
| extend EmailEventsThreatTypes = iff(ConfidenceLevel has "Spam", "QRCode - Spam", EmailEventsThreatTypes)
| extend EmailEventsThreatTypes = iff(ConfidenceLevel has "Phish", "QRCode - Phish", EmailEventsThreatTypes)
| extend ConfidenceLevel = iff(ConfidenceLevel has "Low", "Low", ConfidenceLevel)
| extend ConfidenceLevel = iff(ConfidenceLevel has "Normal", "Normal", ConfidenceLevel)
| extend ConfidenceLevel = iff(ConfidenceLevel has "High", "High", ConfidenceLevel)
)
on $left.NetworkMessageId == $right.NetworkMessageId
| project-rename EmailUrlInfoThreatTypes = ThreatTypes
| project-rename ThreatTypes = EmailEventsThreatTypes
| project TimeGenerated, NetworkMessageId, ThreatTypes, ConfidenceLevel, SenderFromAddress, RecipientEmailAddress, Subject, FileName, UrlDomain, Url, DeliveryAction, DeliveryLocation

What this KQL does:

  • Filters email URL data where the link was extracted from a QR code.
  • Joins with attachment data for contextual evidence.
  • Further correlates with email event data to identify direction, delivery status, and threat classification.
  • Dynamically enriches threat types and confidence levels to highlight potential spam or phishing indicators.
  • Projects relevant fields for analyst review, including sender, recipient, subject, file name, and extracted URLs.

References

Leave a Reply

Your email address will not be published. Required fields are marked *