mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-06-12 11:01:38 -07:00
Add WireServer & GoalState
This commit is contained in:
@@ -837,6 +837,317 @@ Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure WireServer & GoalState
|
||||
|
||||
Azure VMs expose **internal platform endpoints** that are used for configuration, metadata retrieval and identity management. Understanding the difference between them is critical for **enumeration, privilege escalation and post-exploitation**.
|
||||
|
||||
---
|
||||
|
||||
### Wire Server (Azure Fabric Endpoint)
|
||||
|
||||
The **Azure WireServer** is an internal Azure IP (`168.63.129.16`) used by the platform to communicate with the VM.
|
||||
|
||||
It is responsible for:
|
||||
|
||||
- Communication with the **VM Agent**
|
||||
- Delivering:
|
||||
- **GoalState**
|
||||
- **ExtensionsConfig**
|
||||
- Internal VM configuration (including identities)
|
||||
- DHCP & DNS services
|
||||
- Health monitoring
|
||||
|
||||
---
|
||||
|
||||
### GoalState & ExtensionsConfig
|
||||
|
||||
The **GoalState** represents the **desired configuration of the VM** as defined by Azure. It may include:
|
||||
|
||||
- Extensions configuration
|
||||
- Managed identities
|
||||
- Provisioning state
|
||||
- Agent instructions
|
||||
|
||||
The **ExtensionsConfig** contains detailed configuration of VM extensions and may include:
|
||||
|
||||
- **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/?comp=goalstate
|
||||
```
|
||||
|
||||
### Access Restrictions
|
||||
|
||||
Although the endpoint is reachable from the VM network, **it is not equally accessible from all contexts**.
|
||||
|
||||
**Accessible from**:
|
||||
|
||||
- Azure **VM Agent**
|
||||
- Azure **Run Command**
|
||||
- **VM Extensions**
|
||||
|
||||
**Not reliably accessible from**:
|
||||
|
||||
- Interactive SSH sessions (e.g., `azureuser`)
|
||||
- Unprivileged processes inside the VM
|
||||
|
||||
This is because:
|
||||
|
||||
- The WireServer is designed for **platform-agent communication**
|
||||
- Requests may require **specific headers, timing, or context**
|
||||
- Some responses are only available to the **VM Agent execution environment**
|
||||
|
||||
---
|
||||
|
||||
### Run Command vs SSH Context
|
||||
|
||||
Azure provides multiple ways to execute commands inside a VM, but **they do not run in the same context**.
|
||||
|
||||
---
|
||||
|
||||
#### Run Command
|
||||
|
||||
Run Command is an Azure feature that executes scripts via the **VM Agent**.
|
||||
|
||||
- Uses: `Microsoft.Compute/virtualMachines/runCommand/action`
|
||||
- Runs with **agent-level privileges**
|
||||
- Has access to:
|
||||
- WireServer
|
||||
- GoalState
|
||||
- ExtensionsConfig
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
az vm run-command invoke \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--command-id RunShellScript \
|
||||
--scripts @script.sh
|
||||
```
|
||||
|
||||
#### SSH Session
|
||||
|
||||
When connecting via SSH:
|
||||
|
||||
- Runs as a **regular OS user**
|
||||
- Uses standard network stack
|
||||
- Does **NOT have agent-level access**
|
||||
|
||||
As a result:
|
||||
|
||||
- Requests to `168.63.129.16` may fail or return incomplete data
|
||||
- GoalState may not be accessible
|
||||
|
||||
**Script Examples:**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ws="http://168.63.129.16"
|
||||
|
||||
echo "[*] Getting Goal State..."
|
||||
|
||||
goal_urls=(
|
||||
"$ws/?comp=goalstate"
|
||||
"$ws/machine?comp=goalstate"
|
||||
"$ws/machine/?comp=goalstate"
|
||||
)
|
||||
|
||||
goal_xml=""
|
||||
for url in "${goal_urls[@]}"; do
|
||||
if goal_xml="$(curl -fsS -H "x-ms-version: 2012-11-30" "$url" 2>/dev/null)"; then
|
||||
echo "[+] GoalState OK via $url"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$goal_xml" ]]; then
|
||||
echo "[-] No GoalState endpoint responded"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ext_url="$(
|
||||
GOAL_XML="$goal_xml" python3 - <<'PY'
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
xml = os.environ["GOAL_XML"].strip()
|
||||
root = ET.fromstring(xml)
|
||||
|
||||
def lname(tag):
|
||||
return tag.rsplit("}", 1)[-1]
|
||||
|
||||
for el in root.iter():
|
||||
if lname(el.tag) == "ExtensionsConfig" and (el.text or "").strip():
|
||||
print(el.text.strip())
|
||||
break
|
||||
PY
|
||||
)"
|
||||
|
||||
if [[ -z "$ext_url" ]]; then
|
||||
echo "[-] No ExtensionsConfig URL found in GoalState"
|
||||
echo "[*] Identity-like nodes seen in GoalState:"
|
||||
GOAL_XML="$goal_xml" python3 - <<'PY'
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
xml = os.environ["GOAL_XML"].strip()
|
||||
root = ET.fromstring(xml)
|
||||
|
||||
def lname(tag):
|
||||
return tag.rsplit("}", 1)[-1]
|
||||
|
||||
found = False
|
||||
for el in root.iter():
|
||||
name = lname(el.tag)
|
||||
if "Identity" in name:
|
||||
found = True
|
||||
text = (el.text or "").strip()
|
||||
print(f"<{name}>{text}</{name}>")
|
||||
|
||||
if not found:
|
||||
print(" (none)")
|
||||
PY
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "[*] Getting ExtensionsConfig..."
|
||||
ext_xml="$(curl -fsS -H "x-ms-version: 2012-11-30" "$ext_url")"
|
||||
|
||||
EXT_XML="$ext_xml" python3 - <<'PY'
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
xml = os.environ["EXT_XML"].strip()
|
||||
root = ET.fromstring(xml)
|
||||
|
||||
def lname(tag):
|
||||
return tag.rsplit("}", 1)[-1]
|
||||
|
||||
ids = [el for el in root.iter() if lname(el.tag) == "UserAssignedIdentity"]
|
||||
|
||||
if not ids:
|
||||
print("[-] No UserAssignedIdentity nodes found")
|
||||
print("[*] Identity-like nodes present in ExtensionsConfig:")
|
||||
shown = False
|
||||
for el in root.iter():
|
||||
name = lname(el.tag)
|
||||
if "Identity" in name:
|
||||
shown = True
|
||||
text = (el.text or "").strip()
|
||||
attrs = " ".join(f'{k}="{v}"' for k, v in el.attrib.items())
|
||||
if attrs:
|
||||
print(f" <{name} {attrs}>{text}</{name}>")
|
||||
else:
|
||||
print(f" <{name}>{text}</{name}>")
|
||||
if not shown:
|
||||
print(" (none)")
|
||||
raise SystemExit(0)
|
||||
|
||||
for idnode in ids:
|
||||
client_id = ""
|
||||
object_id = ""
|
||||
resource_id = ""
|
||||
|
||||
for child in idnode.iter():
|
||||
name = lname(child.tag)
|
||||
text = (child.text or "").strip()
|
||||
if name == "IdentityClientId":
|
||||
client_id = text
|
||||
elif name == "IdentityObjectId":
|
||||
object_id = text
|
||||
elif name == "IdentityResourceId":
|
||||
resource_id = text
|
||||
|
||||
print()
|
||||
print("[+] Managed Identity:")
|
||||
print(f" ClientId : {client_id}")
|
||||
print(f" ObjectId : {object_id}")
|
||||
print(f" ResourceId : {resource_id}")
|
||||
PY
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
```bash
|
||||
$ws = "http://168.63.129.16"
|
||||
$h = @{
|
||||
"x-ms-version" = "2012-11-30"
|
||||
}
|
||||
|
||||
Write-Host "[*] Getting Goal State..." -ForegroundColor Cyan
|
||||
|
||||
$goalUrls = @(
|
||||
"$ws/?comp=goalstate",
|
||||
"$ws/machine?comp=goalstate",
|
||||
"$ws/machine/?comp=goalstate"
|
||||
)
|
||||
|
||||
$gs = $null
|
||||
|
||||
foreach ($url in $goalUrls) {
|
||||
try {
|
||||
$gs = Invoke-WebRequest -Uri $url -Headers $h -UseBasicParsing -ErrorAction Stop
|
||||
Write-Host "[+] GoalState OK via $url" -ForegroundColor Green
|
||||
break
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (-not $gs) {
|
||||
Write-Host "[-] No GoalState endpoint responded" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
[xml]$xml = $gs.Content
|
||||
$cfg = $xml.GoalState.Container.RoleInstanceList.RoleInstance.Configuration
|
||||
|
||||
$extUrl = $cfg.ExtensionsConfig
|
||||
|
||||
Write-Host "[*] Getting ExtensionsConfig..." -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
$ext = Invoke-WebRequest -Uri $extUrl -Headers $h -UseBasicParsing -ErrorAction Stop
|
||||
[xml]$extXml = $ext.Content
|
||||
} catch {
|
||||
Write-Host "[-] Error getting ExtensionsConfig" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
# Extract Managed Identity info
|
||||
$ids = $extXml.SelectNodes("//UserAssignedIdentity")
|
||||
|
||||
if (!$ids) {
|
||||
Write-Host "[-] No User Assigned Identities found" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($id in $ids) {
|
||||
$clientId = $id.IdentityClientId
|
||||
$objectId = $id.IdentityObjectId
|
||||
$resourceId = $id.IdentityResourceId
|
||||
|
||||
Write-Host "`n[+] Managed Identity:" -ForegroundColor Green
|
||||
Write-Host " ClientId : $clientId"
|
||||
Write-Host " ObjectId : $objectId"
|
||||
Write-Host " ResourceId : $resourceId"
|
||||
}
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
@@ -866,6 +1177,9 @@ Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt
|
||||
- [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/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/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)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user