Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Multiple admin membership removals from newly created admin.

Back
Idcda5928c-2c1e-4575-9dfa-07568bc27a4f
RulenameMultiple admin membership removals from newly created admin.
DescriptionThis query detects when newly created Global admin removes multiple existing global admins which can be an attempt by adversaries to lock down organization and retain sole access.

Investigate reasoning and intention of multiple membership removal by new Global admins and take necessary actions accordingly.
SeverityMedium
TacticsImpact
TechniquesT1531
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1h
Query period7d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/MultipleAdmin_membership_removals_from_NewAdmin.yaml
Version1.0.0
Arm templatecda5928c-2c1e-4575-9dfa-07568bc27a4f.json
Deploy To Azure
let lookback = 7d; 
let timeframe = 1h; 
let GlobalAdminsRemoved = AuditLogs 
| where TimeGenerated > ago(timeframe) 
| where Category =~ "RoleManagement" 
| where AADOperationType in ("Unassign", "RemoveEligibleRole") 
| where ActivityDisplayName has_any ("Remove member from role", "Remove eligible member from role") 
| mv-expand TargetResources 
| mv-expand TargetResources.modifiedProperties 
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) 
| where displayName_ =~ "Role.DisplayName" 
| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))) 
| where RoleName == "Global Administrator" // Add other Privileged role if applicable 
| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) 
| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) 
| where Initiator != "MS-PIM"  // Filtering PIM events 
| extend Target = tostring(TargetResources.userPrincipalName) 
| summarize RemovedGlobalAdminTime = max(TimeGenerated), TargetAdmins = make_set(Target) by OperationName,  RoleName, Initiator, Result; 
let GlobalAdminsAdded = AuditLogs 
| where TimeGenerated > ago(lookback) 
| where Category =~ "RoleManagement" 
| where AADOperationType in ("Assign", "AssignEligibleRole") 
| where ActivityDisplayName has_any ("Add eligible member to role", "Add member to role") and Result == "success" 
| mv-expand TargetResources 
| mv-expand TargetResources.modifiedProperties 
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) 
| where displayName_ =~ "Role.DisplayName" 
| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))) 
| where RoleName == "Global Administrator" // Add other Privileged role if applicable 
| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) 
| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) 
| where Initiator != "MS-PIM"  // Filtering PIM events 
| extend Target = tostring(TargetResources.userPrincipalName) 
| summarize AddedGlobalAdminTime = max(TimeGenerated) by OperationName,  RoleName, Target, Initiator, Result 
| extend AccountCustomEntity = Target; 
GlobalAdminsAdded 
| join kind= inner GlobalAdminsRemoved on $left.Target == $right.Initiator 
| where AddedGlobalAdminTime < RemovedGlobalAdminTime 
| extend NoofAdminsRemoved = array_length(TargetAdmins) 
| where NoofAdminsRemoved > 1
| project AddedGlobalAdminTime, Initiator, Target, AccountCustomEntity, RemovedGlobalAdminTime, TargetAdmins, NoofAdminsRemoved
version: 1.0.0
status: Available
queryFrequency: 1h
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - AuditLogs
entityMappings:
- fieldMappings:
  - columnName: AccountCustomEntity
    identifier: FullName
  entityType: Account
kind: Scheduled
queryPeriod: 7d
severity: Medium
query: |
  let lookback = 7d; 
  let timeframe = 1h; 
  let GlobalAdminsRemoved = AuditLogs 
  | where TimeGenerated > ago(timeframe) 
  | where Category =~ "RoleManagement" 
  | where AADOperationType in ("Unassign", "RemoveEligibleRole") 
  | where ActivityDisplayName has_any ("Remove member from role", "Remove eligible member from role") 
  | mv-expand TargetResources 
  | mv-expand TargetResources.modifiedProperties 
  | extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) 
  | where displayName_ =~ "Role.DisplayName" 
  | extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))) 
  | where RoleName == "Global Administrator" // Add other Privileged role if applicable 
  | extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) 
  | extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) 
  | where Initiator != "MS-PIM"  // Filtering PIM events 
  | extend Target = tostring(TargetResources.userPrincipalName) 
  | summarize RemovedGlobalAdminTime = max(TimeGenerated), TargetAdmins = make_set(Target) by OperationName,  RoleName, Initiator, Result; 
  let GlobalAdminsAdded = AuditLogs 
  | where TimeGenerated > ago(lookback) 
  | where Category =~ "RoleManagement" 
  | where AADOperationType in ("Assign", "AssignEligibleRole") 
  | where ActivityDisplayName has_any ("Add eligible member to role", "Add member to role") and Result == "success" 
  | mv-expand TargetResources 
  | mv-expand TargetResources.modifiedProperties 
  | extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) 
  | where displayName_ =~ "Role.DisplayName" 
  | extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))) 
  | where RoleName == "Global Administrator" // Add other Privileged role if applicable 
  | extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) 
  | extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) 
  | where Initiator != "MS-PIM"  // Filtering PIM events 
  | extend Target = tostring(TargetResources.userPrincipalName) 
  | summarize AddedGlobalAdminTime = max(TimeGenerated) by OperationName,  RoleName, Target, Initiator, Result 
  | extend AccountCustomEntity = Target; 
  GlobalAdminsAdded 
  | join kind= inner GlobalAdminsRemoved on $left.Target == $right.Initiator 
  | where AddedGlobalAdminTime < RemovedGlobalAdminTime 
  | extend NoofAdminsRemoved = array_length(TargetAdmins) 
  | where NoofAdminsRemoved > 1
  | project AddedGlobalAdminTime, Initiator, Target, AccountCustomEntity, RemovedGlobalAdminTime, TargetAdmins, NoofAdminsRemoved  
tags:
- DEV-0537
triggerOperator: gt
id: cda5928c-2c1e-4575-9dfa-07568bc27a4f
description: |
  'This query detects when newly created Global admin removes multiple existing global admins which can be an attempt by adversaries to lock down organization and retain sole access. 
   Investigate reasoning and intention of multiple membership removal by new Global admins and take necessary actions accordingly.'  
triggerThreshold: 0
name: Multiple admin membership removals from newly created admin.
relevantTechniques:
- T1531
tactics:
- Impact
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/MultipleAdmin_membership_removals_from_NewAdmin.yaml
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/cda5928c-2c1e-4575-9dfa-07568bc27a4f')]",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/cda5928c-2c1e-4575-9dfa-07568bc27a4f')]",
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
      "kind": "Scheduled",
      "apiVersion": "2022-11-01",
      "properties": {
        "displayName": "Multiple admin membership removals from newly created admin.",
        "description": "'This query detects when newly created Global admin removes multiple existing global admins which can be an attempt by adversaries to lock down organization and retain sole access. \n Investigate reasoning and intention of multiple membership removal by new Global admins and take necessary actions accordingly.'\n",
        "severity": "Medium",
        "enabled": true,
        "query": "let lookback = 7d; \nlet timeframe = 1h; \nlet GlobalAdminsRemoved = AuditLogs \n| where TimeGenerated > ago(timeframe) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Unassign\", \"RemoveEligibleRole\") \n| where ActivityDisplayName has_any (\"Remove member from role\", \"Remove eligible member from role\") \n| mv-expand TargetResources \n| mv-expand TargetResources.modifiedProperties \n| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) \n| where displayName_ =~ \"Role.DisplayName\" \n| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))) \n| where RoleName == \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) \n| where Initiator != \"MS-PIM\"  // Filtering PIM events \n| extend Target = tostring(TargetResources.userPrincipalName) \n| summarize RemovedGlobalAdminTime = max(TimeGenerated), TargetAdmins = make_set(Target) by OperationName,  RoleName, Initiator, Result; \nlet GlobalAdminsAdded = AuditLogs \n| where TimeGenerated > ago(lookback) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Assign\", \"AssignEligibleRole\") \n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\") and Result == \"success\" \n| mv-expand TargetResources \n| mv-expand TargetResources.modifiedProperties \n| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) \n| where displayName_ =~ \"Role.DisplayName\" \n| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))) \n| where RoleName == \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) \n| where Initiator != \"MS-PIM\"  // Filtering PIM events \n| extend Target = tostring(TargetResources.userPrincipalName) \n| summarize AddedGlobalAdminTime = max(TimeGenerated) by OperationName,  RoleName, Target, Initiator, Result \n| extend AccountCustomEntity = Target; \nGlobalAdminsAdded \n| join kind= inner GlobalAdminsRemoved on $left.Target == $right.Initiator \n| where AddedGlobalAdminTime < RemovedGlobalAdminTime \n| extend NoofAdminsRemoved = array_length(TargetAdmins) \n| where NoofAdminsRemoved > 1\n| project AddedGlobalAdminTime, Initiator, Target, AccountCustomEntity, RemovedGlobalAdminTime, TargetAdmins, NoofAdminsRemoved\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P7D",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0,
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Impact"
        ],
        "techniques": [
          "T1531"
        ],
        "alertRuleTemplateName": "cda5928c-2c1e-4575-9dfa-07568bc27a4f",
        "customDetails": null,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "identifier": "FullName",
                "columnName": "AccountCustomEntity"
              }
            ]
          }
        ],
        "tags": [
          "DEV-0537"
        ],
        "status": "Available",
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/MultipleAdmin_membership_removals_from_NewAdmin.yaml",
        "templateVersion": "1.0.0"
      }
    }
  ]
}