Query Details

HQ 013 Admin Actions From Risky Users

Query

// HQ-013 — Audit Admin Actions from Risky Users
// Purpose  : Surface administrative operations in AuditLogs that were initiated by users
//            currently flagged as medium or high risk in AADRiskyUsers.
//            An attacker using a compromised account may perform privilege escalation or
//            persistence actions while the account is still risk-flagged.
// Tables   : AuditLogs, AADRiskyUsers
// MITRE    : TA0004 Privilege Escalation — T1078.004 Valid Accounts: Cloud Accounts
//            TA0003 Persistence — T1098 Account Manipulation
// Author   : Custom
// ---------------------------------------------------------------------------

let LookbackDays = 14d;
let SensitiveCategories = dynamic([
    "RoleManagement",
    "ApplicationManagement",
    "DirectoryManagement",
    "UserManagement",
    "PolicyManagement"
]);
let SensitiveActivities = dynamic([
    "Add member to role",
    "Remove member from role",
    "Add eligible member to role",
    "Add app role assignment to service principal",
    "Add app role assignment grant to user",
    "Add application",
    "Add service principal",
    "Add owner to application",
    "Add owner to service principal",
    "Add credentials to service principal",
    "Set domain authentication",
    "Update domain",
    "Update federation settings on domain",
    "Add policy",
    "Update policy",
    "Delete policy",
    "Reset password",
    "Admin reset user password",
    "Update user",
    "Add group member"
]);
// ── Step 1: Get users currently flagged as at-risk ──────────────────────────
let RiskyUsers = AADRiskyUsers
| where TimeGenerated > ago(LookbackDays)
| where RiskLevel in ("high", "medium") or RiskState == "atRisk"
| summarize
    RiskLevel            = take_any(RiskLevel),
    RiskState            = take_any(RiskState),
    RiskDetail           = take_any(RiskDetail),
    RiskLastUpdated      = max(RiskLastUpdatedDateTime)
    by RiskyUPN = tolower(UserPrincipalName);
// ── Step 2: Get sensitive admin audit operations initiated by human users ────
let AdminAuditOps = AuditLogs
| where TimeGenerated > ago(LookbackDays)
| where Category in (SensitiveCategories)
    or  ActivityDisplayName in~ (SensitiveActivities)
| extend ActorUPN = tolower(tostring(InitiatedBy.user.userPrincipalName))
| where isnotempty(ActorUPN)
| extend TargetResource = tostring(TargetResources[0].displayName)
| extend TargetUserUPN  = tostring(TargetResources[0].userPrincipalName)
| project
    AuditTime        = TimeGenerated,
    ActorUPN,
    ActivityDisplayName,
    Category,
    TargetResource,
    TargetUserUPN,
    Result,
    LoggedByService,
    CorrelationId;
// ── Step 3: Inner join — admin operations by currently-risky users ───────────
AdminAuditOps
| join kind=inner (RiskyUsers) on $left.ActorUPN == $right.RiskyUPN
| project
    AuditTime,
    ActorUPN,
    RiskLevel,
    RiskState,
    RiskDetail,
    RiskLastUpdated,
    ActivityDisplayName,
    Category,
    TargetResource,
    TargetUserUPN,
    Result,
    LoggedByService,
    CorrelationId
| sort by AuditTime desc

Explanation

This query is designed to identify and list administrative actions performed by users who are currently flagged as medium or high risk in Azure Active Directory (AAD). The goal is to detect potentially malicious activities, such as privilege escalation or account manipulation, that might be carried out by attackers using compromised accounts.

Here's a simplified breakdown of the query:

  1. Lookback Period: The query examines data from the past 14 days.

  2. Sensitive Categories and Activities: It focuses on specific categories and activities considered sensitive, such as role management, application management, and user management. These include actions like adding or removing roles, updating policies, and resetting passwords.

  3. Identify Risky Users: The query first retrieves users who have been flagged as medium or high risk, or are in an "at risk" state, within the specified lookback period.

  4. Audit Admin Actions: It then extracts administrative operations from the AuditLogs table that match the sensitive categories or activities and were initiated by human users.

  5. Join Data: The query performs an inner join between the risky users and the admin actions to find operations initiated by these risky users.

  6. Output: The final result includes details such as the time of the audit, the user who performed the action, their risk level and state, the type of activity, the target resource, and other relevant information, sorted by the most recent actions.

This helps in monitoring and investigating potentially harmful actions by users who are deemed risky, enhancing security oversight.

Details

David Alonso profile picture

David Alonso

Released: April 6, 2026

Tables

AuditLogsAADRiskyUsers

Keywords

AuditLogsAADRiskyUsersUserRoleManagementApplicationManagementDirectoryManagementUserManagementPolicyManagementActorUPNActivityDisplayNameCategoryTargetResourceTargetUserUPNResultLoggedByServiceCorrelationIdRiskLevelRiskStateRiskDetailRiskLastUpdated

Operators

letdynamicin==>agosummarizetake_anybytolowerwhereorextendtostringisnotemptyprojectjoinkind=inneronsort bydesc

Actions