In the dynamic landscape of cybersecurity, attackers are adept at exploiting vulnerabilities, and one critical avenue they often use is the absence of essential controls within a Microsoft 365 environment. This blog explores how three overlooked security controls in your Microsoft 365 environment can help attackers gain initial access to your environment, find sensitive information that shouldn’t be accessible, and escalate their privileges within your Microsoft 365 ecosystem. Understanding the tactics behind these maneuvers is crucial for organizations aiming to fortify their defenses and thwart potential threats at every stage of an attack. Let’s delve into it!
Multifactor authentication (MFA) is the most critical control in your Microsoft 365 environment. As stated by Microsoft, setting up MFA for all your users can prevent 99% of attacks on your accounts. For that reason, all M365 security assessments should verify if you have MFA enabled in your environment. But a question that is often neglected is: Where are the coverage gaps? In other words, are there any user accounts that MFA may not protect because of a misconfiguration, a misunderstanding, or an oversight?
So, how can you check your MFA coverage? Let’s understand two different ways that can introduce such a coverage gap.
Even though this method is no longer recommended by Microsoft (as it is now considered legacy), we sometimes see customers’ environments with what is called “Per-user MFA”. As explained in Microsoft documentation here, per-user MFA is when MFA is enabled on a per-account basis. This can be configured through the Microsoft Entra console by navigating to the Identity section > Users > All Users, then clicking on “Per-user MFA”; or browsing directly to this URL: https://account.activedirectory.windowsazure.com/usermanagement/multifactorverification.aspx.
Once in there, you can see whose accounts have MFA either disabled, enabled, or enforced. From this portal though, and as you can see below, it is not possible to filter accounts with an MFA status of “disabled” (thanks, Microsoft…):
So, how can you extract a list of all accounts where per-user MFA is disabled?
Thanks to The Sysadmin Channel, you can use a PowerShell script to extract this information: https://thesysadminchannel.com/get-per-user-mfa-status-using-powershell/. After installing the requirements, the following command can be used to get a nice CSV list of all accounts with their MFA status:
.\Get-PerUserMFAStatus.ps1 | Export-Csv -Path org-per-mfa-details.csv.
From Excel, you can now filter on the “Disabled” state and go through the list of accounts where MFA is not enabled:
Do you have any user accounts with their MFA status set as disabled? If yes, you have a coverage gap; if not, you’re good to go on this one!
Using Conditional Access policies to enable MFA is the recommended approach to protect users, but it requires a Microsoft Entra ID P1 or P2 plan. As per-user MFA, this approach can also have a coverage gap depending on how the CA policies are defined. This is often the case when the policy enforcing MFA is not configured to apply to “All users”. In other words, when the policy is enforced for specific groups, all active accounts not in these particular groups will not be protected by MFA.
So, how can you understand how many accounts are not protected by such a policy? Well, the Microsoft Entra Admin center gives us everything we need this time:
There you go, you should now know if you have an MFA coverage gap if using Conditional Access policies.
Now that you understand if you have a gap in your MFA coverage, the next step is to remediate it. Here are some suggestions for you to consider:
The second topic I want to discuss is Security and Microsoft 365 groups that are configured as open-to-join for all users. This particular topic is not very well known and can introduce important risks in your environment. Let’s delve into it.
Microsoft 365 defines different types of groups for different purposes:
These three types of groups can be browsed from the Microsoft 365 Admin Center:
https://admin.microsoft.com/Adminportal/Home?#/groups.
Depending on how these groups are created, users in your tenant may be able to join these groups without requesting anything from the group owners. This type of group is what Microsoft calls: “open to join for all users”.
For Microsoft 365 groups, this is seen as the privacy level of the group. Here is a screenshot of a Microsoft 365 group creation, where this information is shown:
By default, the privacy level is set to Public as shown above, so be mindful of these default settings if you are in a hurry when creating a new group…
For Security groups, it is getting more complicated… If a group is created through either the Azure portal or the Microsoft 365 Admin center, the group will not be open to join for all users. But if the security group is created through the “My Group” application at https://myaccount.microsoft.com/, then the user has to choose a Policy:
By default, the policy value is not set to anything, so users must deliberately choose the “open to join” option. But seriously, why does Microsoft allow such a feature for groups created through this interface?!
Anyways, Beau Bullock from Black Hill Infosec recently published a great blog post about his tool, GraphRunner, and explains how to identify these types of groups. Using GraphRunner, and more particularly the Get-UpdatableGroups module, we can easily list all “joinable groups”:
How great is that? Now we can go through this list, understand if users are supposed to be allowed to join the group, and take appropriate actions when necessary.
As explained by Beau in his blog post, open-to-join groups are interesting targets for attackers or pentesters:
Except if you have a real use case for allowing users to create their own security groups, you can disable this capability in your tenant. As explained by Microsoft documentation here, this can easily be disabled in your environment by configurating your group settings.
Now depending on the group type, the situation is more or less complicated to remediate:
The third and last topic I want to discuss is about misconfigured access for SharePoint team sites. This is also something often overlooked, mainly because the list of SharePoint sites can be overwhelming. So, how can you easily spot which ones of your SharePoint sites are potentially misconfigured and accessible to all users?
One easy solution, again, is to use GraphRunner. Thanks to the Get-SharepointSiteURLs module, the list of SharePoint sites accessible to your account can easily be returned. Before running this module though, understand that it will return all legitimate SharePoint sites your account currently has access to. So, if you want to eliminate false positives, I would recommend using a test account with no particular permissions or group assignments.
Here is an example of what the execution of this module looks like:
276 site URLs, that looks quite a lot! Hopefully your environment won’t return as many sites as this example.
If you used your own account and have a very long list, chances are your account has legitimate access to these sites and what you see are mainly false positives. This is why I was recommending running this with a test account not being part of many groups.
That being said, we usually find many SharePoint sites in our customers environments that are misconfigured. From our experience, it either comes from:
Securing a Microsoft 365 environment is not something easy. Many security controls need to be checked, and we have only described three here that are often neglected. Thankfully, the following tools and benchmarks are available to help organizations assess and improve their M365 security controls:
Our approach at Mirai Security, is to use the CIS benchmarks for Microsoft 365 as a solid base which we then improve with custom tests and controls based on the latest threats and techniques used by attackers. If you are interested in assessing the level of security of your environment and staying ahead of the attackers, let us know!