In this post we will explore an entry point into how to leverage AzureAD app registrations for offensive purposes.
Before getting into it, I'd like to thank @Antonlovesdnb for helping me explore this further and the defensive guidance. Also a shoutout to @dafthack for spitballing ideas about ways to abuse this. Cheers to you both :)
UPDATE Wanted to add some more shout outs and links to some awesome work others have done on or related to this:
It's also important I point out up front that nothing I am demonstarting I can take credit for. Evidence of this used in the wild was talked about as mentionted here on Twitter.
In AzureAD a user (unless mitigated which we'll talk about at the end of this post) can create and register a new app that will basically function as a redirector of sorts that asks a targeted user to grant certain permissions as defined in the app, then ask for the users consent to those permissions and then finally takes the OAuth token generated by this process and forwards it along somewhere else. That somewhere else in this case is an attacker controlled host.
In this post I am operating under a compromised user account that has no special access or rights in Azure or AzureAD. This user, Alice, has no subscriptions or Azure roles assigned. This is also why mitigating this attack is quite important IMO since it requires practically nothing other than the compromised user exisiting in AzureAD and the ability to register new applications.
Assume you've grabbed a users creds and used them to gain access to the Azure portal.
We're going to register a new application in AAD, set the redirect URL to our host (DO, AWS, Azure etc.) which is going to run an OAuth 'listener'. Once the user consents to the application, our listener will grab their OAuth token, relay it to the Microsoft '/token' endpoint which will give us back the Access, ID and Refresh tokens for the target user. The Access token being the one we're most interested in.
Once that has been accomplished, and I'm intentionally not going too much deeper here to leave more exploration up to the reader, we will take our acquired token and use the Microsoft Graph API to confirm everything works by pulling some basic information about the user we targeted.
Starting in Azure portal, log in as the assumed compromised user. Navigate to Azure AD > App Registrations and click the + New registration button.
On the Register an application page, here is where you will start defining the application. For the Name field, pick something non-suspect as this is the name everyone else will see under registered applications.
Another decision to make is Supported account types section. If you have a reason to want to leverage this compromised user's Azure tenant to attack another (Multitenant) or even against any free/personal Microsoft account, you can do that too (Multitenant + personal Microsoft account). I'll choose the latter for this example.
Next, I'm making the decision to set a client secret. The reason, I think, is depending on AzureAD and the application registration configuration, some apps are considered public or private when it comes to managing how the OAuth token gets passed around. I ran into an issue where setting this secret fixed things up and to be honest as of writing this, I'm not 100% sure why I had to but I'll explore it more.
Click + New client secret and give it a name. Once created it will display the secret. Write this down somewhere for later.
Next go into the apps API permissions section. Here is where we are going to select (another exercise for the reader) what we wish our app (and ultimately the token we receive) to be able to access from the targeted user.
Click + Add a permission, select Microsoft Graph (or anything else you want to try out) and pick the APIs of interest. Avoid selecting ones where administrative consent is required. Here's what I selected:
In my attack scenario, I'm targeting users who by falling for the phish will expose access to their email. With this API permissions set, as the attacker we can read their contacts, emails and even send emails.
We are done configuring the application. Before moving on, make sure to note down your applications client ID which can be found in the apps Overview section.
When we construct the URL to deliver in our phishing email you will need the client ID, redirect URL and the API permissions you selected earlier.
For this step, I'm using a great utility which you can find on my GitHub here.
It is a fork so once again, all credit due to the author.
This tool is an OAuth server script written in Go. I leave it to you to setup your environment correctly.
On Digital Ocean to keep things simple, I spun up a Ubuntu 18 VPS and hosted this script at https://ograb.invokethreat.cloud during this example.
The script is commented well for what you need to change. I made a couple slight modifications that I want to point out:
The target variable I have set to google.ca and is kinda silly. Realistically, this will be the final redirect location after you as the attacker have achieved the token grab. In a real engagement, you would likely want to redirect the user to something such as O365 or Outlook login pages. Or you could even take this further and use that redirect to bring the target user to a second credential grab such as a clone of Outlook login page. Again, let your creativity fly here ;)
The other modification I made that does not come part of the script is the postData variable. If you look closely, I've added the client_secret string including the secret.
We are ready to phish our target user. How you do that...you guessed it! I leave that up to you. Here is an example of the link you would ultimately want the target user to click on:
When the user clicks the link, if they are not already authenticated they will be brought to the MS default login page. Once they authenticate, they will be brought to your malicious app and asked to consent. Notice how in the beginning of the URL, it is originating from a Microsoft domain and very much helps with the lure.
Also notice the consent being asked of the user. The consent will list out the APIs you select in your app registration. Because of this, another consideration should be made here to minimize alerting the target user to something suspicious. Use only the APIs you need to achieve your objective.
Now once the user has gone through the authentication and consent process, your OAuth server should have a captured their token.
Finally, to confirm you've captured everything correctly, a simple check to the MS Graph API to return account information about this user will help:
and output upon success should look something like this:
A lot of what you can/cannot do at your organization will be hard for me to dictate so I thought I'll just list out some of the things I've observed playing around with this and also some resources that I've come across.
From my understanding if you do not have an AzureAD P1/P2 license (will confirm this), your only option is to enable/disable registrations for all users. While you're at it very little users would actually need Azure portal access so get rid of that too :)
It might not be much but its a start. The users who are phished with something like this need to consent to the malicious app and AzureAD Audit Log records this action:
sry test2 was the app name while I was working on this
I was crawling through some Azure Sentinel stuff on GitHub and there's a few queries I noticed that can help with detection of OAuth/App Consent behaviour:
Again these are forks so all credit due to the authors.
I'm sure there's more that can be used to enhance detection capability as well as mitigations without having to disable something like app registration for every AAD user. This is just some stuff I found for the time being and will update this post with more info as it comes in :)
This attack, which I only leveraged for the very first time on a recent engagement, is not all that new. It's an OAuth token grab that in this scenario is focused on Azure and the AAD app registration feature. There's not exploit. There's no real hack going on. These are features.
Which IMO, makes it pretty nasty. You may also notice I didn't give away anything devastating here. You can phish a single user (obvy you could do more) and get back an OAuth token which you can create an access token out of to do some stuff with.
I have a feeling that the possibilities here could run pretty deep.
Hope this post was interesting and of some use.