Query Details

RULE 09 Privileged Ops New IP

Query

// Rule    : Azure - Privileged Management Operations from a New Source IP for Established Identity
// Severity: Medium
// Tactics : InitialAccess, Persistence
// MITRE   : T1078
// Freq    : PT6H   Period: P14D
//==========================================================================================

let PrivilegedOps = dynamic([
    "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE",
    "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/DELETE",
    "MICROSOFT.KEYVAULT/VAULTS/WRITE",
    "MICROSOFT.KEYVAULT/VAULTS/DELETE",
    "MICROSOFT.COMPUTE/VIRTUALMACHINES/WRITE",
    "MICROSOFT.INSIGHTS/DIAGNOSTICSETTINGS/DELETE",
    "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE",
    "MICROSOFT.AUTHORIZATION/LOCKS/DELETE"
]);
let HistoricalCallerIPs = AzureActivity
    | where TimeGenerated between (ago(14d) .. ago(6h))
    | where OperationNameValue has_any (PrivilegedOps)
    | where ActivityStatusValue =~ "Success"
    | where isnotempty(Caller) and isnotempty(CallerIpAddress)
    | summarize HistoricalIPs = make_set(CallerIpAddress, 50) by Caller;
AzureActivity
| where TimeGenerated > ago(6h)
| where OperationNameValue has_any (PrivilegedOps)
| where ActivityStatusValue =~ "Success"
| where isnotempty(CallerIpAddress)
| where CallerIpAddress !startswith "168.63." and CallerIpAddress !startswith "169.254."
| join kind=inner HistoricalCallerIPs on Caller
| where not(set_has_element(HistoricalIPs, CallerIpAddress))
| summarize
    OperationCount = count(),
    Operations = make_set(OperationNameValue, 10),
    AffectedResources = make_set(ResourceId, 10),
    CallerIP = any(CallerIpAddress),
    SourceIPs = make_set(CallerIpAddress, 5),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by Caller, SubscriptionId
| extend
    AccountName = tostring(split(Caller, "@")[0]),
    AccountUPNSuffix = tostring(split(Caller, "@")[1])

Explanation

This KQL query is designed to detect potentially suspicious activities in Azure by identifying privileged management operations performed from new IP addresses for established user identities. Here's a simplified breakdown of what the query does:

  1. Privileged Operations: It defines a list of sensitive operations, such as writing or deleting role assignments, key vaults, virtual machines, and other critical resources.

  2. Historical IPs: It looks at Azure activity logs from the past 14 days up to 6 hours ago to gather a list of IP addresses that have successfully performed these privileged operations for each user.

  3. Recent Activity: It then examines activities from the last 6 hours to see if any of these privileged operations were performed successfully.

  4. New IP Detection: The query checks if these recent operations were carried out from IP addresses that are not in the historical list for the respective user, excluding certain known internal IP ranges (168.63.x.x and 169.254.x.x).

  5. Summary of Findings: If such new IP addresses are found, it summarizes the findings by counting the operations, listing the types of operations and affected resources, and noting the first and last time these operations were seen. It also extracts the username and domain from the caller's email address.

In essence, this query helps identify potential unauthorized access or misuse of privileged accounts by flagging operations from unfamiliar IP addresses, which could indicate a security threat.

Details

David Alonso profile picture

David Alonso

Released: March 12, 2026

Tables

AzureActivity

Keywords

AzureActivityCallerCallerIpAddressOperationNameValueActivityStatusValueResourceIdSubscriptionIdAccountNameAccountUPNSuffixTimeGenerated

Operators

letdynamicbetweenagohas_any=~isnotemptysummarizemake_setby>!startswithjoinkind=inneronnotset_has_elementcountanyminmaxextendtostringsplit

Actions