Abusing Entra OAuth for fun and access to internal Microsoft applications

2 months ago (research.eye.security)

ohhhh the gifts multi-tenant app authorization keeps giving!

(laid off) Microsoft PM here that worked on the patch described as a result of the research from Wiz.

One correction I’d like to suggest to the article: the guidance given is to check either the “iss” or “tid” claim when authorizing multi-tenant apps.

The actual recommended guidance we provided is slightly more involved. There is a chance that when only validating the tenant, any service principal could be granted authorized access.

You should always validate the subject in addition to validating the tenant for the token being authorized. One method for this would be to validate the token using a combined key (for example, tid+oid) or perform checks on both the tenant and subject before authorizing access. More info can be found here:

https://learn.microsoft.com/en-us/entra/identity-platform/cl...

  • Assume every token is forged. Secure by default. Even if it wastes cpu, validate each and every field. Signatures only work if verified. While you're at it, validate it against your identity database as well. Double check, triple check if you must. This is what I taught my devs.

    Tenant, User, Group, Resource - validate it all before allowing it through.

    • also assume that the valid credentials have been stolen and are being used by a hacker.

      make sure anything done in a session can be undone as part of sanitizing the user

  • How is their "guidance" on what to check? Shouldn't it be a yes / no type thing? I've never worked on a system that had some checkbox for permissions that was labelled something like "maybe users in this group should be able to read everyone's personal notes".

Microsoft documentation is a nightmare, it doesn't surprise me there are vulnerabilities.

I recently built an SSO login using Entra ID (which was thankfully single-tenant) and I basically had to keep randomly stabbing in the dark until I got it to work with the correct scopes and extra fields returned with the access token.

Trying to search for any kind of Getting started guide just took me to child pages several levels deep full of incomprehensible Microsoft jargon and hyperlinks to helpful-sounding but ultimately similarly useless articles.

  • I find this consistent across the Microsoft ecosystem. I thought maybe Copilot would have an edge, but it’s just as lost as us (which i guess makes sense..)

  • I'm pretty sure what you're describing is the fact that Microsoft return Graph scopes by default when you request a token, I agree it is very annoying and only really documented if you read between the lines...

Not surprising at all. The configuration and docs for Oauth2 on Entra is an absolute cluster-f. Evidently, it’s so confusing that not even Microsoft themselves can get it right.

Their solution to this will be to add even more documentation, as if anyone had the stomach to read through the spaghetti that exist today.

  • Ran into this just a few weeks ago. According to the documentation it should be impossible to perform the authorization code flow with a scope that targets multiple resource servers. But if I request "openid $clientid/.default" it works. Kinda. At the end of the flow I get back an ID token and and access token. The ID token indicates that Azure has acknowledged the OIDC scope. But when I check the access token I can see that the scope has been adjusted to not include "openid". And indeed I'm unable to call Microsoft Graph which serves as the UserInfo endpoint. I was unable to find any good explanation for this behavior.

    • (I work on Entra) The OpenID Connect standard says that when you make a request using the OpenID Connect scopes (openid, profile, email, address, phone, offline_access), you get an access token that can be used to call the UserInfo endpoint. The OpenID Connect standard *does not say* what happens when you combine OpenID Connect scopes with OAuth scopes (like $clientid/.default).

      Entra treats such requests as an OpenID Connect OAuth hybrid. The ID token is as specified under OpenID Connect, but the access token is as expected from OAuth. In practice, these are the tokens most people want. The UserInfo endpoint is stupid - you can get all that information in the ID token without an extra round trip.

    • > According to the documentation it should be impossible to perform the authorization code flow with a scope that targets multiple resource servers.

      (I work on Entra) Can you point me to the documentation for this? This statement is not correct. The WithExtraScopesToConsent method (https://learn.microsoft.com/en-us/dotnet/api/microsoft.ident...) exists for this purpose. An Entra client can call the interactive endpoint (/authorize) with scope=openid $clientid/.default $client2/.default $client3/.default - multiple resource servers as long as it specifies exactly one of those resource servers on the non-interactive endpoint (/token) - i.e. scope=openid $clientid/.default. In the language of Microsoft.Identity.Client (MSAL), that's .WithScopes("$clientid/.default").WithExtraScopesToConsent("$client2/.default $client3.default"). This pattern is useful when your app needs to access multiple resources and you want the user to resolve all relevant permission or MFA prompts up front.

      It is true that an access token can only target a single resource server - but it should be possible to go through the first leg of the authorization code flow for many resources, and then the second leg of the authorization code flow for a single resource, followed by refresh token flows for the remaining resources.

    • You are confusing the purpose of the openid scope. That scope is used to "enable" OIDC in an otherwise pure-OAuth server. By itself, the openid scope never gives you access to anything itself, so it should not impact the Access Token at all - which should not include that scope (as it would be useless anyway). The UserInfo endpoint should only return claims that were requested in the authorization request via scopes like `profile` and `email`. The ID token is only returned if your response_type includes `id_token` and usually means you want the claims directly returned as a JWT ID Token, and won't be making Userinfo requests.

      2 replies →

Move to the cloud they said. It will be more secure then your intranet they said. Only fools pay for their own Ops team they said.

I’m so old and dumb that I don’t even understand why an app for internal Microsoft use is even accesible from outside its network.

  • The last decade has seen an increase push in what Google started calling "Zero Trust"[0] and dropping VPNs entirely. The issue being that once someone got into a VPN it was much, much harder to prevent them from accessing important data.

    So everything "internal" is now also external and required to have its own layer of permissions and the like, making it much harder for, e.g. the article, to use one exploit to access another service.

    [0] https://cloud.google.com/learn/what-is-zero-trust

    • I don’t see that really as an argument for this. You still should use VPN as an additional layer of security, assuming that you use some proper protocol. Then zero trust applies to internal network.

      23 replies →

    • The zero trust architechture implies (read: requires) that authentication occurs at every layer. Token reuse constitutes a replay attack that mandatory authentication is supposed to thwart. Bypass it and the system's security profile reverts back to perimeter security, with the added disadvantage of that perimeter being outside your org's control.

    • The big problem with the ZT approach is that smaller shops don't have a lot of developers and testers (some maybe with a security inclination) to be certain to a somewhat high degree that their app is written in a secure manner. Or be able to continuously keep abreast of every new security update Microsoft or other IdP makes to their stack.

      It is easy for Google/Microsoft and any other FAANG like company to preach about Zero Trust when they have unlimited (for whatever value of unlimited you want to consider) resources. And even then they get it wrong sometimes.

      The simpler alternative is to publish all your internal apps through a load balancer / API gateway with a static IP address, put it behind a VPN and call it a day.

      1 reply →

    • Zero trust is a good concept turned into a dumb practice. Basically people buying Google's koolaid for this forgot about "defense in depth". Yeah, authenticating every connection is great, throwing a big effing moat around it too is better.

      The other thing is most companies are not Google. If you're a global company with hundreds of thousands of people who need internal access, moats may be non-ideal. For a business located in one place, local-only on-premise systems which block access to any country which they don't actively do business with is leaps and bounds better.

  • > Move to the cloud they said. It will be more secure then your intranet they said. Only fools pay for their own Ops team they said.

    It seems that the fundamental issue surfaced in the blog post is that developers who work on authorizarion in resource servers are failing to check basic claims in tokens such as the issuer, the audience, and subject.

    If your developers are behind this gross oversight, do you honestly expect an intranet to make a difference?

    Listen, the underlying issue is not cloud vs self-hosted. The underlying issue is that security is hard and in general there is no feedback loop except security incidents. Placing your apps in a intranet, or VPN, does nothing to mitigate this issue.

    • But of course it does provide an additional layer of security that indeed could have reduced the likelihood of this issue being exploited.

      For me, the core of the discovered issue was that applications intended purely for use by internal MS staff were discoverable and attackable by anyone on the Internet, and some of those applications had a mis-configuration that allowed them to be attacked.

      If all those applications had been behind a decently configured VPN service which required MFA, any attacker who wanted to exploit them would first need access to that VPN, which is another hurdle to cross and would reduce the chance of exploitation.

      With a target like MS (and indeed most targets of any value) you shouldn't rely solely on the security provided by a VPN, but it can provide another layer of defence.

      For me the question should be, "is the additional security provided by the VPN layer justified against the costs of managing it, and potentially the additional attack surface introduced with the VPN".

      3 replies →

    • "The underlying issue is that security is hard and in general there is no feedback loop except security incidents."

      this is tbh, computer architecture is already hard enough and cyber security is like a whole different field especially if the system/program is complex

  • For me, I don't think that the application is public exposed is really the problem (i.e. not in intranet).

    I think the real problem is that these applications (Entra ID) are multi-tenant, rather than a dedicated single-tenant instance.

    Here, we have critical identity information that is being stored and shared in the same database with other tenants (malicious attackers). This makes multi-tenancy violations common. Even if Entra ID had a robust mechanism to perform tenancy checks i.e. object belongs to some tenant, there are still vulnerabilities. For example, as you saw in the blog post, multi-tenant requests (requests that span >= 2 tenants), are fundamentally difficult to authorize. A single mistake, can lead to complete compromise.

    Compare this to a single tenant app. First, the attacker would need to be authenticated as an user within your tenant. This makes pre-auth attacks more difficult.

  • That is probably still good advice for most companies. Joe's roof fixing business may be the best roof fixing business in 3 states, but would you want them to run their own server for their website, email, and booking?

    Anyone who is on this forum is capable of building their own stuff, and running their own server, but that is not most people.

Ignoring the ridiculous complexity of Entra and how easy it is to not realize you’re making a mistake with it (especially internal at Microsoft where there’s no delineation between all the internal tenants you need to support and 3P customer tenants), it’s really scary how people think an auth token is the only layer of security you need. These sites shouldn’t have ever been exposed to public internet (they’re not now). Network security is such an afterthought but it’s the best layer of defense you can have!

  • > Network security is such an afterthought but it’s the best layer of defense you can have!

    I think the opposite problem can be the case: people think that something inside a VPN is now secure and we don't have to worry too much about it.

  • > Network security is such an afterthought but it’s the best layer of defense you can have!

    I mean, it's an additional layer.

    Defense-in-depth is about having multiple.

$0 in rewards for RCE on the Windows build servers is crazy. I understand he didn’t find an actual zero-day, only a configuration issue, but still. Imagine the global havoc you can cause if you can pollute the build environment with backdoored DLLs…

  • I was a windows build engineer at Microsoft. I am unfamiliar with this specific UI for managing build tools (I think it may have been added after I left), however I would be surprised if it was actually RCE-capable.

    I notice that it requires the tool to be pulled from NuGet. While it looks like you could enter any package and NuGet source, I would be very surprised if there wasn’t a locked down whitelist of allowed sources (limited to internal Microsoft NuGet feeds).

    Locking down NuGet packages was one of the primary things we (the Windows Engineering System team) were heavily focusing on when I left years ago. We were explicitly prevented from using public NuGet packages at all. We had to repackage them and upload them to the internal source to be used.

That’s what you get. Entra ID doesn’t allow you to blacklist or whitelist specific tenants for multi tenant apps, which causes problems like this.

Add the fact that MSAL doesn’t work for stuff like browser extensions, so people have to implement their own security solutions to interact with Entra ID and it’s not surprising there are so many issues.

  • > Entra ID doesn’t allow you to blacklist or whitelist specific tenants for multi tenant apps.

    This one very annoying "feature" where I could say this app is available for the following tenants. No, only "my tenant" or "all tenants in Azure".

    One workaround I use is to set up apps with "only this tenant" and invite users from other tenants into my tenant. The other approach is to say "all tenants" and then use a group to enforce who can actually use the app.

    I don't know if there are any reasons behind this limitation or just an oversight or no client big enough asked for this feature.

    • Inviting individual users is a good pattern. If you want to allow an entire tenant into your tenant (e.g. if your parent company has a subdivision that has their own tenant), Entra has cross tenant access [1] for that use case.

      Generally, you should say "only this tenant" unless you're a SaaS provider. And if you're a SaaS provider, you should really already understand the need to keep your various customers data separate.

      [1] https://learn.microsoft.com/en-us/entra/external-id/cross-te...

      4 replies →

It's all very simple: Entra* (Azure AD or however you'd call it) should not be used for AuthZ. Entra AuthN is okayish, but forget about Entra AuthZ, do it all yourself. It's all very simple to avoid once you do AuthZ.

