Azure AD Privilege Escalation through Auto Assignment Policies
A recently released Azure AD Identity Governance feature can be abused for Privilege Escalation within Azure Environments through dynamic membership rules.
Dynamic Membership Rules, and the Risks
Besides the ordinary IAM, Azure AD has an extensive list of features that are intended to help and empower how organizations manage their users and groups, through different layers and perspectives.
A common component that’s rising in popularity among Azure AD features is Dynamic Membership Rules — appearing in places like Dynamic Groups, Administrative Units, and recently Access Package Auto Assignment policies.
A membership rule is a single string, that can contain multiple expressions, which automatically detects when attributes of a user or a device change within the tenant, triggering whatever action the feature was set out to do.
Here is an example membership rule designed to trigger all users within the Sales department that also have the letters “Adm” in any part of their display name.
(user.department -eq "Sales") and (user.displayName -contains "Adm_")
The feature is very useful, but it can also lead to unwanted and potentially exploitable outcomes if administrators don’t pay close attention to the conditions they set.
For example, in the rule described here, a look at the second expression reveals an issue around the “contains” condition.
“Contains” means that the expression will be true, as long as the right value (e.g. “Adm_”) appears in any segment of the left value (e.g., “user.displayName”).
If an administrator decides that anyone on the IT team always gets the suffix “Adm_” added to their display name, you would expect that only IT users would be subject to this rule. However, many other users will probably fall under this rule.
The same logic applies to other conditions such as “startsWith,” “notStartsWith,” “notContains,” “in,” “notIn,” and more.
Another exploitable issue surrounds rules that depend on user or device attributes which can be altered to allow hackers to insert themselves into privileged groups and resources. If a tenant’s guest configurations are not tightly defined and rules properly set to keep predators out, any user can invite guest accounts in, as evidenced in this example:
user.userPrincipalName -contains "mydomain.com"
It could appear that a user’s “userPrincipalName” can’t be altered, making loose comparisons impossible penetration routes. However, if a threat actor with a weak user can invite tenant guests, the rule does become exploitable.
These and other potentially exploitable outcomes of the membership rule in Dynamic Groups is a hot topic in the security community, and can be read about here. We can expect the issue to persist in new Azure features as well. Be on the lookout for it in upcoming features dependent on the existing membership rule component.
This brings us to central focus of this blog — Auto Assignment Policies.
Access Package Auto Assignment Policies
For an attack to occur, several mistakes must be made by the Azure administrators. To better understand the escalation, let’s look at it from the perspective of a vulnerable organization.
This is what the Access Packages pane looks like:
At the access package level, the administrator defines what the access package provides; for example, access to groups, Azure APIs, etc.
Let’s configure our access package in a way that any “valid” users that are granted the Access Package can become owners of the “TargetGroup” AD group.
During the creation of the package, we are also prompted to create an initial policy, which is not automatically assigned. This will conclude in our first Access Package.
If we go to Policies, we’ll notice a new button: “Add auto assignment policy.”
This button will be our gateway to utilizing the Dynamic Membership Rules feature. From the administrator’s perspective, we have created a weak rule that grants anyone access to our defined resources (TargetGroup) who has a “userPrincipalName” attribute that contains the “wantedstring” substring.
At this point, the new weak policy will show zero Active Assignments. This means no existing user in the tenant currently matches the rule syntax, so no one is being assigned the Access Package.
From an attack perspective, the scenario is as follows:
- Attacker has a compromised Azure AD user, but it doesn’t have privileges within the tenant
- During the information gathering phase, it learns about possible weak rules that might exist under Access Packages
- Attacker creates a third-party mailbox, named in a way that may match the vulnerable rule syntax (e.g., “wantedstring”)
- Attacker uses its legitimate account to invite the third-party email address as a tenant guest
- The tenant guest’s auto-created User Principal Name attribute is derived from its email address, which was set up by the attacker to comply with the weak rule syntax
- Guest account is automatically added to the TargetGroup due to the auto assignment policy
- Attacker now has compromised a user that belongs to the TargetGroup group and benefits from any new privileges it grants
In the case of Dynamic Groups, arbitrary users (group read access) are allowed to run queries like this to fetch weak membership rules:
az rest -u "https://graph.microsoft.com/v1.0/groups?$filter=membershipRule ge ' '&$select=id,displayName,membershipRule
For arbitrary users, Access Packages is harder to abuse than the Dynamic Groups Privilege escalation vector which would be a better attack route for an attacker with the “EntitlementManagement.Read.All” permission. It creates a blind spot, leaving the attacker to either start bulk-inviting guests hoping a condition is met, or try to deduce weak rule attributes by the package description, organizational patterns, etc.
If the user has enough permissions, combining these two commands will return the assignment membership rules (the “specificAllowedTargets” property contains the actual membership rule of the assignment):
az rest -u https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackagesaz rest -u https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackages/<ID>?$expand=assignmentPolicies
Also, the attacker would have to ensure that the tenant allows guest invitations — a default setting.
With that ability, the attacker can now create a third-party email matching the weak rule:
This will create a new user within the inviting tenant, with the User Principal Name of “imnotthewantedstring_protonmail.com#EXT#<ORG-DOMAIN>”, which matches against the membership rule of “user.userPrincipalName -contains wantedstring.”
The attacker now has a guest account in its control, which also benefits from the automatic policy assignments, assigning it in this case to be a group owner.
The severity of the elevation varies depending on what the auto assignment policy really grants, and what eventual privileges the user ends up with.
Protect your organization
Dynamic membership rules drive stronger IAM security by being an elegant alternative to other management practices. But their use comes with measurable risk. To mitigate these risks, double check these items:
- “contains,” “startsWith,” “notStartsWith,” “notContains,” “in,” and “notIn” are loose, easily exploitable operations. Think twice before you use them.
- The “match” and “notMatch” operators are used for matching regular expressions, which often introduce unexpected results, and are only recommended if you know your regex.
- “eq” and “ne” are the most preferable operators, but that doesn’t mean they can’t introduce mistakes as well if used incorrectly. For example, “user.accountEnabled -eq true” will dynamically add all the enabled users in the tenant.
Always think about what properties might be controlled by ordinary users in your tenant when creating rules. For example, if guest invitation is available for all users (which is enabled by default, but not recommended), be extra cautious when using rules that depend on properties that the inviting user can control, like “user.mail” and “user.userPrincipalName”.
Common risky expression examples❌❌💉
user.displayName -contains "Adm_"user.department -ne null
Better alternatives ✔👌
(user.displayName -startsWith "Adm_") and (user.mail -endsWith "@myorg.com")(user.department -eq "Sales") and (user.mail -endsWith "@myorg.com")
Tomer Bar has been in the cyber security field for more than 5 years. During which time he engaged in Penetration Testing against various technologies, operated in red team assessments, and led two penetration testing teams. Currently, Tomer works as a Security Researcher at CYE.