Defense and Detection for Attacks Within Azure

Ryan Hausknecht
Posts By SpecterOps Team Members
8 min readFeb 4, 2020

Abstract

In my article “Attacking Azure, AzureAD, and Introducing PowerZure”, I provided several tactics, techniques, and procedures (TTPs) on attacking Azure & AzureAD, as well as released PowerZure to automate some of it. I firmly believe that when a new tactic or tool is written, that defensive guidelines should follow to help blue teams secure themselves from those tactics or tools. Unfortunately, Azure’s logging capabilities for operations that occur within Azure, leave much to be desired.

This article’s purpose is to give an overview into the native Activity Log service functionality within Azure and provide insight into how to detect many of the TTPs listed in my previous article, as well as suggestions on how to acquire more detail out of the Activity Log service than just what appears on the ‘summary’ tab.

Overview

Whenever an operation is completed within Azure, an event is generated and kept within the Activity Log service. Within the Activity Log, the user can see all operations and apply basic filters (Time-span, severity, etc.). Operations (events) in the log are broken out based on the status of the operation, i.e. when an event is started, when it updates, when it finishes, etc. In order to see the other “sub-events” within that operation, the user must click on the event and the other status events will then populate. This is important because the details surrounding the operation depend on the status.

Figure 1: Clicking on the first event shows a sub-event.

For example, when a user is assigned to a role (e.g. contributor), an operation is started which creates an event, but essential details are missing.

Figure 2: Initial event created in Azure for a role assignment.

Once the operation finishes, another “sub-event” is created that then discloses the necessary details.

Figure 3: More details revealed when clicking on the sub-event

In this example, the ‘Message’ field is what contains the username of the user that was added to the role, in comparison to the original event which did not contain this info.

Alerting

Alerts can be configured right from Activity Log. Whenever an operation occurs, Azure gives the option to create an alert for that operation once you click into the event.

Figure 4: Option to create a new alert based on an event

When creating a rule, there’s an option to change the condition. When the default condition is left, it is a very general condition, as shown in Figure 5.

Figure 5: The condition is set to any informational level event that succeeds. This would generate several benign alerts.

The condition can be changed by clicking on the trash can icon and clicking ‘Add’ under condition.

Figure 6: Alerting conditions for Runbooks.

From here, the alert action can be set to several options.

Figure 7: Alerting options

It’s All In The Details, or is it?

Getting a general event is great for alerting, however it’s key for an analyst to have details pertaining to that event such as who started the operation, what was the target object of the operation, etc. Unfortunately, there’s several operations that report minimal details.

Command Execution

When a command is run on a virtual machine, an event is created, however there is no record kept of what command was ran.

Figure 8: All that’s returned in the event from running a command on a VM

The summary tab shows when and who executed a command, but in order to see the name of the VM where execution occurred, the user must go to the JSON tab and view the ‘id’ property to see the scope of the event.

Figure 9: Name of the VM in the scope path

Whenever a command is issued to a Windows Virtual Machine, Azure stores the inputted command as a PowerShell script located on the endpoint within

C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\1.1.3\Downloads

This allows an analyst to potentially see what commands were ran on a virtual machine, provided the attacker did not delete the scripts. Of course, it’s always recommended to use additional defensive tools as well as enable script-block logging on those endpoints within Group Policy.

Key Vaults

Key Vaults are very sensitive within Azure due to their purpose. They can house certificates, passwords, and keys, so they should also be heavily monitored for access. Accessing a vault does not generate an event, nor does revealing a key. This is the intended purpose of the resource in conjunction with role-based access control; as far as Azure is concerned, it is not event-worthy if a user accesses a resource they have permission to access. Key Vaults are restricted to their owners and it’s up to the owner to edit the access policy to allow other users to access that vault. However, as a Global Contributor, a user is able to edit the permissions of any vault and give themselves permission to access it. This does generate an event, ‘Update Key Vault’.

Figure 6: Log of when a Key Vault is updated

The event summary shows who updated the vault’s permissions, however the name of the vault is in the JSON output instead of the summary.

Figure 10: The scope in the JSON tab reveals the vault name.

The major problem with this, is that it does not show who was added to the access policy. Therefore, the only way to determine who was added, is to go into each vault and determine if all users on the access policy are meant to be there.

Runbooks