* No idea why the rename happened. Does some manager in Microsoft have the plaque: "Renomino, ergo sum."?

  • It's ok to use Entra for AuthZ. Just click the box that says "Require users to be assigned to this application" and assign them [1]. However - that's really the only AuthZ feature Entra has. If you don't enable AuthZ, you should not expect Entra to just magically do AuthZ for you.

    Edit: I would add - simple allow/deny authz is only relevant for the very simplest of apps (where all users have the same permissions). For any complex application, users will have different levels of access, which usually requires the application to do AuthZ.

    [1] https://learn.microsoft.com/en-us/entra/identity/enterprise-...

    • >For any complex application, users will have different levels of access, which usually requires the application to do AuthZ.

      Any application when AuthZ isn't simply yes/no, which rather quickly is just about all of them (even simple blogs have an admin tier), except for a very heavily microservice based architecture - where one would still want to have a much more convenient interface than Entra to see/manage the access permissions centrally... Entra AuthZ is at best a temporary development aid, but it's so easy to roll AuthZ yourself one might as well do it.

  • IMO “Azure AD” implies it is literally just AD hosted in Azure, when it’s become much more than that

It's Microsoft. I'm sure there are wonderful people there, but haven't we witnessed recently their master key leak, their engineers begging GPT in PRs to do stuff, their CEO boasting 'backend' engineers are going away.. I wouldn't rely on that company for anything, but I acknowledge a ton of people are not in that position. If they do stay however, it's malpractice.

