Azure WireServer HTTP Request from Unexpected User Agent


Description

Identifies HTTP requests to Azure WireServer (168.63.129.16) for GoalState, certificates, versions, or HostGAPlugin vmSettings that do not use a known guest-agent user agent. These requests retrieve transport certificates and extension protectedSettings, including embedded SAS URLs. Azure Linux Agent, Windows guest agent, and related platform UAs are excluded. Requests with no user agent are also excluded; that pattern is common for the Windows guest agent.

Query · eql

network where event.module == "network_traffic" and
destination.ip == "168.63.129.16" and
user_agent.original != null and
not user_agent.original : (
  "WALinuxAgent*",
  "VMAgent*",
  "Python-urllib*",
  "cpprestsdk*",
  "ACMS/*"
) and
(
  url.query : ("*comp=versions*", "*comp=goalstate*", "*comp=certificates*") or
  (destination.port == 32526 and url.path : ("/versions", "/vmSettings"))
)

Implementation guide

Deploy the Network Packet Capture integration via Fleet on Azure virtual machines. Default HTTP port lists do not include HostGAPlugin.

Required integration settings:

  • Enable Capture HTTP Traffic.
  • Set HTTP ports to include 80 (WireServer GoalState, versions, certificates) and 32526 (HostGAPlugin /versions, /vmSettings). Without 32526, HostGAPlugin requests are invisible.
  • Enable Monitor Processes so HTTP events include process.* when available.
  • Optional: Send all headers to retain x-ms-version and x-ms-guest-agent-public-x509-cert for investigation. The rule matches URI, port, and user agent, not the certificate PEM.
  • Do not enable request or response body capture for this rule. /vmSettings bodies are large and often dropped; other WireServer XML is not required for the match.

Known false positives

  • Custom health checks that call HostGAPlugin /versions or /vmSettings with curl. Exclude the specific user agent or host group after validating the script.

Analyst notes

Investigating Azure WireServer HTTP Request from Unexpected User Agent

Network Packet Capture with HTTP decoding on ports 80 and 32526 shows the URI that Elastic Defend network events lack. The match is the WireServer path or query, not a scripting-tool user-agent allowlist.

  • url.query contains comp=versions (discovery)
  • url.query contains comp=goalstate (incarnation, container, extension list, statusUploadBlob pointer)
  • url.query contains comp=certificates (often with request header x-ms-guest-agent-public-x509-cert)
  • destination.port == 32526 and url.path in /versions, /vmSettings

