Azure Privileged or Elevated Role Assignment


Description

Detects when a privileged or elevated Azure role is assigned. Privileged roles include Owner, Contributor, User Access Administrator, Security Admin, and other high-impact administrative roles. Elevated roles include resource-specific roles with significant permissions like Storage Blob Data Owner, Key Vault Administrator, etc.

Query · python

from panther_azureactivity_helpers import (
    add_role_assignment_fields,
    azure_activity_alert_context,
    azure_activity_success,
    azure_parse_json_string,
    get_role_definition_id,
    match_role_name,
)

ROLE_ASSIGNMENT_WRITE = "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
ELEVATE_ACCESS_ACTION = "MICROSOFT.AUTHORIZATION/ELEVATEACCESS/ACTION"

# Common privileged role definition IDs (subscription-level built-in roles)
PRIVILEGED_ROLES = {
    "8e3af657-a8ff-443c-a75c-2fe8c4bcb635": "Owner",
    "b24988ac-6180-42a0-ab88-20f7382dd24c": "Contributor",
    "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9": "User Access Administrator",
    "fb1c8493-542b-48eb-b624-b4c8fea62acd": "Security Admin",
    "92b92042-07d9-4307-87f7-36a593fc5850": "Azure File Sync Administrator",
    "a8889054-8d42-49c9-bc1c-52486c10e7cd": "Reservations Administrator",
    "f58310d9-a9f6-439a-9e8d-f62e7b41a168": "Role Based Access Control Administrator",
    "150f5e0c-0603-4f03-8c7f-cf70034c4e90": "Data Purger",
}

ELEVATED_ROLES = {
    "ba92f5b4-2d11-453d-a403-e96b0029c9fe": "Storage Blob Data Contributor",
    "b7e6dc6d-f1e8-4753-8033-0f276bb0955b": "Storage Blob Data Owner",
    "dffb1e0c-446f-4dde-a09f-99eb5cc68b96": "Azure Arc Kubernetes Admin",
    "a001fd3d-188f-4b5d-821b-7da978bf7442": "Cognitive Services OpenAI Contributor",
    "00482a5a-887f-4fb3-b363-3b7fe8e74483": "Key Vault Administrator",
    "8b54135c-b56d-4d72-a534-26097cfdc8d8": "Key Vault Data Access Administrator",
    "4633458b-17de-408a-b874-0445c86b69e6": "Key Vault Secrets User",
}

# Combine all role mappings for lookup
ALL_ROLES = {**PRIVILEGED_ROLES, **ELEVATED_ROLES}


def extract_role_name(event):
    # Extract and return the role name being assigned from the event
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    role_def_id = get_role_definition_id(request_body)
    return match_role_name(role_def_id, ALL_ROLES)


def rule(event):
    # For elevate access, operationName is a dict with "value" key
    operation_name_value = event.deep_get("operationName", "value", default="")
    if operation_name_value:
        operation_name_value = str(operation_name_value).upper()
        # Check if this is the elevate access action (subscription-level elevation)
        if (
            operation_name_value == ELEVATE_ACCESS_ACTION
            and event.deep_get("status", "value") == "Succeeded"
        ):
            return True

    # For role assignments, operationName is a string
    operation_name = event.get("operationName", "")
    if isinstance(operation_name, str):
        operation_name = operation_name.upper()
        # Check if this is a privileged/elevated role assignment
        if operation_name == ROLE_ASSIGNMENT_WRITE:
            return extract_role_name(event) is not None and azure_activity_success(event)

    return False


