Detection rules › Kusto
Detect non-admin requesting token for admin applications
This rule detects sign-in attempts from non-admin users to admin applications in Entra ID.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution |
References
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- [Entra ID] Suspicious Continuous OAuth Token Usage (Kusto)
- Anomalous sign-in location by user account and authenticating application (Kusto)
- Anomalous Single Factor Signin (Kusto)
- Authentications of Privileged Accounts Outside of Expected Controls (Kusto)
- Azure Portal sign in from another Azure Tenant (Kusto)
- Azure Service Principal Sign-In Followed by Arc Cluster Credential Access (Elastic)
- Azure SignIn via Legacy Authentication Protocol (Panther)
- Cisco - firewall block but success logon to Microsoft Entra ID (Kusto)
Rule body
let ITAccounts=(_GetWatchlist('ITAccounts') | summarize make_set(ITAccounts));
// Materialize Dataset
let DataSetMat= materialize (SigninLogs
| where TimeGenerated > ago(1h)
| where AppDisplayName has_any ("PowerShell", "CLI", "Command Line", "Management Shell")
// Get successful and failed due to no assignment logins
| where ResultType in ("0", "50105")
| summarize max(TimeGenerated) by UserPrincipalName, AppDisplayName, IPAddress, UserId, ResultType
// join IdentityInfo to get more information
| join kind=leftouter (IdentityInfo | where TimeGenerated > ago(14d) | summarize arg_max(TimeGenerated, *) by AccountObjectId ) on $left.UserId == $right.AccountObjectId
// exclude Accounts with Assigned Roles
| where array_length(AssignedRoles) == 0
// exclude known IT personnel Departments
| where Department !has "it" and Department !has "ict" and Department !has "operations"
// exclude service accounts
| where JobTitle != "Service Account");
// exclude IT accounts
let FIL= (DataSetMat
| extend ITAccounts= toscalar(ITAccounts)
| mv-expand ITAccounts
| where AccountUPN contains ITAccounts or AccountDisplayName contains ITAccounts);
DataSetMat
// exclude service accounts
| join kind=leftanti FIL on AccountUPN
| distinct max_TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, JobTitle, Department, UserId, ResultType
Stages and Predicates
let DataSetMat is inlined into the numbered stages below.
Let binding: ITAccounts
let ITAccounts = (_GetWatchlist('ITAccounts') | summarize make_set(ITAccounts));
Let binding: FIL
let FIL = (DataSetMat
| extend ITAccounts= toscalar(ITAccounts)
| mv-expand ITAccounts
| where AccountUPN contains ITAccounts or AccountDisplayName contains ITAccounts);
Stage 1: source
let DataSetMat
Stage 2: source
SigninLogs
Stage 3: where
where TimeGenerated > ago(3600s)
Stage 4: where
where (AppDisplayName contains "PowerShell" or AppDisplayName contains "CLI" or AppDisplayName contains "Command Line" or AppDisplayName contains "Management Shell")
Stage 5: where
where ResultType in~ (0, 50105)
Stage 6: summarize
summarize by UserPrincipalName, AppDisplayName, IPAddress, UserId, ResultType
Stage 7: join
join kind=leftouter (IdentityInfo) on UserId, AccountObjectId
Stage 8: where
where AssignedRoles == 0
Stage 9: where
where not (Department contains "ict") and not (Department contains "it") and not (Department contains "operations")
Stage 10: where
where JobTitle !~ "Service Account"
Stage 11: join (negated)
join kind=leftanti (FIL) on AccountUPN
Stage 12: distinct
distinct AppDisplayName, Department, IPAddress, JobTitle, ResultType, UserId, UserPrincipalName, max_TimeGenerated
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Department | match | ict | excludes:Department field:"Department" value:"ict" |
Department | match | it | excludes:Department field:"Department" value:"it" |
Department | match | operations | excludes:Department field:"Department" value:"operations" |
AccountDisplayName | cross_field_compare | ITAccounts | excludes:AccountDisplayName field:"AccountDisplayName" value:"ITAccounts" |
AccountUPN | cross_field_compare | ITAccounts | excludes:AccountUPN field:"AccountUPN" value:"ITAccounts" |
AppDisplayName | match | PowerShell, CLI, Command Line, Management Shell | excludes:AppDisplayName |
AssignedRoles | eq | 0 | excludes:AssignedRoles field:"AssignedRoles" value:"0" |
JobTitle | ne | Service Account | excludes:JobTitle field:"JobTitle" value:"Service Account" |
ResultType | in | 0, 50105 | excludes:ResultType field:"ResultType" value:"0" field:"ResultType" value:"50105" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AppDisplayName | match |
| field:"Application" kind:match |
Department | match |
| field:"Department" kind:match |
JobTitle | ne |
| field:"JobTitle" kind:ne value:"Service Account" |
ResultType | in |
| field:"ResultType" kind:in |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AppDisplayName | summarize |
IPAddress | summarize |
ResultType | summarize |
UserId | summarize |
UserPrincipalName | summarize |