Excluded user agents from lab guest-agent traffic: WALinuxAgent/*, VMAgent/*, Python-urllib/*, cpprestsdk/*, ACMS/*, and a missing user agent (Windows guest agent). Curl and Windows PowerShell are not excluded and will fire.

/vmSettings response bodies are often dropped when they exceed keyword ignore_above. The URI, port, and user agent are sufficient. Do not enable body capture to chase this rule.

Possible investigation steps

  • Confirm url.path, url.query, destination.port, and user_agent.original.
  • GoalState (comp=goalstate) is reconnaissance; comp=certificates means the client presented a transport certificate. Look on the host for openssl req ... LinuxTransport or a stolen .crt/.key.
  • Correlate with endpoint network events from the same host.name to 168.63.129.16 and process start events for openssl cms decrypt.
  • Search StorageRead platform logs for anonymous or SAS GetBlob against the same storage account after the scrape.

False positive analysis

  • Administrative curl or other non-agent clients against WireServer during incident response. Exclude the specific user agent or host after the change window.
  • A new Microsoft guest-agent build with an unfamiliar user agent will fire until that UA is excluded.
  • Omitting the user agent looks like the Windows guest agent and is not matched. Do not treat a missing UA as suspicious on its own.

Response and remediation

  • Isolate the VM, rotate secrets recovered from vmSettings, and review extension protectedSettings.
  • Enable Metadata Security Protocol in audit or enforce mode to restrict WireServer callers.
Raw source Azure WireServer HTTP Request from Unexpected User Agent · Elastic TOML
Esc
Published by elastic/detection-rules ↗, licensed under Elastic License 2.0 ↗. Reproduced here unmodified.
[metadata]
creation_date = "2026/08/17"
integration = ["network_traffic"]
maturity = "production"
updated_date = "2026/09/18"

[rule]
author = ["Elastic"]
description = """
Identifies HTTP requests to Azure WireServer (168.63.129.16) for GoalState, certificates, versions, or HostGAPlugin
vmSettings that do not use a known guest-agent user agent. These requests retrieve transport certificates and extension
protectedSettings, including embedded SAS URLs. Azure Linux Agent, Windows guest agent, and related platform UAs are
excluded. Requests with no user agent are also excluded; that pattern is common for the Windows guest agent.
"""
false_positives = [
    """
    Custom health checks that call HostGAPlugin /versions or /vmSettings with curl. Exclude the specific user agent or
    host group after validating the script.
    """,
]
from = "now-9m"
index = ["logs-network_traffic.http*"]
language = "eql"
license = "Elastic License v2"
name = "Azure WireServer HTTP Request from Unexpected User Agent"
note = """## Triage and analysis

### Investigating Azure WireServer HTTP Request from Unexpected User Agent

Network Packet Capture with HTTP decoding on ports 80 and 32526 shows the URI that Elastic Defend network events
lack. The match is the WireServer path or query, not a scripting-tool user-agent allowlist.

- `url.query` contains `comp=versions` (discovery)
- `url.query` contains `comp=goalstate` (incarnation, container, extension list, statusUploadBlob pointer)
- `url.query` contains `comp=certificates` (often with request header `x-ms-guest-agent-public-x509-cert`)
- `destination.port == 32526` and `url.path` in `/versions`, `/vmSettings`

Excluded user agents from lab guest-agent traffic: `WALinuxAgent/*`, `VMAgent/*`, `Python-urllib/*`,
`cpprestsdk/*`, `ACMS/*`, and a missing user agent (Windows guest agent). Curl and Windows PowerShell are not
excluded and will fire.

`/vmSettings` response bodies are often dropped when they exceed keyword `ignore_above`. The URI, port, and user
agent are sufficient. Do not enable body capture to chase this rule.

### Possible investigation steps

- Confirm `url.path`, `url.query`, `destination.port`, and `user_agent.original`.
- GoalState (`comp=goalstate`) is reconnaissance; `comp=certificates` means the client presented a transport
  certificate. Look on the host for `openssl req ... LinuxTransport` or a stolen `.crt`/`.key`.
- Correlate with endpoint network events from the same `host.name` to `168.63.129.16` and process start events for
  openssl cms decrypt.
- Search StorageRead platform logs for anonymous or SAS GetBlob against the same storage account after the scrape.

### False positive analysis

- Administrative curl or other non-agent clients against WireServer during incident response. Exclude the specific
  user agent or host after the change window.
- A new Microsoft guest-agent build with an unfamiliar user agent will fire until that UA is excluded.
- Omitting the user agent looks like the Windows guest agent and is not matched. Do not treat a missing UA as
  suspicious on its own.

### Response and remediation

- Isolate the VM, rotate secrets recovered from vmSettings, and review extension protectedSettings.
- Enable Metadata Security Protocol in audit or enforce mode to restrict WireServer callers.
"""
references = [
    "https://cybercx.com.au/blog/azure-ssrf-metadata/",
    "https://www.netspi.com/blog/technical-blog/cloud-pentesting/decrypting-vm-extension-settings-with-azure-wireserver/",
    "https://cloud.google.com/blog/topics/threat-intelligence/escalating-privileges-azure-kubernetes-services",
    "https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16",
]
risk_score = 47
rule_id = "359b5925-a625-4803-90d2-19e44a37d98e"
setup = """## Setup

Deploy the [Network Packet Capture](https://www.elastic.co/docs/reference/integrations/network_traffic) integration
via Fleet on Azure virtual machines. Default HTTP port lists do not include HostGAPlugin.

Required integration settings:

- Enable **Capture HTTP Traffic**.
- Set HTTP ports to include **80** (WireServer GoalState, versions, certificates) and **32526** (HostGAPlugin
  `/versions`, `/vmSettings`). Without 32526, HostGAPlugin requests are invisible.
- Enable **Monitor Processes** so HTTP events include `process.*` when available.
- Optional: **Send all headers** to retain `x-ms-version` and `x-ms-guest-agent-public-x509-cert` for investigation.
  The rule matches URI, port, and user agent, not the certificate PEM.
- Do not enable request or response body capture for this rule. `/vmSettings` bodies are large and often dropped;
  other WireServer XML is not required for the match.
"""
severity = "medium"
tags = [
    "Domain: Cloud",
    "Domain: Network",
    "OS: Linux",
    "OS: Windows",
    "Platform: Azure",
    "Use Case: Threat Detection",
    "Tactic: Credential Access",
    "Tactic: Discovery",
    "Data Source: Network Packet Capture",
    "Resources: Investigation Guide",
    "Rule Type: Event Correlation (EQL)",
    "Platform: Windows",
    "Platform: Linux",
]
timestamp_override = "event.ingested"
type = "eql"

query = '''
network where event.module == "network_traffic" and
destination.ip == "168.63.129.16" and
user_agent.original != null and
not user_agent.original : (
  "WALinuxAgent*",
  "VMAgent*",
  "Python-urllib*",
  "cpprestsdk*",
  "ACMS/*"
) and
(
  url.query : ("*comp=versions*", "*comp=goalstate*", "*comp=certificates*") or
  (destination.port == 32526 and url.path : ("/versions", "/vmSettings"))
)
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1552"
name = "Unsecured Credentials"
reference = "https://attack.mitre.org/techniques/T1552/"
[[rule.threat.technique.subtechnique]]
id = "T1552.005"
name = "Cloud Instance Metadata API"
reference = "https://attack.mitre.org/techniques/T1552/005/"



[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1082"
name = "System Information Discovery"
reference = "https://attack.mitre.org/techniques/T1082/"


[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.