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

New country signIn with correct password

Back
Id7808c05a-3afd-4d13-998a-a59e2297693f
RulenameNew country signIn with correct password
DescriptionIdentifies an interrupted sign-in session from a country the user has not sign-in before in the last 7 days, where the password was correct. Although the session is interrupted by other controls such as multi factor authentication or conditional access policies, the user credentials should be reset due to logs indicating a correct password was observed during sign-in.
SeverityMedium
TacticsInitialAccess
CredentialAccess
TechniquesT1078
T1110
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1d
Query period7d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/SigninLogs/NewCountryValidCreds.yaml
Version1.0.2
Arm template7808c05a-3afd-4d13-998a-a59e2297693f.json
Deploy To Azure
// Creating a list of successful sign-in by users in the last 7 days.
let KnownUserCountry = (
SigninLogs
| where TimeGenerated between (ago(7d) .. ago(1d) ) 
| where ResultType == 0
| summarize KnownCountry = make_set(Location,1048576) by UserPrincipalName
);
// Identify sign-ins that are no successful but have the auth details indicating a correct password.
SigninLogs
| where TimeGenerated >= ago(1d)
| where ResultType != 0
| extend ParseAuth = parse_json(AuthenticationDetails)
| extend AuthMethod = tostring(ParseAuth.[0].authenticationMethod),
    PasswordResult = tostring(ParseAuth.[0].authenticationStepResultDetail),
    AuthSucceeded = tostring(ParseAuth.[0].succeeded)
| where PasswordResult == "Correct Password" or AuthSucceeded == "true"
| where AuthMethod == "Password"
| extend failureReason = tostring(Status.failureReason)
| summarize NewCountry = make_set(Location,1048576), LastObservedTime = max(TimeGenerated), AppName = make_set(AppDisplayName,1048576) by UserPrincipalName, PasswordResult, AuthSucceeded, failureReason
// Combining both tables by user
| join kind=inner KnownUserCountry on UserPrincipalName
// Compare both arrays and identify if the country has been observed in the past.
| extend CountryDiff = set_difference(NewCountry,KnownCountry)
| extend CountryDiffCount = array_length(CountryDiff)
// Count the new column to only alert if there is a difference between both arrays
| where CountryDiffCount != 0
| extend NewCountryEvent = CountryDiff
// Getting UserName and Domain
| extend Name = split(UserPrincipalName,"@",0),
    Domain = split(UserPrincipalName,"@",1)
| mv-expand Name,Domain
relevantTechniques:
- T1078
- T1110
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/SigninLogs/NewCountryValidCreds.yaml
eventGroupingSettings:
  aggregationKind: SingleAlert
triggerOperator: gt
requiredDataConnectors:
- dataTypes:
  - SigninLogs
  connectorId: AzureActiveDirectory
severity: Medium
entityMappings:
- fieldMappings:
  - identifier: FullName
    columnName: UserPrincipalName
  - identifier: Name
    columnName: Name
  - identifier: NTDomain
    columnName: Domain
  entityType: Account
version: 1.0.2
tactics:
- InitialAccess
- CredentialAccess
triggerThreshold: 0
metadata:
  categories:
    domains:
    - Identity
    - Security - Threat Protection
  support:
    tier: Community
  source:
    kind: Community
  author:
    name: Juanse
queryPeriod: 7d
queryFrequency: 1d
id: 7808c05a-3afd-4d13-998a-a59e2297693f
name: New country signIn with correct password
kind: Scheduled
description: |
    'Identifies an interrupted sign-in session from a country the user has not sign-in before in the last 7 days, where the password was correct. Although the session is interrupted by other controls such as multi factor authentication or conditional access policies, the user credentials should be reset due to logs indicating a correct password was observed during sign-in.'
