← Back to SOC feed Coverage →

IP with multiple failed Microsoft Entra ID logins successfully logs in to Palo Alto VPN

kql MEDIUM Azure-Sentinel
T1078T1110
AADNonInteractiveUserSignInLogsCommonSecurityLogSigninLogs
microsoftofficial
This rule was pulled from an open-source repository and enriched with AI. Validate in a test environment before deploying to production.
View original rule at Azure-Sentinel →
Retrieved: 2026-03-25T03:06:09Z · Confidence: medium

Hunt Hypothesis

IP addresses with multiple failed Microsoft Entra ID logins may indicate credential stuffing attempts, and a subsequent successful login to Palo Alto VPN suggests the adversary has compromised credentials, making proactive hunting critical to identify and mitigate potential lateral movement in Azure Sentinel. SOC teams should hunt for this behavior to detect and respond to credential-based attacks before they lead to broader network compromise.

KQL Query

//Set a threshold of failed AAD signins from an IP address within 1 day above which we want to deem those logins suspicious.
let signin_threshold = 5; 
//Make a list of IPs with AAD signin failures above our threshold.
let aadFunc = (tableName:string){
let suspicious_signins = 
    table(tableName)
    //Looking for logon failure results
    | where ResultType !in ("0", "50125", "50140")
    //Exclude localhost addresses to reduce the chance of FPs
    | where IPAddress !in ("127.0.0.1", "::1")
    | summarize count() by IPAddress
    | where count_ >  signin_threshold
    | summarize make_set(IPAddress);
    suspicious_signins
};
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
let suspicious_signins = 
union isfuzzy=true aadSignin, aadNonInt
| summarize make_set(set_IPAddress);
//See if any of those IPs have sucessfully logged into PA VPNs during the same timeperiod
CommonSecurityLog
    //Select only PA VPN sucessful logons
    | where DeviceVendor == "Palo Alto Networks" and DeviceEventClassID == "globalprotect"
    | where Message has "GlobalProtect gateway user authentication succeeded"
    //Parse out the logon source IP from the Message field to match on
    | extend SourceIP = extract("Login from: ([^,]+)", 1, Message) 
    | where SourceIP in (suspicious_signins)
    | extend Reason = "Multiple failed AAD logins from SourceIP"
    //Parse out other useful information from Message field
    | extend User = extract('User name: ([^,]+)', 1, Message) 
    | extend ClientOS = extract('Client OS version: ([^,\"]+)', 1, Message)
    | extend Location = extract('Source region: ([^,]{2})',1, Message)
    | project TimeGenerated, Reason, SourceIP, User, ClientOS, Location, Message, DeviceName, ReceiptTime, DeviceVendor, DeviceEventClassID, Computer, FileName
    | extend timestamp = TimeGenerated

Analytic Rule Definition

id: ba144bf8-75b8-406f-9420-ed74397f9479
name: IP with multiple failed Microsoft Entra ID logins successfully logs in to Palo Alto VPN
description: |
    This query creates a list of IP addresses with the number of failed login attempts to Entra ID 
    above a set threshold ( default of 5 ).  It then looks for any successful Palo Alto VPN logins from any of these IPs within the same timeframe.
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
     - SigninLogs
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AADNonInteractiveUserSignInLogs
  - connectorId: PaloAltoNetworks
    dataTypes:
     - CommonSecurityLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - CredentialAccess
relevantTechniques:
  - T1078
  - T1110
query: |
  //Set a threshold of failed AAD signins from an IP address within 1 day above which we want to deem those logins suspicious.
  let signin_threshold = 5; 
  //Make a list of IPs with AAD signin failures above our threshold.
  let aadFunc = (tableName:string){
  let suspicious_signins = 
      table(tableName)
      //Looking for logon failure results
      | where ResultType !in ("0", "50125", "50140")
      //Exclude localhost addresses to reduce the chance of FPs
      | where IPAddress !in ("127.0.0.1", "::1")
      | summarize count() by IPAddress
      | where count_ >  signin_threshold
      | summarize make_set(IPAddress);
      suspicious_signins
  };
  let aadSignin = aadFunc("SigninLogs");
  let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
  let suspicious_signins = 
  union isfuzzy=true aadSignin, aadNonInt
  | summarize make_set(set_IPAddress);
  //See if any of those IPs have sucessfully logged into PA VPNs during the same timeperiod
  CommonSecurityLog
      //Select only PA VPN sucessful logons
      | where DeviceVendor == "Palo Alto Networks" and DeviceEventClassID == "globalprotect"
      | where Message has "GlobalProtect gateway user authentication succeeded"
      //Parse out the logon source IP from the Message field to match on
      | extend SourceIP = extract("Login from: ([^,]+)", 1, Message) 
      | where SourceIP in (suspicious_signins)
      | extend Reason = "Multiple failed AAD logins from SourceIP"
      //Parse out other useful information from Message field
      | extend User = extract('User name: ([^,]+)', 1, Message) 
      | extend ClientOS = extract('Client OS version: ([^,\"]+)', 1, Message)
      | extend Location = extract('Source region: ([^,]{2})',1, Message)
      | project TimeGenerated, Reason, SourceIP, User, ClientOS, Location, Message, DeviceName, ReceiptTime, DeviceVendor, DeviceEventClassID, Computer, FileName
      | extend timestamp = TimeGenerated
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: User
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Devic

Required Data Sources

Sentinel TableNotes
AADNonInteractiveUserSignInLogsEnsure this data connector is enabled
CommonSecurityLogEnsure this data connector is enabled
SigninLogsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Detections/MultipleDataSources/AAD_PAVPN_Correlation.yaml