Query Details

Risky External Privileged Users With Enrichment Of Known Attack Paths And Tiering

Query

// Early draft: List of Directory Roles including known attack paths (defined by Emilien Socchi repository: https://github.com/emiliensocchi/azure-tiering/blob/main/Entra%20roles/tiered-entra-roles.json), classification by EntraOps, categories and rich details by Graph API and their role members with flags for Guest, Risky User and count of role members from IdentityInfo.
let SensitiveEntraDirectoryRoles = externaldata(RoleName: string, RoleId: string, Categories: string, RichDescription: string, isPrivileged: bool, Classification: dynamic, RolePermissions:dynamic)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_EntraIdDirectoryRoles.json"] with(format='multijson')
| where Classification.EAMTierLevelName != "Unclassified"
| mv-expand RolePermissions
| extend Categories = split(Categories,',')
| summarize EntraOpsCategory = make_set(RolePermissions.Category), Categories = make_set(Categories) by RoleName, RoleId, isPrivileged, EntraOpsClassification = tostring(Classification.EAMTierLevelName), RichDescription;
let KnownAttackPaths = externaldata(id: string, pathType: string, knownShortestPath: string, example: string)["https://raw.githubusercontent.com/emiliensocchi/azure-tiering/main/Entra%20roles/tiered-entra-roles.json"] with(format='multijson')
| where isnotempty(knownShortestPath) or isnotempty(example)
| project-rename RoleId = id, AttackPathType = pathType, ShortestAttackPath = knownShortestPath, AttackPathExample = example;
let PrivilegedUsers = IdentityInfo
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by AccountObjectId
| mv-expand AssignedRoles
| extend RoleName = tostring(AssignedRoles);
SensitiveEntraDirectoryRoles
| join kind=inner ( PrivilegedUsers ) on RoleName
| extend RoleAssignment = bag_pack_columns(AccountName, AccountUPN, UserType, Tags, IsAccountEnabled, RiskState)
| summarize RoleMembers = count(), RoleAssignments = make_list(RoleAssignment), RiskState = make_list(RiskState), UserType = make_list(UserType) by RoleName, RoleId, tostring(Categories), tostring(EntraOpsCategory), isPrivileged, tostring(EntraOpsClassification), tostring(RichDescription)
| extend RiskyAdmins = iff(RiskState has "atRisk", true, false)
| extend GuestAsAdmins = iff(UserType has "Guest", true, false)
| project-reorder RiskState, RoleName, RichDescription, EntraOpsClassification, isPrivileged, EntraOpsCategory,Categories, RoleMembers, RoleAssignments
| sort by RoleName asc
| join kind=inner ( KnownAttackPaths) on RoleId
| project-away RiskState, UserType, RoleId1
// Filter for risky or external users only
| where RiskyAdmins = true or GuestAsAdmins == true

Explanation

This query is designed to generate a comprehensive list of sensitive directory roles in an Azure environment, enriched with various details and classifications. Here's a simplified breakdown of what the query does:

  1. Load Sensitive Directory Roles: It fetches a list of directory roles from an external JSON file, including details like role name, ID, categories, descriptions, and classifications.

  2. Filter and Expand Roles: It filters out unclassified roles and expands the role permissions to categorize them.

  3. Load Known Attack Paths: It fetches known attack paths for these roles from another external JSON file, renaming and projecting relevant fields.

  4. Fetch Privileged Users: It retrieves information about privileged users from the IdentityInfo table, focusing on users who have been active in the last 14 days.

  5. Join Roles with Users: It joins the directory roles with the privileged users, creating a detailed list of role assignments, including flags for risky users and guest users.

  6. Summarize and Extend Data: It summarizes the data to count role members and includes additional flags for risky admins and guest admins.

  7. Filter and Sort: Finally, it filters the results to include only roles with risky or guest admins and sorts the list by role name.

In essence, the query provides a detailed and filtered list of sensitive directory roles, highlighting those with potential security risks due to the presence of risky or guest users.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: August 8, 2024

Tables

SensitiveEntraDirectoryRolesKnownAttackPathsIdentityInfo

Keywords

DirectoryRolesAttackPathsEntraOpsCategoriesGraphAPIRoleMembersGuestRiskyUserIdentityInfo

Operators

letexternaldatawithformatwheremv-expandextendsplitsummarizemake_setbytostringproject-renameisnotemptyprojectjoinkindbag_pack_columnscountmake_listiffhasproject-reordersortascproject-away==

Actions