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

Anomaly Sign In Event from an IP

Back
Id9c1e9381-79dd-4ddf-9570-b73a1dc59fe0
RulenameAnomaly Sign In Event from an IP
DescriptionIdentifies sign-in anomalies from an IP in the last hour, targeting multiple users where the password is correct after multiple attempts
SeverityMedium
TacticsInitialAccess
TechniquesT1078
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1h
Query period1h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/Anomalies/SignInAnomaly.yaml
Version1.0.1
Arm template9c1e9381-79dd-4ddf-9570-b73a1dc59fe0.json
Deploy To Azure
let LookBack = 1h;
let Data = (
SigninLogs
| where TimeGenerated >= ago(LookBack)
| where parse_json(NetworkLocationDetails)[0].networkType != "trustedNamedLocation" // Excludes known tagged networks
// Counts the number of sign in events in the last hour every 15 minutes by IP
| make-series EventCounts = count() on TimeGenerated from ago(LookBack) to now() step 15m by IPAddress 
);
let AnomalyAlert = (
Data
| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(EventCounts,1.5,-1,'linefit')
| mv-expand EventCounts,TimeGenerated,Anomalies to typeof(double),Baseline to typeof(long),Score to typeof(double)
| where Anomalies > 0
);
AnomalyAlert
| join kind = inner (SigninLogs
| where TimeGenerated between (ago(LookBack) .. now())
| where parse_json(NetworkLocationDetails)[0].networkType != "trustedNamedLocation"
| extend PasswordResult = tostring(parse_json(AuthenticationDetails).authenticationStepResultDetail)
| summarize UserCount = dcount(UserPrincipalName), UserList = make_set(UserPrincipalName), AppName = make_set(AppDisplayName), PasswordResult = make_list(PasswordResult) by IPAddress) on IPAddress
| where PasswordResult has "Correct Password"
| where UserCount > 1 // looks for events targeting more than one user.
queryFrequency: 1h
description: |
    'Identifies sign-in anomalies from an IP in the last hour, targeting multiple users where the password is correct after multiple attempts'
customDetails:
  PasswordResult: PasswordResult
  Baseline: Baseline
  UserList: UserList
  AppName: AppName
  Score: Score
  UserCount: UserCount
severity: Medium
version: 1.0.1
relevantTechniques:
- T1078
name: Anomaly Sign In Event from an IP
triggerThreshold: 0
kind: Scheduled
query: |
  let LookBack = 1h;
  let Data = (
  SigninLogs
  | where TimeGenerated >= ago(LookBack)
  | where parse_json(NetworkLocationDetails)[0].networkType != "trustedNamedLocation" // Excludes known tagged networks
  // Counts the number of sign in events in the last hour every 15 minutes by IP
  | make-series EventCounts = count() on TimeGenerated from ago(LookBack) to now() step 15m by IPAddress 
  );
  let AnomalyAlert = (
  Data
  | extend (Anomalies, Score, Baseline) = series_decompose_anomalies(EventCounts,1.5,-1,'linefit')
  | mv-expand EventCounts,TimeGenerated,Anomalies to typeof(double),Baseline to typeof(long),Score to typeof(double)
  | where Anomalies > 0
  );
  AnomalyAlert
  | join kind = inner (SigninLogs
  | where TimeGenerated between (ago(LookBack) .. now())
  | where parse_json(NetworkLocationDetails)[0].networkType != "trustedNamedLocation"
  | extend PasswordResult = tostring(parse_json(AuthenticationDetails).authenticationStepResultDetail)
  | summarize UserCount = dcount(UserPrincipalName), UserList = make_set(UserPrincipalName), AppName = make_set(AppDisplayName), PasswordResult = make_list(PasswordResult) by IPAddress) on IPAddress
  | where PasswordResult has "Correct Password"
  | where UserCount > 1 // looks for events targeting more than one user.  
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/Anomalies/SignInAnomaly.yaml
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - SigninLogs
metadata:
  source:
    kind: Community
  author:
    name: Juanse
  support:
    tier: Community
  categories:
    domains:
    - Identity
tactics:
- InitialAccess
id: 9c1e9381-79dd-4ddf-9570-b73a1dc59fe0
queryPeriod: 1h
entityMappings:
- fieldMappings:
  - columnName: IPAddress
    identifier: Address
  entityType: IP
{
  "$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/9c1e9381-79dd-4ddf-9570-b73a1dc59fe0')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/9c1e9381-79dd-4ddf-9570-b73a1dc59fe0')]",
      "properties": {
        "alertRuleTemplateName": "9c1e9381-79dd-4ddf-9570-b73a1dc59fe0",
        "customDetails": {
          "AppName": "AppName",
          "Baseline": "Baseline",
          "PasswordResult": "PasswordResult",
          "Score": "Score",
          "UserCount": "UserCount",
          "UserList": "UserList"
        },
        "description": "'Identifies sign-in anomalies from an IP in the last hour, targeting multiple users where the password is correct after multiple attempts'\n",
        "displayName": "Anomaly Sign In Event from an IP",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "IPAddress",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/Anomalies/SignInAnomaly.yaml",
        "query": "let LookBack = 1h;\nlet Data = (\nSigninLogs\n| where TimeGenerated >= ago(LookBack)\n| where parse_json(NetworkLocationDetails)[0].networkType != \"trustedNamedLocation\" // Excludes known tagged networks\n// Counts the number of sign in events in the last hour every 15 minutes by IP\n| make-series EventCounts = count() on TimeGenerated from ago(LookBack) to now() step 15m by IPAddress \n);\nlet AnomalyAlert = (\nData\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(EventCounts,1.5,-1,'linefit')\n| mv-expand EventCounts,TimeGenerated,Anomalies to typeof(double),Baseline to typeof(long),Score to typeof(double)\n| where Anomalies > 0\n);\nAnomalyAlert\n| join kind = inner (SigninLogs\n| where TimeGenerated between (ago(LookBack) .. now())\n| where parse_json(NetworkLocationDetails)[0].networkType != \"trustedNamedLocation\"\n| extend PasswordResult = tostring(parse_json(AuthenticationDetails).authenticationStepResultDetail)\n| summarize UserCount = dcount(UserPrincipalName), UserList = make_set(UserPrincipalName), AppName = make_set(AppDisplayName), PasswordResult = make_list(PasswordResult) by IPAddress) on IPAddress\n| where PasswordResult has \"Correct Password\"\n| where UserCount > 1 // looks for events targeting more than one user.\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "PT1H",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1078"
        ],
        "templateVersion": "1.0.1",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}