Blog: How-Tos
Bypassing MFA on Microsoft Azure Entra ID
TL;DR
- Even though MFA is effective it is one security control amongst many
- Even if MFA is in use, check its configuration
- Consider unexpected patterns of use, such as people logging in from Linux or macOS
- Make sure you log and can react to out-of-band behaviour
Introduction
On a recent Red Team engagement we got Domain Admin privileges on the on-premises Active Directory (AD) network. But we had not yet gained access to their cloud estate, which was hosted in Azure. Our level of access to on-prem AD gave us access to a large number of resources, many containing sensitive data. But it did not allow us to access the goldmine of data stored in the cloud. This required us to authenticate with Azure Entra ID.
While looking at our options to make this jump we found that Azure Seamless Single Sign-On was in use. This allows users to access Azure Entra ID protected resources using their corporate devices without requiring them to enter their passwords.
Behind the scenes, this is achieved using two TGS tickets:
- HTTP/autologon.microsoftazuread-sso.com
- HTTP/aadg.windows.net.nsatc.net
But, as we were already DA, we could retrieve the required hashes to get hold of these tickets for any user, so this wasn’t a problem. It was when we attempted this that we hit a roadblock: it wanted us to use MFA:
Figure 1: MFA required for SSO
Step 1: Bypass the MFA
Our first port of call was a classic MFA bypass that regularly works against Azure if you make Azure think that you’re logging in from Linux then it won’t always require MFA. This can easily be performed by changing the browser’s user-agent. We chose one that made it look as if we were using the latest version of Chrome on Linux:
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Now, in this case, we have not yet been informed of the configuration issue that allowed this bypass to work against this specific tenant. But we have seen it before, quite a few times in fact. The most common root causes have been:
- Only automated systems within an organisation use Linux, so a broad bypass was added to allow these through without MFA
- Typos in Conditional Access policies
- A policy has been inadvertently disabled
- It was just plain overlooked, often in organisations that don’t use anything except Windows
Using a simple User-Agent switching browser extension, we then tried to login again, and got further, but came across another hurdle when we got this error message:
Step 2: Bypass conditional access
So, we can get round the MFA now, but we still need to be on a domain joined machine. The easiest way we could do this would be to join our own machine to the domain, which we could achieve via a proxy. The client domain had ms-DSMachineAccountQuota (MAQ – https://www.thehacker.recipes/a-d/movement/domain-settings/machineaccountquota) set to the default of 10, so any user could join up to 10 machines, and with our admin access we could do this without that. But we already exploited this previously in the engagement and wanted to try something new.
This engagement was being conducted from an “Assumed Compromise” perspective, so we had a legitimate domain joined laptop available to us. But it was locked down in various ways, notably, the only browsers installed were Edge and Chrome, both using the Chromium engine. This had been locked down via group policy to prevent access to various development tools or installing extensions. We therefore would struggle to achieve the User-Agent change required to bypass MFA.
Due to policies installed on the laptop, we also couldn’t install our own browser, well, directly. Instead, we downloaded a portable version of Firefox to our own devices, installed it, and copied the files to the domain joined laptop. This was able to bypass the restriction and provide us access to an unmanaged browser.
We then needed to configure Firefox to allow Windows authentication to allow the SSO. The first setting is simple, starting in Firefox 91, a simple checkbox setting is now present. Under “Settings” -> “Privacy & Security” -> “Passwords” -> “Allow Windows single sign-on for Microsoft, work, and school accounts”:
Figure 2: Enable Firefox Windows sign on
We also made some changes in “about:config” to ensure negotiate authentication was enabled for the SSO domains:
Figure 3: Negotiate authentication enabled
At this point, we injected the two TGS tickets required into our logon session on the domain joined laptop using Rubeus (shoutout to BOFNET), then attempted to login with our target user’s email address at https://portal.azure.com.
And… success! The Azure portal accessed without using MFA!
Figure 4: Portal accessed!
Step 3: Profit
So, at this point we achieved our goal, we leveraged our on-premises access to take control of the cloud estate. Importantly, we had no knowledge of our target user’s password (beyond the hash / krbtgt hash), MFA or access to their device. Additionally, we required no interaction with our target. We could now easily repeat this attack to login as any user, to any system that also supports SSO (for example, InTune, it makes a great C2).
These chains of attacks show how despite having put thought and effort into defending, and locking down their cloud environment, small misconfigurations can be chained by malicious actors to break through these protections and access critical resources.
How could we avoid this?
Now we’ve talked about what we did, let’s think about how this could have been stopped, or detected. Firstly, none of this would have been possible without the MFA bypass, the client has enforced strong MFA (code, or number matching only) to all users even when authenticating from their corporate devices, with an on-premises IP address. This shows how critical it is to ensure your MFA policies are set correctly so as not to leave a chink in the armour for attackers.
Secondly, we’ll address the unexploited chain: having the MAQ set to 10. This is the default in AD and is something we come across fairly regularly. This would have allowed us to have a domain joined machine if we did not have direct access to one ourselves. We advise that the MAQ is set to 0, and the ability to join machines to the domain is restricted. This can also be achieved via a Group Policy. There are a multitude of other attacks that only become possible when an attacker has access to Computer Account credentials, and creating their own account due to MAQ is a very common technique to acquire them.
Finally on the prevention front, preventing us from using our own, unmanaged browser would have left us at the mercy of the policies applied to Chromium, preventing us combining the MFA bypass and domain joined requirement. In this case, we were unable to directly install new software, but could execute portable applications. As is a common recommendation from our Purple and Red Team engagements, use of an application execution restriction tool, such as AppLocker, would have prevented this.
Now, these preventions may not have been enough, there may still be bypasses we didn’t identify in this test, or new techniques may be found in the future. So, it is also important to be able to detect when an attacker has gained access to something they shouldn’t have. Now in my opinion, the best way to detect this issue would be identifying the login as suspicious, the biggest indicator, is a user logging into Azure from the wrong device. The device I had was issued to “User1” whereas I logged in as “User2”. It is likely “User2” only ever logs in from the device issued to them.