query: |
  // Creating a list of successful sign-in by users in the last 7 days.
  let KnownUserCountry = (
  SigninLogs
  | where TimeGenerated between (ago(7d) .. ago(1d) ) 
  | where ResultType == 0
  | summarize KnownCountry = make_set(Location,1048576) by UserPrincipalName
  );
  // Identify sign-ins that are no successful but have the auth details indicating a correct password.
  SigninLogs
  | where TimeGenerated >= ago(1d)
  | where ResultType != 0
  | extend ParseAuth = parse_json(AuthenticationDetails)
  | extend AuthMethod = tostring(ParseAuth.[0].authenticationMethod),
      PasswordResult = tostring(ParseAuth.[0].authenticationStepResultDetail),
      AuthSucceeded = tostring(ParseAuth.[0].succeeded)
  | where PasswordResult == "Correct Password" or AuthSucceeded == "true"
  | where AuthMethod == "Password"
  | extend failureReason = tostring(Status.failureReason)
  | summarize NewCountry = make_set(Location,1048576), LastObservedTime = max(TimeGenerated), AppName = make_set(AppDisplayName,1048576) by UserPrincipalName, PasswordResult, AuthSucceeded, failureReason
  // Combining both tables by user
  | join kind=inner KnownUserCountry on UserPrincipalName
  // Compare both arrays and identify if the country has been observed in the past.
  | extend CountryDiff = set_difference(NewCountry,KnownCountry)
  | extend CountryDiffCount = array_length(CountryDiff)
  // Count the new column to only alert if there is a difference between both arrays
  | where CountryDiffCount != 0
  | extend NewCountryEvent = CountryDiff
  // Getting UserName and Domain
  | extend Name = split(UserPrincipalName,"@",0),
      Domain = split(UserPrincipalName,"@",1)
  | mv-expand Name,Domain  
customDetails:
  AuthSucceeded: AuthSucceeded
  failureReason: failureReason
  AppName: AppName
  PasswordResult: PasswordResult
  LastObservedTime: LastObservedTime
  NewCountryEvent: NewCountryEvent
{
  "$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/7808c05a-3afd-4d13-998a-a59e2297693f')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/7808c05a-3afd-4d13-998a-a59e2297693f')]",
      "properties": {
        "alertRuleTemplateName": "7808c05a-3afd-4d13-998a-a59e2297693f",
        "customDetails": {
          "AppName": "AppName",
          "AuthSucceeded": "AuthSucceeded",
          "failureReason": "failureReason",
          "LastObservedTime": "LastObservedTime",
          "NewCountryEvent": "NewCountryEvent",
          "PasswordResult": "PasswordResult"
        },
        "description": "'Identifies an interrupted sign-in session from a country the user has not sign-in before in the last 7 days, where the password was correct. Although the session is interrupted by other controls such as multi factor authentication or conditional access policies, the user credentials should be reset due to logs indicating a correct password was observed during sign-in.'\n",
        "displayName": "New country signIn with correct password",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UserPrincipalName",
                "identifier": "FullName"
              },
              {
                "columnName": "Name",
                "identifier": "Name"
              },
              {
                "columnName": "Domain",
                "identifier": "NTDomain"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "SingleAlert"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/SigninLogs/NewCountryValidCreds.yaml",
        "query": "// Creating a list of successful sign-in by users in the last 7 days.\nlet KnownUserCountry = (\nSigninLogs\n| where TimeGenerated between (ago(7d) .. ago(1d) ) \n| where ResultType == 0\n| summarize KnownCountry = make_set(Location,1048576) by UserPrincipalName\n);\n// Identify sign-ins that are no successful but have the auth details indicating a correct password.\nSigninLogs\n| where TimeGenerated >= ago(1d)\n| where ResultType != 0\n| extend ParseAuth = parse_json(AuthenticationDetails)\n| extend AuthMethod = tostring(ParseAuth.[0].authenticationMethod),\n    PasswordResult = tostring(ParseAuth.[0].authenticationStepResultDetail),\n    AuthSucceeded = tostring(ParseAuth.[0].succeeded)\n| where PasswordResult == \"Correct Password\" or AuthSucceeded == \"true\"\n| where AuthMethod == \"Password\"\n| extend failureReason = tostring(Status.failureReason)\n| summarize NewCountry = make_set(Location,1048576), LastObservedTime = max(TimeGenerated), AppName = make_set(AppDisplayName,1048576) by UserPrincipalName, PasswordResult, AuthSucceeded, failureReason\n// Combining both tables by user\n| join kind=inner KnownUserCountry on UserPrincipalName\n// Compare both arrays and identify if the country has been observed in the past.\n| extend CountryDiff = set_difference(NewCountry,KnownCountry)\n| extend CountryDiffCount = array_length(CountryDiff)\n// Count the new column to only alert if there is a difference between both arrays\n| where CountryDiffCount != 0\n| extend NewCountryEvent = CountryDiff\n// Getting UserName and Domain\n| extend Name = split(UserPrincipalName,\"@\",0),\n    Domain = split(UserPrincipalName,\"@\",1)\n| mv-expand Name,Domain\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P7D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess",
          "InitialAccess"
        ],
        "techniques": [
          "T1078",
          "T1110"
        ],
        "templateVersion": "1.0.2",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}