Overview

BRICKSTORM is a sophisticated, Go-based backdoor attributed to People's Republic of China (PRC) state-sponsored threat actors (tracked as UNC5221 / Warp Panda) that specifically targets VMware vSphere infrastructure — the vCenter Server Appliance (VCSA) and ESXi hypervisors. The malware is designed to operate entirely beneath the guest OS layer, exploiting the fundamental visibility gap created by the absence of EDR support on virtualization control planes.

Key Risks

Complete Virtualisation-Layer Compromise

Control of vCenter grants power-off, deletion, and reconfiguration of every managed VM. Domain controllers and PAM vaults are directly reachable, bypassing OS-layer controls entirely.

Silent Credential & Data Exfiltration

BRICKSTEAL scrapes Tomcat memory for SSO tokens and credentials. VM cloning allows offline NTDS.dit extraction without triggering host-based controls.

KQL Detections

The following queries target Microsoft Sentinel ingesting vSphere syslog. Each maps to the relevant MITRE ATT&CK technique.

T1190 T1021.004

1. SSH Enablement via VAMI (Initial Access)

Detects POST/PUT requests to the vSphere Appliance Management Interface on port 5480 enabling SSH — a common first step in BRICKSTORM deployments. Filter to exclude known privileged access workstation IPs.

Syslog
| where ProcessName has_any ("vami-httpd", "vmware-vami")
| where SyslogMessage has "5480"
| where SyslogMessage has_any ("POST", "PUT")
| where SyslogMessage has_any ("ssh", "enableSSH", "sshd")
| extend SourceIP = extract(@"(\d+\.\d+\.\d+\.\d+)", 1, SyslogMessage)
| where SourceIP !in (trusted_mgmt_ips)  // Replace with your PAW IP list
| project TimeGenerated, HostName, SourceIP, SyslogMessage
| order by TimeGenerated desc
T1136.001 T1070

2. Transient SSO Account Lifecycle (Persistence)

Identifies accounts that are created and deleted within a 30-minute window — a hallmark of BRICKSTORM's ghost-account persistence technique used to avoid leaving permanent artefacts in vCenter SSO.

Syslog
| where ProcessName has_any ("vsphere-ui", "vmware-sso")
| where SyslogMessage has "PrincipalManagement"
| extend EventType = extract(@"(UserAdded|UserDeleted|GroupMemberAdded)", 1, SyslogMessage)
| extend AccountName = extract(@"principal[=\s]+([^\s,]+)", 1, SyslogMessage)
| summarize
    Created = countif(EventType == "UserAdded"),
    Deleted = countif(EventType == "UserDeleted"),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by AccountName, bin(TimeGenerated, 30m)
| where Created >= 1 and Deleted >= 1
| extend DwellMinutes = datetime_diff('minute', LastSeen, FirstSeen)
| where DwellMinutes <= 30
| project FirstSeen, AccountName, DwellMinutes, Created, Deleted
| order by FirstSeen desc
T1059.004 T1106

3. auditd — Suspicious Binary Execution (Execution)

Leverages Linux auditd telemetry forwarded from the VCSA to catch known BRICKSTORM binary names and executions from suspicious paths such as /tmp/ and /dev/shm/.

Syslog
| where SyslogMessage has "msg=audit"
| where SyslogMessage has_any ('key="execpriv"', 'key="privileged"')
| extend
    AuditUser = extract(@'auid=(\d+)', 1, SyslogMessage),
    Command   = extract(@'exe="([^"]+)"', 1, SyslogMessage),
    CmdArgs   = extract(@'proctitle=([^\s]+)', 1, SyslogMessage)
| where Command has_any ("pg_update","vmp","vmsrc","BRICKSTORM","/tmp/","/dev/shm/")
      or AuditUser == "0"  // Root executions of unexpected binaries
| project TimeGenerated, HostName, AuditUser, Command, CmdArgs, SyslogMessage
| order by TimeGenerated desc
T1037.004

4. Startup Script Injection via sed (Persistence)

BRICKSTORM achieves persistence by patching VCSA startup scripts. This query watches auditd for writes to known init paths and is most effective when AIDE or equivalent file integrity monitoring is also in place.

Syslog
| where SyslogMessage has "msg=audit"
| where SyslogMessage has_any ('key="startup_scripts"', 'key="perm_mod"')
| extend
    FilePath = extract(@'name="([^"]+)"', 1, SyslogMessage),
    Syscall  = extract(@'syscall=([^\s]+)', 1, SyslogMessage)
| where FilePath has_any (
    "/etc/rc.local",
    "/etc/rc.local.d/",
    "/etc/sysconfig/init",
    "/opt/vmware/etc/init.d/",
    "/etc/init.d/"
  )
| project TimeGenerated, HostName, FilePath, Syscall, SyslogMessage
| order by TimeGenerated desc
T1003.003 T1020

5. VM Clone / Export of Domain Controller (Exfiltration)

VM cloning is a preferred BRICKSTORM technique for extracting NTDS.dit offline without triggering Windows-layer controls. This query alerts on clone or export events targeting VMs with names matching domain controller and privileged infrastructure patterns.

Syslog
| where ProcessName has_any ("vpxd", "vmware-vpxd")
| where SyslogMessage has_any (
    "VmClonedEvent",
    "VmBeingClonedEvent",
    "VmDiskHotPlugEvent",
    "VmExportedEvent"
  )
| extend
    VMName    = extract(@'vm\.name=([^\s,]+)', 1, SyslogMessage),
    AdminIP   = extract(@'(\d+\.\d+\.\d+\.\d+)', 1, SyslogMessage),
    EventType = extract(@'(VmCloned|VmBeingCloned|VmDiskHotPlug|VmExported)Event', 1, SyslogMessage)
| where VMName has_any ("DC","DomainControl","CA","cert","PAM","vault","ADFS")
       or VMName matches regex @"[Dd][Cc]\d+"
| project TimeGenerated, VMName, EventType, AdminIP, SyslogMessage
| order by TimeGenerated desc
T1599 T1021

6. Ghost NIC Addition to VM (Lateral Movement)

Adding a hidden network adapter to a VM allows BRICKSTORM to bridge isolated network segments. This query fires on NIC addition events targeting management, vSAN, or restricted port groups.

Syslog
| where ProcessName has_any ("vpxd","vmware-vpxd")
| where SyslogMessage has_any (
    "VmNetworkAdapterAddedEvent",
    "VmReconfiguredEvent"
  )
| extend
    VMName    = extract(@'vm\.name=([^\s,]+)', 1, SyslogMessage),
    NetworkPG = extract(@'network[=\s]+([^\s,]+)', 1, SyslogMessage),
    AdminIP   = extract(@'(\d+\.\d+\.\d+\.\d+)', 1, SyslogMessage)
| where NetworkPG has_any ("mgmt","management","infra","restricted","vsan","vmotion")
        or SyslogMessage has "VmNetworkAdapterAddedEvent"
| project TimeGenerated, VMName, NetworkPG, AdminIP, SyslogMessage
| order by TimeGenerated desc
T1071.001 T1090.001

7. VCSA Outbound C2 Blocked (C2 Detection)

Requires a zero-trust egress policy on VCSA. Repeated blocked outbound connections from VCSA IPs to common C2 and SOCKS proxy ports indicate an active implant attempting to beacon. Tune the vcsa_management_ips variable to your environment.

Syslog
| where SyslogMessage has_any (
    "VCSA_FW_DROP",
    "INTERNET_BLOCKED",
    "ZT_OUTBOUND_DENIED"
  )
| extend
    SrcIP   = extract(@'SRC=(\d+\.\d+\.\d+\.\d+)', 1, SyslogMessage),
    DstIP   = extract(@'DST=(\d+\.\d+\.\d+\.\d+)', 1, SyslogMessage),
    DstPort = extract(@'DPT=(\d+)', 1, SyslogMessage),
    Proto   = extract(@'PROTO=(\w+)', 1, SyslogMessage)
| where SrcIP has_any (vcsa_management_ips)  // Replace with your VCSA IPs
| where DstPort in ("443","80","8080","8443","1080","9050")  // Common C2 / SOCKS ports
| summarize
    Count     = count(),
    FirstSeen = min(TimeGenerated),
    LastSeen  = max(TimeGenerated),
    DestIPs   = make_set(DstIP)
    by SrcIP, DstPort, Proto
| where Count > 3
| order by Count desc
T1036 T1562.001

8. AIDE Integrity Violation Alert (Tamper Detection)

AIDE (Advanced Intrusion Detection Environment) running on the VCSA provides a critical compensating control where EDR cannot operate. This query surfaces integrity violations in high-value paths targeted by BRICKSTORM for persistence and defence evasion.

Syslog
| where SyslogMessage has "AIDE_TRAP"
| where SyslogMessage has_any (
    "differences between database",
    "Changed files",
    "Added files",
    "Removed files"
  )
| extend
    ChangedFile = extract(@'(?:Changed|Added|Removed) files?: ([^\n]+)', 1, SyslogMessage)
| where ChangedFile has_any (
    "/lib64","/root/.ssh","/etc/audit","/etc/audisp",
    "/etc/rc.local","/opt/vmware/etc/init.d","/etc/sysconfig/init"
  )
| project TimeGenerated, HostName, ChangedFile, SyslogMessage
| order by TimeGenerated desc