The world is getting used to hybrid work, and using the cloud as our virtual workplace is the new normal. Microsoft Teams is the hub for all of this, and we use Azure AD B2B guest access to collaborate across organisations. The guest capabilities that Microsoft provides are very powerful and we only need to keep track on one account even though we collaborate in multiple tenants simultaneously.
The use of Azure AD guest access is very common in Microsoft 365 tenants, but in almost all cases, nothing has been done for guest access security. In this blog post I will demonstrate, in my opinion, a critical security risk with default guest security configuration. This is something you need to assess and probably fix ASAP!
Default Guest Permissions and Why They Are Dangerous
If you haven’t already, take a look at the default Azure AD guest permissions here (where the risky permissions are actually documented): Compare member and guest default permissions
The default setting is ‘Guest users have limited access to properties and memberships of directory objects’ and it is controlled from here: https://portal.azure.com/#blade/Microsoft_AAD_IAM/AllowlistPolicyBlade

With this setting, guests are allowed to do explicit lookups in Azure AD for other users and guest accounts by specifying its object ID or UPN. Guests are NOT allowed to fetch a complete list of all users Guests are also able to do explicit lookups for security groups and teams by specifying object ID. The danger here is that guests are also allowed to get the group memberships of specified users, and then the members of those groups. This makes it very easy to enumerate users, groups and teams with a loop. I bet you are starting to see where this is going! This could potentially be a GDPR issue as well. Let’s have a look:
By default, guests are allowed to connect to an Azure AD tenant with PowerShell. A guest can connect to a tenant with like this:

The tenant ID of the target tenant can be found in the Azure portal under the Switch directory blade: https://portal.azure.com/#settings/directory
When the guest is signed in, let’s have a look at what’s possible. First of all, a guest is not allowed to fetch users at random, or a complete list. A Forbidden error is returned.

But if we know the UPN of a user, we can get a lot of information about that user, including the users manager.

A guest can also get all group memberships, including security groups, of a specified user like this.

And ones we know the object ID of a group, we can get all other members of that group. This includes both Microsoft 365 groups/teams, security groups, and synced on-prem groups.

With all these capabilities, it is very easy to enumerate everything. Let’s look at that.
Get-DCAzureADUsersAndGroupsAsGuest
I’ve created a simple proof of concept script, included in DCToolbox version 1.0.24 and later. It lets a guest user enumerate users and security groups/teams when ‘Guest user access restrictions’ in Azure AD is set to the default configuration. It works around the limitation that guest users must do explicit lookups for users and groups. It basically produces a list of all users and groups in the tenant, even though such actions are blocked for guests by default.
The script will output one array with found users, and one array with found groups/teams. You can then export them to CSV or some other format of your choice. Export examples are outputed for your convenience.
This script is a proof of concept. Don’t use it for bad things! Only use it in test tenants!
Just specify the tenant ID of the target tenant where you are a guest, specify your UPN in your home tenant (probably your email adress), and then list one or more UPNs of users in the target tenant that you know of (probably their email addresses). The script will get all groups/teams that the target users are members of, get all other members of those groups, repeat this process up to five times until there are no new users and groups to find, and then output the result. If the tenant contains many groups, it can take some time to run this tool, but it will work. Some basic iteration basically. A friend of a friend of a friend…

Some of the things we can learn from the output:
- How many users and groups exist.
- The complete map of the organisation, including management and critical roles.
- What security groups are important.
- What licenses are being applied, for users and admins.
- What break glass accounts exists.
- What secret teams/projects exists.
- The list goes on…
Mitigation
To protect against this type of guest access enumeration, change the guest permissions to ‘Guest user access is restricted to properties and memberships of their own directory objects (most restrictive)’. This makes sure the guest can only lookup its own information. I’ve changed this for many of my customers already and we have not seen any major issues with the restricted configuration. However, things like user search in Teams and Planner might be limited. It is very easy to rollback if you should notice anything strange.

You should also consider blocking PowerShell access for guest accounts with Conditional Access. I recommend going with a white list approach where you only allow certain apps for guests, like Office 365 and Azure Information Protection. See my Conditional Access baseline for more info. Here is an example:

By going with this two step approach, restricting guest permissions and blocking PowerShell access for guests, you make sure that guests in your tenant can’t easily enumerate everything.
Summary
The default guest permissions in an Azure AD tenant implicates a great security risk and compliance risk. A guest user can easily steal the complete user database with a complete organisational map, all groups and teams with its memberships, and understand what accounts are important, like admin accounts and break glass accounts, what to further investigate, and where there are vulnerabilities. Please fix this in your tenant ASAP!
Please follow me here, on LinkedIn, and on Twitter!
Scary stuff :(. What if both mitigations are not applicable? Do you know if there is also a way to block powershell access instead of going with the whitelisting approach?
There is no way to explicitly block Azure AD PowerShell with Conditional Access. But guests probably never need to connect with PowerShell anyway. They almost always just needs access to Teams and O355.
You can block access via Conditional Access to both Azure AD PowerShell and Microsoft Graph PowerShell – you just need to create Service Principals for both – you can see those mitigations here: https://link.medium.com/0qBI6OQHilb
If you block external consultants that uses b2b accounts like this, they will effectively no longer be able to help you building things in azure or any other platform that uses azure ad, without asking internal IT every time they need to assign permissions to anything. It is something to consider, might be worth it, but might also slow down development considerably. And if you say just give them an internal account, then you have given them the same ability again, so yes, something to consider.
Seems your script only works on windows powershell?
Needs the AzureAD module which I think in only supported on windows powershell (vs the Az module).
Yes, but you can accomplish the same thing with PowerShell and Graph on other platforms. The script is just a simple PoC.
Any reference to an attack that happened using this technique to break into or get details of AAD?
Not that I’m aware of, but we use it all the time to demo this vulnerability.