Detection rules › Kusto
User impersonation by Identity Protection alerts
'This detection focuses on identifying user-related events involving IAM roles, groups, user access, and password changes. It examines instances where the user's IP address matches and alerts generated by Identity Protection share the same IP address. The analysis occurs within a time window of 1 hour, helping to flag potential cases of user impersonation.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | T1134 Access Token Manipulation |
Rules detecting the same action
Other rules on this platform that filter on the same API call or operation.
- ASL AWS Create Access Key (Splunk)
- ASL AWS IAM Failure Group Deletion (Splunk)
- ASL AWS IAM Successful Group Deletion (Splunk)
- ASL AWS New MFA Method Registered For User (Splunk)
- AWS CreateAccessKey (Splunk)
- AWS Lateral Movement from Kubernetes SA via AssumeRoleWithWebIdentity (Elastic)
- AWS New MFA Method Registered For User (Splunk)
- AWSCloudTrail - Creation of Access Key for IAM User (Kusto)
Rule body kusto
id: 11c3d541-5fa5-49df-8218-d1c98584473b
name: User impersonation by Identity Protection alerts
description: |
'This detection focuses on identifying user-related events involving IAM roles, groups, user access, and password changes. It examines instances where the user's IP address matches and alerts generated by Identity Protection share the same IP address. The analysis occurs within a time window of 1 hour, helping to flag potential cases of user impersonation.'
severity: Medium
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
- connectorId: AzureActiveDirectoryIdentityProtection
dataTypes:
- SecurityAlert (IPC)
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1134
query: |
// Retrieve SecurityAlerts generated within the last day
SecurityAlert
// Filter alerts for Azure Active Directory Identity Protection and High severity
| where ProductName has "Azure Active Directory Identity Protection"
| where AlertSeverity == "High"
// Extract IP address entities from the 'Entities' field
| extend ipAddress = extract(@'\b(?:\d{1,3}\.){3}\d{1,3}\b', 0, Entities)
// Filter out alerts without IP address entities
| where isnotempty(ipAddress)
// Summarize entities per unique combination of attributes
| summarize make_set(Entities)
by
AlertTime = TimeGenerated,
ipAddress,
AlertName,
ProductName,
AlertSeverity
// Perform an inner join with AWS CloudTrail events
| join kind=inner (
AWSCloudTrail
| where isempty(ErrorMessage)
| extend UserType = tostring(parse_json(RequestParameters).userType)
| where EventName in~ ("CreateRole", "DeleteRole", "CreateUser", "CreateAccessKey", "DeleteAccessKey", "CreateGroup", "AddUserToGroup", "ChangePassword", "DeleteGroup", "DeleteUser", "RemoveUserFromGroup", "CreateVirtualMFADevice", "DeleteLoginProfile")
| summarize
make_set(RequestParameters),
make_set(ResponseElements)
by
SourceIpAddress,
UserIdentityArn,
UserIdentityType,
EventName,
EventTime = TimeGenerated
)
on $left.ipAddress == $right.SourceIpAddress
// Filter results based on temporal correlation
| where AlertTime between ((EventTime - 1h) .. (EventTime + 1h))
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIpAddress
customDetails:
AWSUser: UserIdentityArn
AlertIp : ipAddress
AlertName: AlertName
kind: Scheduled
version: 1.0.0
Stages and Predicates
Stage 1: source
SecurityAlert
Stage 2: where
| where ProductName has "Azure Active Directory Identity Protection"
Stage 3: where
| where AlertSeverity == "High"
Stage 4: extend
| extend ipAddress = extract(@'\b(?:\d{1,3}\.){3}\d{1,3}\b', 0, Entities)
Stage 5: where
| where isnotempty(ipAddress)
Stage 6: summarize
| summarize make_set(Entities)
by
AlertTime = TimeGenerated,
ipAddress,
AlertName,
ProductName,
AlertSeverity
Stage 7: join
| join kind=inner (
AWSCloudTrail
| where isempty(ErrorMessage)
| extend UserType = tostring(parse_json(RequestParameters).userType)
| where EventName in~ ("CreateRole", "DeleteRole", "CreateUser", "CreateAccessKey", "DeleteAccessKey", "CreateGroup", "AddUserToGroup", "ChangePassword", "DeleteGroup", "DeleteUser", "RemoveUserFromGroup", "CreateVirtualMFADevice", "DeleteLoginProfile")
| summarize
make_set(RequestParameters),
make_set(ResponseElements)
by
SourceIpAddress,
UserIdentityArn,
UserIdentityType,
EventName,
EventTime = TimeGenerated
)
on $left.ipAddress == $right.SourceIpAddress
Stage 8: where
| where AlertTime between ((EventTime - 1h) .. (EventTime + 1h))
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
AlertSeverity | eq |
|
ErrorMessage | is_null | |
EventName | in |
|
ProductName | match |
|
ipAddress | is_not_null |
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
AlertName | summarize |
AlertSeverity | summarize |
AlertTime | summarize |
ProductName | summarize |
ipAddress | summarize |