Detection rules › Kusto
Service Principal Authentication Attempt from New Country
Detects when there is a Service Principal login attempt from a country that has not seen a successful login in the previous 14 days. Threat actors may attempt to authenticate with credentials from compromised accounts - monitoring attempts from anomalous locations may help identify these attempts. Authentication attempts should be investigated to ensure the activity was legitimate and if there is other similar activity. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Azure | any: Sign-in record (AADServicePrincipalSignInLogs, any result) |
Rule body
id: 1baaaf00-655f-4de9-8ff8-312e902cda71
name: Service Principal Authentication Attempt from New Country
description: |
'Detects when there is a Service Principal login attempt from a country that has not seen a successful login in the previous 14 days.
Threat actors may attempt to authenticate with credentials from compromised accounts - monitoring attempts from anomalous locations may help identify these attempts.
Authentication attempts should be investigated to ensure the activity was legitimate and if there is other similar activity.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AADServicePrincipalSignInLogs
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078.004
tags:
- AADSecOpsGuide
query: |
let known_locations = (
AADServicePrincipalSignInLogs
| where TimeGenerated between(ago(14d)..ago(1d))
| where ResultType == 0
| summarize by Location);
AADServicePrincipalSignInLogs
| where TimeGenerated > ago(1d)
| where ResultType != 50126
| where Location !in (known_locations)
| extend City = tostring(parse_json(LocationDetails).city)
| extend State = tostring(parse_json(LocationDetails).state)
| extend Place = strcat(City, " - ", State)
| extend Result = strcat(tostring(ResultType), " - ", ResultDescription)
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), make_set(Result), make_set(IPAddress), make_set(Place) by ServicePrincipalName, Location
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: ServicePrincipalName
version: 1.0.1
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Pete Bryan
support:
tier: Community
categories:
domains: [ "Security - Others", "Identity" ]
Stages and Predicates
Let binding: known_locations
let known_locations = (
AADServicePrincipalSignInLogs
| where TimeGenerated between(ago(14d)..ago(1d))
| where ResultType == 0
| summarize by Location);
Stage 1: source
AADServicePrincipalSignInLogs
Stage 2: where
| where TimeGenerated > ago(1d)
Stage 3: where
| where ResultType != 50126
Stage 4: where
| where Location !in (known_locations)
Stage 5: extend (4 consecutive steps)
| extend City = tostring(parse_json(LocationDetails).city)
| extend State = tostring(parse_json(LocationDetails).state)
| extend Place = strcat(City, " - ", State)
| extend Result = strcat(tostring(ResultType), " - ", ResultDescription)
Stage 6: summarize
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), make_set(Result), make_set(IPAddress), make_set(Place) by ServicePrincipalName, Location
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Location | eq | known_locations | excludes:Location field:"Location" value:"known_locations" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ResultType | ne |
| field:"ResultType" kind:ne value:"50126" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
FirstSeen | summarize |
LastSeen | summarize |
Location | summarize |
ServicePrincipalName | summarize |