def title(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Handle elevate access action (subscription-level elevation)
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        caller_identity = event.deep_get("identity", "claims", "name", default="<UNKNOWN_USER>")
        return f"Azure subscription access elevated by [{caller_identity}]"

    # Handle role assignment
    role_assignment = event.deep_get("resourceId", default="<UNKNOWN_ASSIGNMENT>")
    role_name = extract_role_name(event) or "<UNKNOWN_ROLE>"
    role_str = "<UNKNOWN_ROLE_TYPE>"
    if role_name in PRIVILEGED_ROLES.values():
        role_str = "privileged"
    if role_name in ELEVATED_ROLES.values():
        role_str = "elevated"
    return f"Azure [{role_str}] role " f"[{role_name}] assigned on " f"[{role_assignment}]"


def severity(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Elevate access action grants User Access Administrator at root scope
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        return "HIGH"

    # Get the role name being assigned
    role_name = extract_role_name(event)

    if role_name:
        # Check if it's a privileged role
        if role_name in PRIVILEGED_ROLES.values():
            return "HIGH"
        # Check if it's an elevated role
        if role_name in ELEVATED_ROLES.values():
            return "MEDIUM"

    return "DEFAULT"


def alert_context(event):
    context = azure_activity_alert_context(event)

    # Parse and add request body fields
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    add_role_assignment_fields(context, request_body)

    # Add role name
    role_name = extract_role_name(event)
    if role_name:
        context["role_name"] = role_name

    return context

Analyst notes

  1. Find all Azure Monitor Activity role assignment and elevate access operations by the callerIpAddress in the 24 hours before and after the alert to identify if multiple privileged roles are being granted
  2. Query for all API calls by the principalId in the 6 hours after the role assignment to determine if newly granted permissions were immediately exploited
  3. Check if the callerIpAddress is associated with known VPN services or corporate IP ranges and compare to the caller's authentication patterns in the past 30 days
Raw source Azure Privileged or Elevated Role Assignment · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: azure_role_assignment_privileged_or_elevated.py
RuleID: "Azure.MonitorActivity.RoleAssignment.PrivilegedOrElevated"
DisplayName: "Azure Privileged or Elevated Role Assignment"
Enabled: true
LogTypes:
  - Azure.MonitorActivity
Severity: Medium
Description: >
  Detects when a privileged or elevated Azure role is assigned.
  Privileged roles include Owner, Contributor, User Access Administrator, Security Admin, and other high-impact administrative roles.
  Elevated roles include resource-specific roles with significant permissions like Storage Blob Data Owner, Key Vault Administrator, etc.
Reports:
  MITRE ATT&CK:
    - TA0004:T1098 # Persistence: Account Manipulation
    - TA0003:T1098.003 # Persistence: Add Office 365 Global Administrator Role
    - TA0005:T1078.004 # Defense Evasion: Valid Accounts - Cloud Accounts
Tags:
  - AZT402
  - Persistence
  - Defense Evasion
  - Account Manipulation
  - Add Office 365 Global Administrator Role
  - Valid Accounts
  - Cloud Accounts
Runbook: |
  1. Find all Azure Monitor Activity role assignment and elevate access operations by the callerIpAddress in the 24 hours before and after the alert to identify if multiple privileged roles are being granted
  2. Query for all API calls by the principalId in the 6 hours after the role assignment to determine if newly granted permissions were immediately exploited
  3. Check if the callerIpAddress is associated with known VPN services or corporate IP ranges and compare to the caller's authentication patterns in the past 30 days
Reference: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
SummaryAttributes:
  - resourceId
  - callerIpAddress
  - correlationId
Tests:
  - Name: Owner Role Assignment
    ExpectedResult: true
    Log:
      {
        "time": "2024-12-17T10:30:00.0000000Z",
        "resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/providers/Microsoft.Authorization/roleAssignments/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "operationName": "Microsoft.Authorization/roleAssignments/write",
        "operationVersion": "2021-04-01",
        "category": "Administrative",
        "resultType": "Success",
        "resultSignature": "200",
        "callerIpAddress": "1.1.1.1",
        "correlationId": "f1e2d3c4-b5a6-7890-bcde-f12345678901",
        "location": "",
        "tenantId": "87654321-4321-4321-4321-111111111111",
        "identity": {
          "authorization": {
            "action": "Microsoft.Authorization/roleAssignments/write",
            "evidence": {
              "principalId": "6b6d44f0-b13a-46a0-bfde-161324d4c34d",
              "principalType": "User",
              "role": "Owner",
              "roleAssignmentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
              "roleAssignmentScope": "/subscriptions/12345678-1234-1234-1234-123456789abc",
              "roleDefinitionId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
            }
          }
        },
        "properties": {
          "requestbody": "{\"Id\":\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\"Properties\":{\"PrincipalId\":\"770797c4-e05a-43f9-bda2-1f1f379987ae\",\"PrincipalType\":\"ServicePrincipal\",\"RoleDefinitionId\":\"/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635\",\"Scope\":\"/subscriptions/12345678-1234-1234-1234-123456789abc\"}}"
        }
      }
  - Name: Non-Privileged Role Assignment
    ExpectedResult: false
    Log:
      {
        "time": "2024-12-17T13:30:00.0000000Z",
        "resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/providers/Microsoft.Authorization/roleAssignments/c3d4e5f6-a7b8-9012-cdef-111111111111",
        "operationName": "Microsoft.Authorization/roleAssignments/write",
        "operationVersion": "2021-04-01",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "1.2.3.4",
        "correlationId": "h3g4f5e6-d7c8-9012-def0-333333333333",
        "location": "eastus",
        "tenantId": "87654321-4321-4321-4321-222222222222",
        "identity": {
          "authorization": {
            "action": "Microsoft.Authorization/roleAssignments/write",
            "evidence": {
              "principalId": "6b6d44f0-b13a-46a0-bfde-161324d4c34d",
              "principalType": "User",
              "role": "Owner",
              "roleAssignmentId": "c3d4e5f6-a7b8-9012-cdef-111111111111",
              "roleAssignmentScope": "/subscriptions/12345678-1234-1234-1234-123456789abc",
              "roleDefinitionId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
            }
          }
        },
        "properties": {
          "requestbody": "{\"Id\":\"c3d4e5f6-a7b8-9012-cdef-111111111111\",\"Properties\":{\"PrincipalId\":\"22222222-3333-4444-5555-666666666666\",\"PrincipalType\":\"User\",\"RoleDefinitionId\":\"/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7\",\"Scope\":\"/subscriptions/12345678-1234-1234-1234-123456789abc\"}}"
        }
      }
  - Name: Elevated Role Assignment (Storage Blob Data Owner)
    ExpectedResult: true
    Log:
      {
        "time": "2024-12-17T14:00:00.0000000Z",
        "resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/providers/Microsoft.Authorization/roleAssignments/d4e5f6a7-b8c9-0123-def4-111111111111",
        "operationName": "Microsoft.Authorization/roleAssignments/write",
        "operationVersion": "2021-04-01",
        "category": "Administrative",
        "resultType": "Success",
        "resultSignature": "200",
        "callerIpAddress": "1.2.3.4",
        "correlationId": "i4h5g6f7-e8d9-0123-efgh-222222222222",
        "location": "westus",
        "tenantId": "87654321-4321-4321-4321-111111111111",
        "identity": {
          "authorization": {
            "action": "Microsoft.Authorization/roleAssignments/write",
            "evidence": {
              "principalId": "6b6d44f0-b13a-46a0-bfde-161324d4c34d",
              "principalType": "User",
              "role": "Owner",
              "roleAssignmentId": "d4e5f6a7-b8c9-0123-def4-111111111111",
              "roleAssignmentScope": "/subscriptions/12345678-1234-1234-1234-123456789abc",
              "roleDefinitionId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
            }
          }
        },
        "properties": {
          "requestbody": "{\"Id\":\"d4e5f6a7-b8c9-0123-def4-111111111111\",\"Properties\":{\"PrincipalId\":\"33333333-4444-5555-6666-777777777777\",\"PrincipalType\":\"ServicePrincipal\",\"RoleDefinitionId\":\"/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b\",\"Scope\":\"/subscriptions/12345678-1234-1234-1234-123456789abc/resourcegroups/storage-rg/providers/Microsoft.Storage/storageAccounts/mystorageacct\"}}"
        }
      }
  - Name: Elevate Access to All Azure Subscriptions
    ExpectedResult: true
    Log:
      {
        "time": "2024-12-24T15:45:00.0000000Z",
        "resourceId": "/providers/Microsoft.Authorization",
        "operationName": {
          "value": "Microsoft.Authorization/elevateAccess/action",
          "localizedValue": "Assigns the caller to User Access Administrator role"
        },
        "operationVersion": "2018-01-01-preview",
        "category": "Administrative",
        "resultType": "Success",
        "status": {
          "value": "Succeeded",
          "localizedValue": "Succeeded"
        },
        "callerIpAddress": "203.0.113.42",
        "correlationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
        "tenantId": "87654321-4321-4321-4321-111111111111",
        "identity": {
          "claims": {
            "name": "attacker@example.com",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn": "attacker@example.com"
          }
        },
        "level": "Information"
      }

# ------ paired body: azure_role_assignment_privileged_or_elevated.py ------

from panther_azureactivity_helpers import (
    add_role_assignment_fields,
    azure_activity_alert_context,
    azure_activity_success,
    azure_parse_json_string,
    get_role_definition_id,
    match_role_name,
)

ROLE_ASSIGNMENT_WRITE = "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
ELEVATE_ACCESS_ACTION = "MICROSOFT.AUTHORIZATION/ELEVATEACCESS/ACTION"

# Common privileged role definition IDs (subscription-level built-in roles)
PRIVILEGED_ROLES = {
    "8e3af657-a8ff-443c-a75c-2fe8c4bcb635": "Owner",
    "b24988ac-6180-42a0-ab88-20f7382dd24c": "Contributor",
    "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9": "User Access Administrator",
    "fb1c8493-542b-48eb-b624-b4c8fea62acd": "Security Admin",
    "92b92042-07d9-4307-87f7-36a593fc5850": "Azure File Sync Administrator",
    "a8889054-8d42-49c9-bc1c-52486c10e7cd": "Reservations Administrator",
    "f58310d9-a9f6-439a-9e8d-f62e7b41a168": "Role Based Access Control Administrator",
    "150f5e0c-0603-4f03-8c7f-cf70034c4e90": "Data Purger",
}

ELEVATED_ROLES = {
    "ba92f5b4-2d11-453d-a403-e96b0029c9fe": "Storage Blob Data Contributor",
    "b7e6dc6d-f1e8-4753-8033-0f276bb0955b": "Storage Blob Data Owner",
    "dffb1e0c-446f-4dde-a09f-99eb5cc68b96": "Azure Arc Kubernetes Admin",
    "a001fd3d-188f-4b5d-821b-7da978bf7442": "Cognitive Services OpenAI Contributor",
    "00482a5a-887f-4fb3-b363-3b7fe8e74483": "Key Vault Administrator",
    "8b54135c-b56d-4d72-a534-26097cfdc8d8": "Key Vault Data Access Administrator",
    "4633458b-17de-408a-b874-0445c86b69e6": "Key Vault Secrets User",
}

# Combine all role mappings for lookup
ALL_ROLES = {**PRIVILEGED_ROLES, **ELEVATED_ROLES}


def extract_role_name(event):
    # Extract and return the role name being assigned from the event
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    role_def_id = get_role_definition_id(request_body)
    return match_role_name(role_def_id, ALL_ROLES)


def rule(event):
    # For elevate access, operationName is a dict with "value" key
    operation_name_value = event.deep_get("operationName", "value", default="")
    if operation_name_value:
        operation_name_value = str(operation_name_value).upper()
        # Check if this is the elevate access action (subscription-level elevation)
        if (
            operation_name_value == ELEVATE_ACCESS_ACTION
            and event.deep_get("status", "value") == "Succeeded"
        ):
            return True

    # For role assignments, operationName is a string
    operation_name = event.get("operationName", "")
    if isinstance(operation_name, str):
        operation_name = operation_name.upper()
        # Check if this is a privileged/elevated role assignment
        if operation_name == ROLE_ASSIGNMENT_WRITE:
            return extract_role_name(event) is not None and azure_activity_success(event)

    return False


def title(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Handle elevate access action (subscription-level elevation)
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        caller_identity = event.deep_get("identity", "claims", "name", default="<UNKNOWN_USER>")
        return f"Azure subscription access elevated by [{caller_identity}]"

    # Handle role assignment
    role_assignment = event.deep_get("resourceId", default="<UNKNOWN_ASSIGNMENT>")
    role_name = extract_role_name(event) or "<UNKNOWN_ROLE>"
    role_str = "<UNKNOWN_ROLE_TYPE>"
    if role_name in PRIVILEGED_ROLES.values():
        role_str = "privileged"
    if role_name in ELEVATED_ROLES.values():
        role_str = "elevated"
    return f"Azure [{role_str}] role " f"[{role_name}] assigned on " f"[{role_assignment}]"


def severity(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Elevate access action grants User Access Administrator at root scope
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        return "HIGH"

    # Get the role name being assigned
    role_name = extract_role_name(event)

    if role_name:
        # Check if it's a privileged role
        if role_name in PRIVILEGED_ROLES.values():
            return "HIGH"
        # Check if it's an elevated role
        if role_name in ELEVATED_ROLES.values():
            return "MEDIUM"

    return "DEFAULT"


def alert_context(event):
    context = azure_activity_alert_context(event)

    # Parse and add request body fields
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    add_role_assignment_fields(context, request_body)

    # Add role name
    role_name = extract_role_name(event)
    if role_name:
        context["role_name"] = role_name

    return context

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.