Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

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

Back
Idba144bf8-75b8-406f-9420-ed74397f9479
RulenameIP with multiple failed Microsoft Entra ID logins successfully logs in to Palo Alto VPN
DescriptionThis 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.
SeverityMedium
TacticsInitialAccess
CredentialAccess
TechniquesT1078
T1110
Required data connectorsAzureActiveDirectory
PaloAltoNetworks
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/AAD_PAVPN_Correlation.yaml
Version1.0.4
Arm templateba144bf8-75b8-406f-9420-ed74397f9479.json
Deploy To Azure
//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: DeviceName
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SourceIP
queryFrequency: 1d
name: IP with multiple failed Microsoft Entra ID logins successfully logs in to Palo Alto VPN
severity: Medium
kind: Scheduled
tactics:
- InitialAccess
- CredentialAccess
metadata:
  author:
    name: Microsoft Security Research
  source:
    kind: Community
  categories:
    domains:
    - Security - Others
    - Identity
  support:
    tier: Community
triggerThreshold: 0
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  
triggerOperator: gt
queryPeriod: 1d
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/AAD_PAVPN_Correlation.yaml
relevantTechniques:
- T1078
- T1110
id: ba144bf8-75b8-406f-9420-ed74397f9479
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - SigninLogs
- connectorId: AzureActiveDirectory
  dataTypes:
  - AADNonInteractiveUserSignInLogs
- connectorId: PaloAltoNetworks
  dataTypes:
  - CommonSecurityLog
version: 1.0.4
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.  
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/ba144bf8-75b8-406f-9420-ed74397f9479')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/ba144bf8-75b8-406f-9420-ed74397f9479')]",
      "properties": {
        "alertRuleTemplateName": "ba144bf8-75b8-406f-9420-ed74397f9479",
        "customDetails": null,
        "description": "This query creates a list of IP addresses with the number of failed login attempts to Entra ID \nabove 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.\n",
        "displayName": "IP with multiple failed Microsoft Entra ID logins successfully logs in to Palo Alto VPN",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "User",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "DeviceName",
                "identifier": "HostName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIP",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/AAD_PAVPN_Correlation.yaml",
        "query": "//Set a threshold of failed AAD signins from an IP address within 1 day above which we want to deem those logins suspicious.\nlet signin_threshold = 5; \n//Make a list of IPs with AAD signin failures above our threshold.\nlet aadFunc = (tableName:string){\nlet suspicious_signins = \n    table(tableName)\n    //Looking for logon failure results\n    | where ResultType !in (\"0\", \"50125\", \"50140\")\n    //Exclude localhost addresses to reduce the chance of FPs\n    | where IPAddress !in (\"127.0.0.1\", \"::1\")\n    | summarize count() by IPAddress\n    | where count_ >  signin_threshold\n    | summarize make_set(IPAddress);\n    suspicious_signins\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nlet suspicious_signins = \nunion isfuzzy=true aadSignin, aadNonInt\n| summarize make_set(set_IPAddress);\n//See if any of those IPs have sucessfully logged into PA VPNs during the same timeperiod\nCommonSecurityLog\n    //Select only PA VPN sucessful logons\n    | where DeviceVendor == \"Palo Alto Networks\" and DeviceEventClassID == \"globalprotect\"\n    | where Message has \"GlobalProtect gateway user authentication succeeded\"\n    //Parse out the logon source IP from the Message field to match on\n    | extend SourceIP = extract(\"Login from: ([^,]+)\", 1, Message) \n    | where SourceIP in (suspicious_signins)\n    | extend Reason = \"Multiple failed AAD logins from SourceIP\"\n    //Parse out other useful information from Message field\n    | extend User = extract('User name: ([^,]+)', 1, Message) \n    | extend ClientOS = extract('Client OS version: ([^,\\\"]+)', 1, Message)\n    | extend Location = extract('Source region: ([^,]{2})',1, Message)\n    | project TimeGenerated, Reason, SourceIP, User, ClientOS, Location, Message, DeviceName, ReceiptTime, DeviceVendor, DeviceEventClassID, Computer, FileName\n    | extend timestamp = TimeGenerated\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess",
          "InitialAccess"
        ],
        "techniques": [
          "T1078",
          "T1110"
        ],
        "templateVersion": "1.0.4",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}