In PowerZure, a function that takes advantages of Runbooks is Create-Backdoor. This works by creating a Runbook that will provide a new account and assign it to the Contributor role when executed. Instead of automatically executing, it generates a Webhook URI that can be passed into Execute-Backdoor which will run the Runbook on demand. This requires the Administrative Role because only Administrators can create users in Azure AD. Luckily, creating a Runbook generates several events so detection for this is straight forward. The first key event, is the creation of a Runbook, followed by the creation of a Webhook and then generation of a URI for that Webhook.

Figure 11: Sequence of operations for ‘Create-Backdoor’ in PowerZure

The problem with this, is that the ‘event initiated by’ field is incorrect. The field is always populated with the tenant Administrator, instead of the person who actually created the Runbook, if the Runbook was created from the command line. To ensure my sanity, I tested this with three different accounts, and every time the event was initiated by my administrative account, even though it wasn’t logged in anywhere.

Figure 12: Event Initiated by field shows the tenant admin instead of the actual user for Webhook and Runbook creations when done through CLI.

As for 1/24/2020, this bug has been submitted to Microsoft and I am currently awaiting their response.

Update: As of 2/7/2020, this bug is now fixed.

Group assignments

Even if on-premise Activity Directory (AD) is synchronized to AzureAD, it’s not possible to add a user to an on-premise AD group. However, adding a user to a Azure group in Azure does not generate an event under the Activity Log. AzureAD has its own event viewer, called Audit Logs. This does give the necessary details of an operation, however alerts cannot be configured for these events in AzureAD unless the Log Analytics service is being used and AzureAD is configured to send logs to Log Analytics. The alert would then have to be generated from Log Analytics instead of AzureAD’s Audit Logs.

Virtual Machine Disks

If an attacker compromises an account that is a Global Contributor, they may generate a link to download a VM disk. This can be detected with the operation name ‘Get Disk SAS URI’. The link is not shown in the summary or JSON tab, nor is if the disk was actually downloaded or not. Only a generic event is created with no details other than the disk name.

Defensive Approach

With Azure utilizing role-based access control (RBAC), it should be treated similarly to on-premise AD group membership, meaning it should follow the method of least-privileged access. Assigning the Global Contributor role to a user gives that user a great amount of access and execution capabilities. It is suggested to review which roles are actually necessary for operation within Azure. Azure contains many built-in roles outside of the ‘Global’ roles, which can be viewed here. In addition, custom role creation is a possibility that may better suit a businesses need.

Following the methodology of least-privileged access, Azure does offer the Privileged Identity Management (PIM) service, for a cost, but is heavily recommended.

Organizations want to minimize the number of people who have access to secure information or resources, because that reduces the chance of a malicious actor getting that access, or an authorized user inadvertently impacting a sensitive resource. However, users still need to carry out privileged operations in Azure AD, Azure, Office 365, or SaaS apps. Organizations can give users just-in-time (JIT) privileged access to Azure resources and Azure AD. There is a need for oversight for what those users are doing with their administrator privileges. — Microsoft

PIM is similar to a Privileged Access Management (PAM) solution, where it gives administrative or privileged access only when needed. PIM can used on a per-resource basis. In the PIM panel, there’s three categories: Eligible, Active, and Expired. Eligible means the user is able request access to that role on that resource. Active means the user actively has that role and does not need approval. Expired means that user is no longer allowed to request access for that role and no longer has it.

Figure 13: ‘Contrib’ user has allowed to request access to the contributor role for a resource

For example, if a user was added to PIM for a virtual machine resource and made eligible to request access to the Contributor role, then that user would only have to request to activate their privileges for that virtual machine, while not having to do that for all others. Since roles are hierarchical, if PIM is placed on the subscription, then it would affect all resources within that subscription. With PIM, it doesn’t enable the requirement for the request to be approved by default.

Figure 14: Default activation settings for a role

This means that by default, a user could just activate their role whenever they wanted.

The logging for PIM, however, is properly detailed within Activity Log.

Figure 15: The event summary when a user activates their PIM controlled role. ‘Reader’ activated the role ‘Contributor’ for the Subscription ‘Azure Test’

Final Thoughts

Azure offers several additional services that give more insight into the operations within resources, such as Log Analytics and Azure Sentinel, however the native logging for operations within Azure itself is not perfect. Hopefully Microsoft will implement more details into Activity Log so defenders can have the full picture of an event instead of requiring additional effort.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

What are your thoughts?