Andy Robbins Profile picture
Product Architect of BloodHound Enterprise. Co-creator of BloodHound. Please donate to MDA: https://t.co/wtLm1eFzRc. He/him. @SpecterOps. Mstdn: @wald0@infosec.exchange

Aug 6, 2022, 22 tweets

From initial access to Global Admin with #BloodHound and BARK.

In this thread let's walk, step by step, through an example attack path based on real configurations we've seen in real environments:

There are MANY ways to achieve initial access into AzureAD. For this example we will go with something simple: we were able to phish a user and get their username and clear text password.

This user has no MFA/CAP restrictions - we'll discuss how to deal with these later.

We now want to collect data with AzureHound. We'll clone the repo, inspect the source code, then build the binary ourselves:

$ git clone github.com/BloodHoundAD/A…
$ cd AzureHound
$ go build .

Now we will run this command:

$ ./azurehound -u "phisheduser@specterdev.onmicrosoft.com" -p "Password1" list -o initial-scan.json --tenant "specterdev.onmicrosoft.com"

This instructs AzureHound to attempt to list ALL data and output the results to a file called initial-scan.json.

Collection finished after 45 seconds, BUT you might have noticed the following warning:

"unable to process azure management groups; either the organization has no management groups or azurehound does not have the reader role on the root management group."

Our user can read all the relevant info at the AzureAD level (most users *can* by default in all tenants), but our user CANNOT read anything in AzureRM. That's ok, we can keep going.

Now we will drag and drop initial-scan.json into the BloodHound GUI:

Ok! Now we're ready to find an attack path to Global Admin! We'll find our user, enable path finding mode, select Global Admin to find a path, aaaaaaaaaaaand...

"No data returned from query" - damn, this means we don't have an attack path to Global Admin. But not all hope is lost, remember that there is an entire world of enumeration we haven't done in AzureRM.

Let's see whether our user DOES have anywhere to go by clicking the user and inspecting the "Outbound Object Control" section.

Indeed, we find this user can add members to several non role eligible security groups, including one called "Subscription Admins":

When we click on "Subscription Admins", we see that that group has no privileges -- as far as we can tell so far! Let's take a chance and use BARK to add ourselves to this group and re-run AzureHound, maybe we'll be able to read the subscriptions.

To perform this abuse, we need to use two functions. First we will use BARK's Get-MSGraphTokenWithUsernamePassword function to get an MS Graph-scoped JWT for our phished user:

We will now feed this token, the ID for our user, and the ID for the target group to BARK's Add-AZMemberToGroup function.

Then we will verify the user was added to the group with BARK's Get-AZGroupMembers function:

Now that our user belongs to this group, does it have any more privileges than it previously had? Let's re-run AzureHound again and see!

Collect -> Import -> Explore outbound object control for our user:

Ok! It turns out the "Subscription Admins" group has "User Access Admin" rights on pretty much everything in AzureRM. Now that our user belongs to this group, our user now also has that right.

That's great, but do we have a path to Global Admin now? Let's try path finding in the BloodHound GUI again from our phished user to the Global Admin role and see:

Here's our attack path to Global Admin:

"But no admin in their mind would grant Global Admin to a VM's managed identity service principal."

We're already a member of the "Subscription Admins" group, so our next step is to grant ourselves the ability to execute commands on BHESpecterDevWin10-01.

To do this, we need to use a number of functions from BARK:

Get-ARMTokenWithUsernamePassword to do... exactly what it says.

Get-AzureRMRoleDefinitions to get the names and IDs for Azure roles

New-AzureRMRoleAssignment to grant ourselves the "Owner" role over the VM.

and

Get-AzureRMRoleAssignment to verify the new Owner assignment:

Bing bang boom. We now have "Owner" role against the VM. The next step in our attack path is to abuse our Ownership of the VM to take over the VM's managed identity.

To do this, we're going to use a trick I learned by reading this post by @kfosaaen: netspi.com/blog/technical…

We are going to remotely execute a command on the VM, and that command is going to give us an MS Graph-scoped JWT for the managed identity service principal.

To do this we will use BARK's Invoke-AzureRMVMRunCommand function:

And... we're done! That heavily censored token will let us perform any action in AzureAD as a Global Admin now!

Defenders: The "Prevention" section of this blog post offers guidance to find/fix/prevent these attack paths in your own environments: medium.com/p/82667d17187a

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling