In the recent investigations of compromised Microsoft 365 tenants I’ve been involved in, we have seen that one of the first actions the attacker make is connecting to Azure-AD as the compromised user.
This is most likely to exfiltrate information about the employees and all other accounts that is present in your Azure-AD.
In several cases, I’ve seen that the attacker use this information to target specific end-users to simply gain more credibility and even try to take control over the tenant. So basically this is a type of reconnaissance for the attacker to gain more information about the organization they now have access to.
In this blog post, we will go through how you can detect when an end-user might exfiltrate Azure-AD data through PowerShell and cover what options are available for blocking this.
Example of data an regular end-user can export from Azure-AD when compromised
End-users have by default full read access to Azure-AD, so this means that the attacker can use an compromised account to export information about your accounts that exist in Azure-AD.
Just a simple PowerShell command, and the attacker can export all attributes about all users (as long as the attributes have been populated). Here is just a subset of attributes available:
Mobile Phone numbers
If this isn’t convincing enough, it’s also really easy to find service accounts, users with specific administrative roles & dedicated administrative accounts that might be interesting for the attacker.
Detect end-users who connect to Azure-AD through PowerShell
In this section, we will focus on how to find end-users who connect to Azure-AD through PowerShell. This will cover connections though both MsolPowerShell and Azure AD PowerShell modules.
We will use Azure Monitor and a KQL query in this case.
We will look for all sign-in attempts to the application “Azure Active Directory PowerShell” that have the AppId “1b730954-1685-4b74-9bfd-dac224a7b894“.
We will “exclude” all sign-ins with an UPN that contains the onmicrosoft.com domain, since we target end-users and not service accounts / dedicated administrator accounts.
1.Sign-in to the Azure-Portal
3.Go to Logs
4.Enter the query and run it, to see that you get the correct data from the query
// Find All sign-ins to the Azure Active Directory PowerShell app where the UPN does not contain onmicrosoft.com domain SigninLogs | where AppId == "1b730954-1685-4b74-9bfd-dac224a7b894" and UserPrincipalName !contains "onmicrosoft.com" | project TimeGenerated, Identity, IPAddress, Location, AppDisplayName, Status
Now we need to configure an alert, so we can get notifications when this kind of actions have been detected!
5. Click on “New alert rule”
6. Now we need to adjust the alert condition, click on the condition as the picture below
7. Configure the Alert logic, Number of results Greater Than 0 and configure the Period and Frequency to your needs
8. Now we will configure the Actions, click on add action groups
9. In this case, we will add an existing action group. If you need one specific for this one, or do not have any action groups configured, create a new one.
10. Now configure your alert details and then click on create alert
Now I recommend you to test the alert, so you make sure that it detects and notify your team so you can start your investigation and foremost secure the environment from the attempted or detected breach.
Proactively remediate sign-ins to Azure-AD through PowerShell
Obviously it would be great if we could evade the situation when an compromised end-users account is used to export this kind of company information in the first place.
So I ended up testing a couple of different ways to block the possibility for the end-user to connect to Azure AD through the MsolPowerShell module and the Azure AD module.
Here is a couple of examples and some results
Example 1: Block sign-ins through Conditional Access (Does not solve the issue)
I tested to create an Conditional Access Policy, that included the application “Microsoft Azure Management” that includes the following services:
- Azure portal
- Azure Resource Manager provider
- Classic deployment model APIs
- Azure PowerShell
- Azure CLI
- Visual Studio subscriptions administrator portal
- Azure DevOps
- Azure Data Factory portal
Not so surprising, but this did not solve the issue when and end-user connects to Azure-AD through either Connect-Msolservice or Connect-AzureAD.
I wonder why Microsoft have chosen to not include these services within the Microsoft Azure Management application, any thoughts on this?
Example 2: Block the usage of MsolPowerShell (Does not solve the issue)
I also tested to block the usage of msolPowerShell through the AzureADMSAuthorizationPolicy. This blocks the usage of MsolPowerShell, but the end-user can still use the Azure AD PowerShell module to get to the data.
Example 3: Restrict end-users read-permission to other users within Azure-AD (Solves the issue, but with major end-user impact)
The last option is simply to restrict the end-users permissions to read data about other users in Azure-AD through Set-MsolCompanySettings -UsersPermissionToReadOtherUsersEnabled $False.
At first glance, this seemed to solve the issue for both MsolPowerShell and Azure AD PowerShell.
However, restricting the end-users permissions to read other end-users Azure-AD Profile and information results in some issues:
Unable to assign tasks to other end-users within the same team
Unable as an Microsoft 365 Group Owner to search for and add new users
Unable to read some delve information about other users
This is the only option that really restrict an end-user from exporting information about other users, but it comes with an impact that more or less no organization can cope with.
Until we get a better option to control theas kind of read permissions in Azure-AD we will simply need to focus on detecting this behavior and build automated processes for remediation
After posting this article, I got some feedback from Dr. Nestori Syynimaa that have found a way to evade this detection method, through using APIs directly with other client ids.
And unfortunately there any way to detect this method since Microsoft do not have any way to log the used API commands.
Read more about it at his blog o365blog.com