diff --git a/src/pentesting-cloud/azure-security/az-services/vms/README.md b/src/pentesting-cloud/azure-security/az-services/vms/README.md index ff2aadbe4..b269d5d9b 100644 --- a/src/pentesting-cloud/azure-security/az-services/vms/README.md +++ b/src/pentesting-cloud/azure-security/az-services/vms/README.md @@ -889,6 +889,8 @@ However, not every process will necessarily get the same practical result: Therefore, if a request works from Run Command but fails from SSH, the usual explanation is a difference in OS user, environment, routing, proxy, firewall, or namespace, not a general Azure rule that only agent execution contexts can reach `168.63.129.16`. +In lab testing this distinction was visible: Linux/Windows VM Agent execution through Run Command or Custom Script extensions could reach GoalState on `168.63.129.16`, while a normal SSH session on another Linux VM could still reach IMDS but timed out when querying GoalState. Treat WireServer/GoalState as useful but environment-dependent; do not rely on it as the canonical way to enumerate managed identities. + ### Managed Identity Access From Inside the VM The reliable way to use a VM's managed identities is the **IMDS managed identity endpoint** at `169.254.169.254`, not the WireServer `ExtensionsConfig` XML. Scripts that only search `ExtensionsConfig` for `UserAssignedIdentity` nodes are not reliable because: @@ -897,7 +899,19 @@ The reliable way to use a VM's managed identities is the **IMDS managed identity - They miss **system-assigned managed identities**. - They only find user-assigned identities if the current GoalState/extension data happens to expose the expected XML shape. -Microsoft's documented security model is that **all code running on the VM can request tokens for the managed identities available on that VM**. If several user-assigned identities exist, request a specific one with `client_id`, `object_id`, or `msi_res_id`. +Microsoft's documented security model is that **all code running on the VM can request tokens for the managed identities available on that VM**. This was confirmed from: + +- Linux SSH as a regular VM user. +- Linux Run Command through the VM Agent. +- Linux Custom Script extension through the VM Agent. +- Windows Custom Script extension as `NT AUTHORITY\SYSTEM`. + +In all of those contexts, IMDS could mint tokens for Management, Microsoft Graph/Entra ID, Key Vault, and Storage when the requested identity was available to the VM. + +There are two different problems that are easy to mix up: + +- **Getting a token for a known identity:** If the identity is assigned to the VM, IMDS can issue tokens for different audiences such as `https://management.azure.com/`, `https://graph.microsoft.com/`, `https://vault.azure.net`, and `https://storage.azure.com/`. If several user-assigned identities exist, request a specific one with `client_id`, `object_id`, or `msi_res_id`. +- **Discovering every attached identity from inside the VM:** IMDS does not provide a simple "list all identities" endpoint. A practical method is to get a default Management token, read the VM resource through ARM, and inspect the `identity` property. This only works if that managed identity has permissions such as `Microsoft.Compute/virtualMachines/read` on the VM. If ARM returns `403`, the token can still be valid and useful, but it cannot enumerate the VM's full identity list. The following examples first request a token. Then they try to read the VM resource from Azure Resource Manager and print its `identity` property. The second step only works if the managed identity has permissions such as `Microsoft.Compute/virtualMachines/read` on the VM.