I’ve been looking into Azure attack primitives over the past couple of months to gain a better understanding of how the system works, what privileges and permissions can be abused, what limitations may exist, and what attack paths present themselves in real environments. I’ve kept my eyes open for attacks that allow the following:
Lateral movement from an on-premises (on-prem) device/user context into Azure
Privilege escalation within an Azure Active Directory (AAD) tenant
Lateral movement from Azure AD back down to on-prem AD
The first two scenarios are well-documented by folks like Dirk-Jan Mollema, Karl Fosaaen, and Sean Metcalf. That third scenario is really what I wanted to find, as it would open up the possibility of using an Azure AD tenant to bridge the gap between disparate environments that do not explicitly trust each other, and would also make the prospect of taking over an Azure AD tenant all the more attractive and impactful as an attacker.
In this blog post, I’ll explain how we can abuse Microsoft Endpoint Manager to move laterally from an Azure tenant to an on-prem AD domain. This abuse becomes possible when Windows devices have been Hybrid-Joined to both the Azure tenant and the on-prem Active Directory domain. Note that hybrid-joined Windows systems are not the only type of system you can target with Microsoft Intune — you can also target Azure-joined Windows systems and macOS systems that are Azure- or Hybrid-joined.
This post is one output of a larger research effort into Azure abuses by myself and Ryan Hausknecht.
On the offensive side, several people have been laying the groundwork for this kind of attack to become apparent, namely:
Sean Metcalf, Trimarc Security
Karl Fosaaen, NetSPI
Dirk-jan Mollema, Fox-IT
Tal Maor, Microsoft
Leron Gray, Microsoft
On the operational side, several people have documented the inner workings and operational-level ins-and-outs of Hybrid Device Join, Intune, and Microsoft Endpoint Manager, namely:
Michael Niehuas, Microsoft
Oliver Kieselbach, Glueck & Kanja Consulting AG
Jos Lieben, Freelance
Elli Shlomo, Netafim
Intune & Hybrid Azure Join
Azure provides organizations with all the tools they need to manage user and service principal identities, with attractive features that promise to lower overhead, provide greater uptime, and simplify administration. Admins at many organizations want to use that same system, Azure, to manage the systems users are logging on to and accessing corporate resources with. To that end, Microsoft has made several tools available to Azure admins: ConfigMgr, Intune, and Endpoint Manager.
These tools allow admins to configure endpoints to a certain extent, and while these systems may pale in comparison to the fine-grained control of endpoints you can achieve with Group Policy, the scope of systems you can configure and control is rather significant, thanks to Hybrid Azure AD joined devices.
Just as a computer can be “joined” to an on-prem Active Directory domain (along with all the consequences of doing so), a computer can also be “joined” to an Azure Active Directory domain. There are significant technical and practical differences between joining a computer to vanilla AD and AzureAD, but the very basic analogy will suffice for now. Not only can a computer be joined to a vanilla AD domain or an AzureAD domain, a computer can also be joined to both a vanilla AD domain and an AzureAD domain: this is what Microsoft refers to as Hybrid Azure AD join.
If an organization is using Hybrid Azure AD join to manage on-prem Windows systems, then an attacker with control of a “Global Admin” or “Intune Administrator” principal can execute arbitrary PowerShell scripts on those on-prem devices as the SYSTEM user. On-prem systems from different Active Directory domains can be hybrid-joined to the same tenant, which in certain circumstances have resulted in attack paths originating in one on-prem domain (or one of the many other identity platforms that can authenticate to Azure) and landing in another on-prem domain, where absolutely no domain or forest trusts exist.
Let me say that again: pivoting from an Azure AD tenant into an on-prem AD domain can enable attack paths between completely distinct identity management environments and platforms that do not explicitly trust each other, or even know about each other.
Determining which systems are hybrid-joined couldn’t be simpler. You can easily see devices that are hybrid-joined in the Azure portal by following these steps:
After logging in to Azure, click or search for “Azure Active Directory:”
This takes you to the tenant overview page. In the left navigation, click “Devices:”
This page will list all devices that are “joined” to the Azure AD tenant, regardless of join type. We only have a small handful of devices joined to this tenant, and so it’s easy to pick out the three devices that are “Hybrid Azure AD joined:”
You can filter this list by clicking “Add filters”, selecting “join type”, then selecting “Hybrid Azure AD Joined”. This will only show those devices that are hybrid-joined. You can further filter this list to only show those systems where Intune is successfully managing the device by adding the “IsCompliant” filter:
We can also very easily enumerate these devices with PowerShell, using Microsoft’s AzureAD PowerShell module. After importing the module and authenticating to the tenant, use Get-AzureADDevice to easily list all devices joined to the tenant:
The objects returned by Get-AzureADDevice have many more properties than what are shown by default, which you can see by piping the output of the cmdlet to Get-Member, or by piping each object to “Select *” in the pipeline. We are particularly interested in the “DeviceTrustType” property:
When the property of the “DeviceTrustType” property is “ServerAd”, then this device is “Hybrid Azure AD Joined,” meaning it is joined to both an on-prem Active Directory domain and the Azure AD tenant. We can use PowerShell’s pipeline and filtering to easily list out all devices with this join type, and display the most relevant info we care about for each device:
There does not appear to be a way at this time to determine what on-prem domains these devices are joined to, at least not from the perspective of an Azure tenant authenticated user. Other Azure objects, such as users and groups, have an “OnPremSecurityIdentifier” property that lists the on-prem SID of the object, but that information does not appear to be available for devices.
Enumerating the above information can be done by any Azure tenant authenticated user — no special privileges or roles needed. Abusing one of the three endpoint management systems to execute PowerShell scripts on hybrid-joined devices requires either the “Global Admin” or “Intune Administrator” roles.
Microsoft has signaled that they are consolidating all current endpoint management systems under one unified tool called Microsoft Endpoint Manager, so we will focus on that tool for this post.
First, have your PowerShell script ready to go and save it somewhere as a PS1 file. Take all the necessary operational security (opsec) and AMSI-bypass steps you want at this point, keeping in mind the script will run as the SYSTEM user unless you specify otherwise. Also keep in mind that the script will be written to disk, so take whatever AV bypass measures you need as well.
Next, log into the Azure web portal as the user with the “Global Admin” or “Intune Administrator” role activated (we’ll talk about how to escalate to these roles in a later post.) After authenticating, access Endpoint Manager at https://endpoint.microsoft.com:
Click on “Devices” on the left, which takes you, unsurprisingly, to the devices overview:
Here you can see basic stats about the devices managed by Endpoint Manager. Keep in mind that as these systems (ConfigMgr, Intune, Endpoint Manager) are migrating under one unified tool, Endpoint Manager; the information you see here may be misleading. You may have more hybrid-joined devices to the tenant than what you can see in this interface.
Click on “Scripts” under the “Policy” section to go to the scripts management page:
Here’s where we will add our new PowerShell script. Click “Add,” then click “Windows 10:”
This will bring you to the “Add Powershell Script” page. On this first page, you’ll enter a name for the script and a brief description. Depending on your objectives, you may want to pick a name here that will not raise suspicions. For the sake of a simple demo, we’ll stick with a “Hello World” script for now:
On the next page, click the folder and then select your PS1 from the common dialogue window. You’ve now got three options to configure, but can leave them all in the default “No” position. Most interestingly, keeping the first selection as “No” will cause the script to run as the SYSTEM user:
Click next, and you’ll see the page that lets you scope which systems and users this script will execute for:
You can choose to assign the script to “All devices,” “All users,” or “All users and devices.” If you leave the “Assign to” dropdown at its default selection of “Selected groups,” you can scope the script to only execute on systems or for users that belong to certain security groups. The choice is yours: run the script on every possible system or constrain it to only run on certain systems by scoping it to existing security groups or by adding specific devices or users to new security groups.
Click “Next” and you’ll see the review page which lets you see what you’re about to do:
Click “Add” and Azure will begin registering the script.
At this point, the script is now ready to run on your target systems. This process works similarly to Group Policy, in that the Intune agent running on each device periodically checks in (by default every hour) with Intune/Endpoint Manager to see if there is a PowerShell script for it to run, so you will need to wait up to an hour for your target system to actually pull the script down and run it:
Before we talk about how to detect this attack happening, let’s talk about how to prevent it from happening in the first place. Recall that this attack requires access to a privileged identity within Azure — an identity that has the rights to add PowerShell scripts to Microsoft Endpoint Manager.
There are two tenant-level roles with the explicit ability to add PowerShell scripts to Endpoint Manager: “Global Administrator” and “Intune Administrator.” You may be able to audit who has those roles activated via the Azure Portal, or you can use the Powershell AzureAD module to enumerate who currently has those roles activated. For example, to list the principals with the “Global Admin” role activated:
Do you trust all of these users/principals to execute code as SYSTEM on your hybrid-joined, Endpoint Management-enrolled systems?
We can also list all principals with the “Intune Admin” role activated:
But, there are also eligible role assignments that can be controlled at the tenant “Roles and Administrators” page, or via Microsoft Privileged Identity Management (MS-PIM). You’ll currently want to use the web GUI to list eligible role assignments in those two spots.
To complicate matters even more, it is possible for principals with other roles to grant themselves or others one of those two roles, but, as stated earlier, we’ll talk more about those kinds of attacks in a later blog post.
Additionally, you may want to know and audit which systems within your on-prem domains are being managed by Intune. There are several ways to do this, depending on what sort of information or telemetry you have access to:
1. Find all systems where the Intune agent service is installed.
Service short name: IntuneManagementExtension
Service display name: “Microsoft Intune Management Extension”
Binary: C:\Program Files (x86)\Microsoft Intune Management Extension\Microsoft.Management.Services.IntuneWindowsAgent.exe
2. Find all systems that have resolved the Intune MDM enrollment URLs. By default, those URLs are:
3. Find all systems where the Intune service log folder/files exist. Those files reside in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs, and three files may exist in that folder:
When the Intune agent pulls down and executes PowerShell scripts, a number of artifacts are created on the endpoint — some permanent and some ephemeral. Let’s get the ephemeral artifacts out of the way first.
Two files are created on the endpoint when a PowerShell script is executed in the following locations:
C:\Program files (x86)\Microsoft Intune Management Extension\Policies\Scripts
C:\Program files (x86)\Microsoft Intune Management Extension\Policies\Results.
The file under the “Scripts” folder will be a local copy of the PS1 stored in Azure, and the file under the “Results” folder will be the output of the PS1; however, both of these files are automatically deleted as soon as the script finishes running.
There are also permanent artifacts left over (assuming the attacker doesn’t tamper with them). First, a full copy of the contents of the PS1 can be found in this log file:
For example, here is the “Hello World” script we used in the demo above, logged as the “Policy Body” of the script:
The hash you see there is also logged in the registry under this key:
Collecting these artifacts may help with detecting or responding to an attack where an attacker achieved execution on a device by abusing Endpoint Manager.
Abusing Microsoft Endpoint Manager gives attackers a way to execute code as the SYSTEM user on devices that are Hybrid-Joined to an Azure tenant. It also enables execution on devices that are simply joined to the tenant, as long as those devices are being managed by ConfigMgr/Intune/Endpoint Manager. This is the first attack vector we’ve discovered so far that allows turning control of an Azure tenant into code execution within an on-prem domain without needing to reset on-prem user passwords. As Microsoft continues to introduce more management capabilities that blur the line between the cloud and on-prem, we expect more attack primitives of this nature to appear.