Home NewsX Detecting AiTM Phishing via 3rd-Party Network events in Unified Security Operations Platform

Detecting AiTM Phishing via 3rd-Party Network events in Unified Security Operations Platform

by info.odysseyx@gmail.com
0 comment 9 views


Microsoft Security has evolved from individual security products such as endpoint, email, identity, and apps to an Extended Detection and Response (XDR) solution, and also offers a cloud-based SIEM solution, Microsoft Sentinel. Despite these two strong security backbones, we have made tremendous progress by integrating our SIEM and XDR experiences into a single platform called the Unified Security Operations Platform. This platform provides comprehensive visibility, investigation, and response capabilities across endpoints, hybrid identities, email, collaboration tools, cloud apps, cloud workloads, and data.

When it comes to Advanced Hunting capabilities, there are now no boundaries for threat hunting. Security analysts have access to a variety of tables across Microsoft Defender XDR and Microsoft Sentinel. However, with the introduction of the unified hunting environment, the “SecurityAlert” table, which previously contained data from Microsoft security solutions and was available in Microsoft Sentinel, is no longer in Advanced Hunting. Instead, Advanced Hunting now has “Notification information” and “Warning Evidence” Table.

Hunting man-in-the-middle (AiTM) attacks is a great example of how advanced hunting can provide additional insights. AiTM attacks use sophisticated tactics, including creating fraudulent sites that intercept user login credentials. This allows attackers to hijack login sessions and bypass authentication protections. Users with multi-factor authentication (MFA) enabled can also fall for this method. In addition to providing out-of-the-box (OOTB) detection alerts, the Unified Security Operations Platform includes: Attack interference Thanks to its ability to stop persistent attacks, Correlation mechanism And various signals from Microsoft Defender XDR. While the unified security operations platform provides a significant number of AiTM detections, you may still need visibility into how third-party network activity and network detections correlate with your own logs, such as Entra ID login events and AiTM-related URL click behavior. So we currently have two queries that we would like to provide.

Hunting AiTM Phishing Events on the Unified Security Operations Platform

These two KQL queries leverage four data tables. The first is Common Security Log The table stores third-party network logs from sources such as ‘Palo Alto Networks’, ‘Fortnite’, ‘Check Point’, ‘Zscaler’, which are provided through Microsoft Sentinel. The second is the SigninLogs table, which contains Microsoft Entra ID sign-in event data from Microsoft Sentinel. Finally, the AlertEvidence and AlertInfo tables contain detection data from Microsoft Defender XDR. By using join operations and binding common keys across four different data tables within a single platform, we can detect AiTM-related suspicious activities in Advanced Hunting, our unified security operations platform.

Prerequisites:

1) These KQL queries must be executed within: Unified Security Operations Platform This is a non-Microsoft Defender XDR or Microsoft Sentinel Portal environment. For more information about integration, see: Connect Microsoft Sentinel to Microsoft Defender XDR – Microsoft Defender XDR | Microsoft Learn

2) To run these queries: Azure Monitor, CommonSecurityLog Tables (‘Palo Alto Networks’, ‘Fortnite’, ‘Check Point’, ‘Zscaler’) are required. For more information about tables, see Azure Monitor Log Reference – CommonSecurityLog | Microsoft Learn


How Key Entities Work with Third-Party Network Logs in AiTM AttacksHow Key Entities Work with Third-Party Network Logs in AiTM Attacks
Clicking on phishing links in network traffic

  • explanation: This rule is designed to identify successful user clicks on phishing links and subsequent network activity on non-Microsoft network devices.
  • How it works: Microsoft Defender XDR identifies phishing-related alerts and matches them to logs from third-party network devices, such as firewalls, instead of non-Microsoft devices. The goal is to detect successful phishing link clicks and the subsequent suspicious network activity.
