Query Details

Added Owner To Application By Unprivileged

Query

  // Owner added to high privileged application by unprivileged or lower privileged user
  let SensitiveMsGraphPermissions = externaldata(EAMTierLevel: string, Category: string, APIPermission: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_MsGraphPermissions.json"] with(format='multijson');
  let SensitiveAadDirectoryRoles = externaldata(EAMTierLevel: string, Category: string, id: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_AadDirectoryRoles.json"] with(format='multijson');
  AuditLogs
  | where OperationName in ("Add owner to application","Add owner to service principal")
  | extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
  | extend InitiatingUserOrAppId = iff(isnotempty(InitiatedBy.user.id),tostring(InitiatedBy.user.id), tostring(InitiatedBy.app.id))
  | extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
  | mv-expand TargetResources
  | mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.ObjectID" | extend ApplicationObjectID = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
  | mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.DisplayName" | extend ApplicationDisplayName = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
  | mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.AppId" | extend ApplicationAppId = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
  | join kind=inner(
    AADServicePrincipals_CL
    | mv-expand parse_json(APP_s), parse_json(SPAppRoleAssignments_s)
    | mv-expand SPAppRoleAssignments_s.AppRolePermissionSensitivity, SPAppRoleAssignments_s.AppRolePermission, parse_json(SPAADRoleAssignments_s)
    | mv-expand SPAADRoleAssignments_s.roleDefinitionName, SPAADRoleAssignments_s.roleDefinitionId
    | extend AppRolePermission = tostring(SPAppRoleAssignments_s_AppRolePermission)
    | extend AadDirectoryRoleId = tostring(SPAADRoleAssignments_s_roleDefinitionId)
    | extend AadDirectoryRoleName = tostring(SPAADRoleAssignments_s_roleDefinitionName)
    // Option A: Filter on classification from AadSpInsights
    //| where SPAADRoleAssignments_s_roleDefinitionId == true or SPAppRoleAssignments_s_AppRolePermissionSensitivity == "critical"
    // Option B: Filter on enrichment from external classification schema
    | join kind=leftouter(
        SensitiveMsGraphPermissions | project AppRolePermissionTierLevel = EAMTierLevel, AppRolePermissionCategory = Category, APIPermission
        ) on $left.AppRolePermission == $right.APIPermission
    | join kind=leftouter(
        SensitiveAadDirectoryRoles | project AadDirectoryRoleTierLevel = EAMTierLevel, AadDirectoryRoleTierCategory = Category, id
        ) on $left.AadDirectoryRoleId == $right.id
    | extend AppClassification = iif((AppRolePermissionTierLevel == "ControlPlane" or AadDirectoryRoleTierLevel == "ControlPlane"), "ControlPlane", "ManagementDataPlane")
    | project APPObjectId = tostring(parse_json(APP_s).APPObjectId), APPDisplayName = tostring(parse_json(APP_s).APPDisplayName), ObjectId_g, ObjectType_s, AppRolePermission, AadDirectoryRoleName, AppClassification, AppRolePermissionCategory, AadDirectoryRoleTierCategory, tostring(parse_json(APP_s).APPSignInAudience)
    | distinct APPObjectId, APPDisplayName, ObjectId_g, ObjectType_s, AppClassification
    ) on $left.ApplicationObjectID == $right.APPObjectId  
  | join kind=inner (
    PrivilegedEAM_CL
        | where TimeGenerated > ago(14d)
        | summarize arg_max(TimeGenerated, *) by ObjectId
        | extend InitiatingUserOrAppClassification = iff(isnotempty(parse_json(Classification)), parse_json(Classification), "UserAccess")
        | project ObjectId, ObjectAdminTierLevel, ObjectAdminTierLevelName, InitiatingUserOrAppClassification
    ) on $left.InitiatingUserOrAppId == $right.ObjectId
| where parse_json(tostring(parse_json(InitiatingUserOrAppClassification))) !contains AppClassification
| project-reorder OperationName, ApplicationObjectID, ApplicationDisplayName, ApplicationAppId, AppClassification, InitiatingUserOrApp, InitiatingUserOrAppId, InitiatingIpAddress, InitiatingUserOrAppClassification

Explanation

This query retrieves audit logs where a user or application adds an owner to a high privileged application. It joins the audit logs with data from external sources to classify the application and the user or application performing the action. The query then filters out any logs where the user or application classification does not contain the application classification. The final result includes information about the operation, application, user or application, and their classifications.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: September 16, 2023

Tables

AuditLogsAADServicePrincipals_CLSensitiveMsGraphPermissionsSensitiveAadDirectoryRolesPrivilegedEAM_CL

Keywords

Devices,Intune,User,Application

Operators

externaldatawithformatwhereinextendiffisnotemptytostringmv-expandreplace_stringjoinkindprojectoniifdistinctsummarizearg_maxbyagoparse_jsoncontainsproject-reorder

Actions