OAuth is frequently marketed as "more secure". But implementations often confuse authentication with authorization, resulting in problems like this.

  • I just say auth. You decide which one I mean.

    • I know it's a joke, but it's funny because it's (somewhat) true. To add to the confusion, sometimes one of them gets abbreviated "authn". That is so unhelpful.

Did he really get no bounties out of this? The guy found a way into build boxes retail Windows is built on, potentially found the private key that would be used to generate license keys, likely could have dived in a little bit more after getting RCE on the build box to exfil the latest Windows 11 source code. He even found a way to issue rewards. They still gave him nothing?

  • If their rules say this doesn't deserve a bounty their bounty program is a sham.

    • Microsoft's bug bounty program is a shell of its former self. They quietly disqualified a lot of high-impact findings in 2023.

      In my own experience:

      - Leaked service principal credentials granting access to their tenant? $0 bounty.

      - Leaked employee credentials granting access to generate privileged tokens? $0 bounty.

      - Access to private source code? $0 bounty.

      Etc.

      8 replies →

    • My own , small, experience with MSRC is indeed their bug bounty program is not good, they take any possible opportunity to avoid payouts.

      this means that a lot of genuine bug bounty hunters just won't look at MS stuff and MS avoid getting things fixed, instead other attackers will be the ones finding things, and they likely won't report it to MS...

  • If Azure's horrific security track record (tens of exploits, often cross-tenant, often trivial) over the past few years doesn't give you pause, their joke of a bug bounty definitely should.

    Obviously nobody with power cares about security in Microsoft's Azure branch. Why does anyone trust continue trusting them? (I mean, I know that Azure is not something you buy by choice, you do because you got a good deal on it or were a Microsoft shop before, but still).

Azure is a true cluster F.

Okta (the other elephant in the room) has its own issues but at least it has decent documentation and even though it’s more expensive I think it’s worth paying that price just to keep security in a separate domain than co-mingle it with other Azure services.

Now remember these dimwits are bragging that 30% of their code is now written by AI; and have mandated Microsoft Accounts, set up OneDrive backup by default, and are providing infrastructure to OpenAI who is currently required to preserve even deleted chats. They also own LinkedIn.

This totally has no foreseeable potential consequences. It would be a real shame if some foreign hostile government with nuclear weapons managed to connect MS Account, LinkedIn Profile, and OpenAI accounts together by shared emails and phone numbers. Is it really worth starting a war for the crime of depantsing the nation?

  • Having done two rounds at different Fortune 10s (one being Microsoft) I can tell you: This isn't AI, this is the result of years of "make it work" and duct tape.

    This is "It'll be safe if we leave it on the intranet" and then someone says "Zero trust!" and then all the sudden things that had authentication on the inside are also going through a new and different layer of authentication. A stack of totally reasonable expectations stack tolerance on tolerance, and just like the Sig Sauer P320, it has a habit of shooting you in the foot when you least expect it.

  • To be fair, I’m pretty sure the code here was written before modern AI was a thing, back when dinosaurs roamed the earth.

This is still very effective for other organizations, not just microsoft. Of course they won't pay a bounty but any org that uses Micorosft 365/Office 365, Entrea ID which was Azure Active Directory can be polled and abused.

Was not new news, AFAIK from the article they just patched the microsoft tools but they won't be pushing it tenant wide for all orgs.

Automattic HTTP Headers:

   x-hacker: Want root?  Visit join.a8c.com and mention this header
   x-nananana: Batcache-Hit

Popular CDNs require SNI but do not offer a solution for plaintext domain names on the wire.

(ECH exists but is not enabled everywhere SNI is required.)

Meanwhile Wordpress hosts multiple HTTPS sites on same IP and does not require SNI.

(No plaintext domain names on the wire.)

This dumb stuff is why even Microsoft should use a common, secured and vetted pipeline for service principals so this does not happen.

Does this have a CVE or something? I have the weird feeling the cloud initiative here won't notice this ever otherwise...

Ohh, that's probably why our integration suddenly stopped working for single-tenant app registrations right before release. We were using the /common endpoint for everyone. That is disallowed now.