// Define a list of alert titles that we are interested in
let Alert_List = dynamic(["Phishing link click observed in Network Traffic",
"Phish delivered due to an IP allow policy",
"A potentially malicious URL click was detected",
"High Risk Sign-in Observed in Network Traffic",
"A user clicked through to a potentially malicious URL",
"Suspicious network connection to AitM phishing site",
"Messages containing malicious entity not removed after delivery",
"Email messages containing malicious URL removed after delivery",
"Email reported by user as malware or phish",
"Phish delivered due to an ETR override",
"Phish not zapped because ZAP is disabled"]);
// Filter AlertInfo for relevant alerts within the past 10 days from Defender for Office 365
AlertInfo
| where TimeGenerated > ago(5d)
| where DetectionSource == "Microsoft Defender for Office 365"
| where Title has_any (Alert_List)
// Join with AlertEvidence to get additional evidence details
| join kind=inner (
AlertEvidence
| where TimeGenerated > ago(5d)
| where DetectionSource == "Microsoft Defender for Office 365"
| where EntityType in ("Url", "User")
) on AlertId
// Parse the JSON field AdditionalFields to extract entities
| extend Entities = parse_json(AdditionalFields)
| mv-apply Entity = Entities on (
where Entity.Type in ('account', 'url')
| extend
// Assign entity properties based on type
EntityUPN = iff(Entities.Type == 'account', strcat(Entities.Name, "@", Entities.UPNSuffix), Entities.UserPrincipalName),
"",
EntityUrl = iff(Entities.Type == 'url', tostring(Entities.Url), "")
)
// Extract the domain from the URL if it's not empty
| extend DomainFromUrl = iff(isnotempty(EntityUrl), tostring(parse_url(EntityUrl).Host), "")
// Summarize to create sets of UPNs and URLs grouped by AlertId and TimeGenerated
| summarize UserPrincipalNames = make_set(EntityUPN), Urls = make_set(EntityUrl) by AlertId, TimeGenerated
// Expand the sets to have individual rows for each UPN and URL
| mv-expand Urls
| mv-expand UserPrincipalNames
// Filter out empty URLs and UPNs
| where isnotempty(Urls)
| where isnotempty(UserPrincipalNames)
// Parse URL into its components
| extend Url = tostring(Urls)
| extend Domain = tostring(parse_url(Url).Host), Path = tostring(parse_url(Url).Path)
// Project relevant columns
| project AlertTime = TimeGenerated, AlertId, UserPrincipalName = UserPrincipalNames, Url, Domain, Path, tostring(parse_url(Url))
// Join with CommonSecurityLog for related network activity
| join kind=inner (
CommonSecurityLog
//| where TimeGenerated > ago(5d)
| where DeviceAction != "Block"
| where DeviceProduct has_any ("FortiGate", "PAN", "VPN", "FireWall", "NSSWeblog", "URL")
| where isnotempty(RequestURL)
| where isnotempty(SourceUserName)
| extend RequestURL = tostring(tolower(RequestURL))
| project
LogTime = TimeGenerated,
DeviceVendor,
DeviceProduct,
Activity,
DestinationHostName,
DestinationIP,
Domain = tostring(parse_url(RequestURL).Host),
RequestPath = tostring(parse_url(RequestURL).Path),
MaliciousIP,
UserName = tostring(split(SourceUserName, "@")[0]),
UPNSuffix = tostring(split(SourceUserName, "@")[1]),
SourceUserName,
IndicatorThreatType,
ThreatSeverity,
AdditionalExtensions,
ThreatConfidence 
) on Domain // Join on Domain for matching records
| where RequestPath has Path

Correlating M365D alerts to non-Microsoft network device activity

  • explanation: This rule correlates Microsoft Defender XDR phishing-related alerts with sign-in activity from non-Microsoft network devices, specifically when users connect to phishing URLs.
  • How it works:Correlate Microsoft 365 Defender alerts with network logs from devices such as Palo Alto Networks, Fortinet, Check Point, and Zscaler. Focus on instances where users connect to phishing URLs on these devices and then make successful login attempts.
