All You Need Is Guest
This is a long overdue blog version of a talk I gave at BlackHat USA 2023 titled All You Need Is Guest. Slides and video recording are available as well.
Intro
When you get invited as a guest to an EntraID tenant you get restricted deny-by-default access. You shouldn’t have access to any resource not explicitly shared with you, right?
Well, no. By the end of this post, you’ll see how guests can find credentials to Azure resources and SQL servers and exploit them to get full data dumps of everything behind them.
Why invite guests in?
As a small cybersecurity company every enterprise engagement starts the same – how do we share sensitive data back and forth? We don’t want to use email (you’ve never done that, right?).
How do we share resources securely? EntraID external identities – guests – are the mechanism to do that in a safe way.
To accomplish that, it needs to satisfy two conditions: It needs to be easy for vendors to onboard and for IT/security to control.
Indeed, it’s super easy to gain access and thus for vendors to onboard. Under default configuration, any user on Teams can just invite a guest in by adding them to a new team. In most enterprises, this is up to individual user choice.
For IT/security the promise is incredible - by inviting guests in you can apply your existing Microsoft security infrastructure to them. Conditional access policies, Intune, the entire Microsoft Security stack.
There is a caveat here though, it is crucial that guests don’t get full access to your tenant otherwise you have just compromised your own controls. Guest access should be deny-by-default.
Guest accounts in practice
Reality differs. Grab any corporate account, go to make.powerapps.com and click on connections.
You will see enterprise credentials lying around waiting to be leveraged.
These were overshared due to a simple mistake by a business user. They are available for ANY EntraID account to pick up and use, including guests.
These connections are created by business users. Or more precisely, anyone in your organization can just plug in their credentials and create a connection. There are thousands of connectors available for people to use to any enterprise system you can think of. Including on-prem.
Exploit
These credentials are not just available for use directly. They are used to give Power Apps or Power Automate access to enterprise resources.
There are a few mechanisms protecting these credentials from a wondering guest (or insider malicious insider, for that matter). Most of the talk was focused on bypassing each and every one of those. Here is a quick overview of each:
Blocked by license
Guests cannot view Power Apps or query connections through Power Apps because they don’t have they right license. While licensing is definitely not a security mechanism, it is somethings used as such nevertheless.
But wait, what if we get a trial license on our home tenant - the one we control? That should work for the guest tenant, right?
Well, it works! Power Apps validate that you have a license in at least one of the tenant you are part of. Not the specific one you are trying to access.
Blocked by DLP
The main security mechanism for Power Platform is their DLP. Do not get confused, this is not a DLP in the cybersecurity sense. It does not allow labeling of sensitive data not does it provide data leakage controls. Instead, it is an allow/deny list for which connectors can be used. It provides very blunt controls - allowing or blocking entire categories of services like SharePoint or SQL Servers. If you want to get to a more granular level, you need to manage a tight and ever-changing URL list.
It is also VERY easy to bypass.
Nevertheless, it can deny access to connections in case those are blocked in the DLP policy. Here, we have a DLP policy that blocks SQL Server connections.
At this point, I basically had to wave my hands and ask the audience to allow me to move forward. I will share full details on a subsequent post.
Say the connection isn’t blocked by DLP then. What now?
Digging into the API calls made by a Power App using a SQL server connection you can spot a call to a service called API Hub. Though those calls, the app makes both read and write operations on top of the SQL server.
API Hub is a service an intermediary service that allows Power Platform apps and users to use shared credentials without actually getting access to the credentials themselves. Instead, API Hub generate a REST API interface for any imaginable operation on the underlying service. Any call to API Hub gets translated to a call to the underlying service using the credentials stored in its internal storage. Those can be user credentials (OAuth refresh tokens), passwords or long-lived secrets. This is how connection sharing works. Sharing a connection in Power Platform means allowing another user to use your credentials which are stored in API Hub.
Blocked by programmatic access to API Hub
Users can’t just generate tokens with the right scope to query API Hub, it is an internal Microsoft resource.
You can’t use a built-in public client app because those need to be pre-approved to query API Hub.
You can’y use your own app because API Hub is an internal resource you cannot grant your apps access to.
FOCI to the rescue
At this point, we are stuck.
We know that these credentials are available for us in the Power Apps UI but we want direct access to API Hub. We can’t generate the right token though.
We know that the Power Apps app can generate tokens to API Hub, but it is a confidential app so we can’t generate tokens on its behalf.
Or can we?
Recalling FOCI, we can take a look into the list of know FOCI apps.
We can generate a token using Azure CLI (of course we can) and exchange that token for a Power Apps token to API Hub! Actually, it turned out you can just ask Azure CLI for a token to API Hub directly.
The fun part
powerpwn is an offensive toolset for M365 focused on Power Platform. It combines the methods above we now have full access to the services behinds those credentials shared in the Power Platform.
It can also install a backdoor that persist even if the user gets deleted, deploy a phishing app on a Microsoft owned domain and more. But that is a story for another day.
powerpwn recon -t <tenant_id>
finds all of the overshared credentials, apps and automations your user has access to.
powerpwn dump -t <tenant_id>
goes through each and every one of those and dumps all data from their underlying services. Every SQL server table, every blob in a storage account.
You also gain access to a full Swagger UI for each credential that allows you to run arbitrary commands using those credentials (whatever is possible in Power Platform). For SQL Server, you can pass any SQL command to run on the server.
I strongly encourage you to play around with it!
Defense
Tactically, use powerpwn. Find and delete these overshared connections. Ideally, do it on a schedule or even automated.
But admittedly this is a tactical patch. We are placing dev-level power in the hands of every enterprise user without guardrails or training. Of course people will make bad judgment calls. Still, share with everyone? That it just too much.
I strongly suggest using the OWASP LCNC Top 10 to start getting a handle on citizen development.