Detection rules › Kusto
PRODAFT USTA - Compromised credential used in successful sign-in
Correlates corporate credentials exposed in PRODAFT USTA Account Takeover Prevention tickets with successful Microsoft Entra ID sign-ins for the same user. A successful sign-in by an account whose credentials are known to be compromised is a strong signal of account takeover. Requires the Microsoft Entra ID (SigninLogs) connector. Username matching is best-effort (case-insensitive) because USTA may record either an email or a bare username.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Credential Access |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Entra ID | SigninLogs sign-in event: Successful sign-in |
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
id: 5da571b5-54f6-42c2-8c3e-27edd987ceec
name: PRODAFT USTA - Compromised credential used in successful sign-in
description: |
'Correlates corporate credentials exposed in PRODAFT USTA Account Takeover Prevention
tickets with successful Microsoft Entra ID sign-ins for the same user. A successful
sign-in by an account whose credentials are known to be compromised is a strong signal
of account takeover. Requires the Microsoft Entra ID (SigninLogs) connector. Username
matching is best-effort (case-insensitive) because USTA may record either an email or a
bare username.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: PRODAFTUstaATPCCPDefinition
dataTypes:
- PRODAFTUstaCompromisedCredentials_CL
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- InitialAccess
relevantTechniques:
- T1078
- T1555
query: |
let lookback = 14d;
let detection = 1h;
let compromised =
PRODAFTUstaCompromisedCredentials
| where Created > ago(lookback)
| where IsCorporate == true
| where isnotempty(Username)
| extend MatchName = tolower(Username)
| summarize arg_max(TimeGenerated, TicketId, CompanyName, InfectionDate, Source) by MatchName;
SigninLogs
| where TimeGenerated > ago(detection)
| where ResultType == 0
| where isnotempty(UserPrincipalName)
| extend MatchName = tolower(UserPrincipalName)
| join kind=inner compromised on MatchName
| project
TimeGenerated,
UserPrincipalName,
IPAddress,
Location,
AppDisplayName,
ClientAppUsed,
TicketId,
CompanyName,
Source,
InfectionDate
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
Ticket: TicketId
Company: CompanyName
Source: Source
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1d
matchingMethod: Selected
groupByEntities:
- Account
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 14d;
let detection = 1h;
Let binding: compromised
let compromised = PRODAFTUstaCompromisedCredentials
| where Created > ago(lookback)
| where IsCorporate == true
| where isnotempty(Username)
| extend MatchName = tolower(Username)
| summarize arg_max(TimeGenerated, TicketId, CompanyName, InfectionDate, Source) by MatchName;
Stage 1: source
SigninLogs
Stage 2: where
| where TimeGenerated > ago(detection)
Stage 3: where
| where ResultType == 0
Stage 4: where
| where isnotempty(UserPrincipalName)
Stage 5: extend
| extend MatchName = tolower(UserPrincipalName)
Stage 6: join
| join kind=inner compromised on MatchName
Stage 7: project
| project
TimeGenerated,
UserPrincipalName,
IPAddress,
Location,
AppDisplayName,
ClientAppUsed,
TicketId,
CompanyName,
Source,
InfectionDate
Stage 8: summarize aggregation inside the join branch
summarize by MatchName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
IsCorporate | eq |
| field:"IsCorporate" kind:eq value:"true" |
ResultType | eq |
| field:"ResultType" kind:eq value:"0" |
UserPrincipalName | is_not_null | field:"TargetUserName" kind:is_not_null | |
Username | is_not_null | field:"user" kind:is_not_null |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
MatchName | summarize |