// Define a list of alert titles that we are interested in
let Alert_List = dynamic(["Phishing link click observed in Network Traffic",
"Phish delivered due to an IP allow policy",
"A potentially malicious URL click was detected",
"High Risk Sign-in Observed in Network Traffic",
"A user clicked through to a potentially malicious URL",
"Suspicious network connection to AitM phishing site",
"Messages containing malicious entity not removed after delivery",
"Email messages containing malicious URL removed after delivery",
"Email reported by user as malware or phish",
"Phish delivered due to an ETR override",
"Phish not zapped because ZAP is disabled"]);
// Filter AlertInfo for relevant alerts within the past 10 days from Defender for Office 365
AlertInfo
| where TimeGenerated > ago(5d)
| where DetectionSource == "Microsoft Defender for Office 365"
| where Title has_any (Alert_List)
// Join with AlertEvidence to get additional evidence details
| join kind=inner (
AlertEvidence
| where TimeGenerated > ago(5d)
| where DetectionSource == "Microsoft Defender for Office 365"
| where EntityType in ("Url", "User")
) on AlertId
// Parse the JSON field AdditionalFields to extract entities
| extend Entities = parse_json(AdditionalFields)
| mv-apply Entity = Entities on (
where Entity.Type in ('account', 'url')
| extend
// Assign entity properties based on type
EntityUPN = iff(Entities.Type == 'account', strcat(Entities.Name, "@", Entities.UPNSuffix), Entities.UserPrincipalName),
"",
EntityUrl = iff(Entities.Type == 'url', tostring(Entities.Url), "")
)
// Extract the domain from the URL if it's not empty
| extend DomainFromUrl = iff(isnotempty(EntityUrl), tostring(parse_url(EntityUrl).Host), "")
// Summarize to create sets of UPNs and URLs grouped by AlertId and TimeGenerated
| summarize UserPrincipalNames = make_set(EntityUPN), Urls = make_set(EntityUrl) by AlertId, TimeGenerated
// Expand the sets to have individual rows for each UPN and URL
| mv-expand Urls
| mv-expand UserPrincipalNames
// Filter out empty URLs and UPNs
| where isnotempty(Urls)
| where isnotempty(UserPrincipalNames)
// Parse URL into its components
| extend Url = tostring(Urls)
| extend Domain = tostring(parse_url(Url).Host), Path = tostring(parse_url(Url).Path)
| extend AlertTime= TimeGenerated
// matching with 3rd party network logs and 3p Alerts
    | join kind= inner (CommonSecurityLog
    | where TimeGenerated > ago(5d)
        | where DeviceVendor has_any  ("Palo Alto Networks", "Fortinet", "Check Point", "Zscaler")
        | where DeviceProduct startswith "FortiGate" or DeviceProduct startswith  "PAN" or DeviceProduct startswith  "VPN" or DeviceProduct startswith "FireWall" or DeviceProduct startswith  "NSSWeblog" or DeviceProduct startswith "URL"
        | where DeviceAction != "Block"
        | where isnotempty(RequestURL)
        | project
            3plogTime=TimeGenerated,
            DeviceVendor,
            DeviceProduct,
            Activity,
            DestinationHostName,
            DestinationIP,
            RequestURL=tostring(tolower(RequestURL)),
            MaliciousIP,
            SourceUserName=tostring(tolower(SourceUserName)),
            IndicatorThreatType,
            ThreatSeverity,
            ThreatConfidence,
            SourceUserID,
            SourceHostName)
        on $left.Url == $right.RequestURL
    // matching successful Login from suspicious IP
    | join kind=inner (SigninLogs
        //filtering the Successful Login
        | where TimeGenerated > ago(5d)
        | where ResultType == 0
        | project
            IPAddress,
            SourceSystem,
            SigniningTime= TimeGenerated,
            OperationName,
            ResultType,
            ResultDescription,
            AlternateSignInName,
            AppDisplayName,
            AuthenticationRequirement,
            ClientAppUsed,
            RiskState,
            RiskLevelDuringSignIn,
            UserPrincipalName=tostring(tolower(UserPrincipalName)),
            Name = tostring(split(UserPrincipalName, "@")[0]),
            UPNSuffix =tostring(split(UserPrincipalName, "@")[1]))
        on $left.DestinationIP == $right.IPAddress and $left.SourceUserName == $right.UserPrincipalName
    | where SigniningTime between ((AlertTime - 6h) .. (AlertTime + 6h)) and 3plogTime between ((AlertTime - 6h) .. (AlertTime + 6h))





Source link

You may also like

Leave a Comment

Our Company

Welcome to OdysseyX, your one-stop destination for the latest news and opportunities across various domains.

Newsletter

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

Laest News

@2024 – All Right Reserved. Designed and Developed by OdysseyX