Hey folks, Dave Glover here with some critical intel you need to act on right now. On October 15, 2025, F5 dropped a bombshell disclosure that's sending shockwaves through our industry—a nation-state threat actor, tracked as UNC5221 (China-nexus), maintained persistent access to F5's corporate network for over 12 months, exfiltrating BIG-IP source code and undisclosed vulnerability intelligence. CISA immediately issued Emergency Directive ED-26-01, and for good reason—this isn't just another breach, it's a strategic supply chain compromise with massive downstream implications.
If you're running F5 BIG-IP appliances (and let's be honest, who isn't?), you need to be threat hunting right now. This post will arm you with the knowledge and NetWitness queries to detect BRICKSTORM backdoor activity and related TTPs in your environment.
F5 discovered the intrusion on August 9, 2025, but evidence suggests UNC5221 had been inside since at least mid-2024.
The attackers exfiltrated:
The stolen source code dramatically increases the risk of rapid zero-day discovery and weaponization. F5 has since released patches for over 20 vulnerabilities spanning BIG-IP (all modules), F5OS-A/C, and BIG-IP Next. Key CVEs include:
Full vulnerability list available at: https://my .f5.com/manage/s/article/K000154696
UNC5221's weapon of choice is BRICKSTORM, a Go-based backdoor specifically engineered to compromise network appliances that don't support traditional EDR. Here's what makes it dangerous:
Technical Capabilities:
Operational Security:
Alright, enough theory—let's get to the good stuff. Here are NetWitness queries you can run right now to hunt for indicators of BRICKSTORM activity and UNC5221 TTPs in your environment.
# Detect HTTP/2 traffic from known appliance subnets
ip.src = '<your_appliance_subnet>' && http.version = '2.0'
# Detect WebSocket upgrade requests from appliances
ip.src = '<your_appliance_subnet>' && http.header contains 'Upgrade: websocket'
# Combine both for high-fidelity alert
ip.src = '<your_appliance_subnet>' && (http.version = '2.0' || http.header contains 'Upgrade: websocket')
Pro Tip: Create a meta key for your appliance management IPs (BIG-IP, vCenter, ESXi, VPN concentrators, firewalls) and substitute with your actual ranges.
# Look for persistent long-duration TLS sessions from appliances
ip.src = '<your_appliance_subnet>' && service = 443 && session.duration > 3600 && packets > 1000
# Detect TLS connections with HTTP/2 ALPN from appliances
ip.src = '<your_appliance_subnet>' && ssl.alpn = 'h2'
# Hunt for TLS sessions to non-standard ports (Yamux can run on any port)
ip.src = '<your_appliance_subnet>' && service != 443 && (tls.version = '1.2' || tls.version = '1.3')
# Detect outbound connections from appliances NOT to F5/VMware/known vendors
ip.src = '<your_appliance_subnet>' && direction = 'outbound' && !(alias.host contains 'f5.com' || alias.host contains 'vmware.com' || alias.host contains '<add_your_vendor_domains>')
# Focus on HTTPS connections to unknown destinations
ip.src = '<your_appliance_subnet>' && service = 443 && !(alias.host contains 'f5.com' || alias.host contains 'vmware.com')
# Detect DoH queries (usually to public resolvers)
ip.src = '<your_appliance_subnet>' && (alias.host = 'dns.google' || alias.host = 'cloudflare-dns.com' || alias.host = 'dns.quad9.net' || url contains '/dns-query')
# Broader hunt for HTTPS to known DoH providers
ip.src =
' && (ip.dst = '8.8.8.8' || ip.dst = '1.1.1.1' || ip.dst = '9.9.9.9') && service = 443
# Hunt for SMB traffic from appliances to Windows servers
ip.src = '
' && service = 445 && ip.dst = '
'
# Detect RDP sessions initiated from appliances
ip.src = '
' && service = 3389
# Look for Kerberos/NTLM authentication from appliances
ip.src = '<your_appliance_subnet>' && (service = 88 || service = 135 || service = 139)
Windows Event Correlation: Enrich with Windows Event Logs (Event ID 4624 Type 3) where source IP matches appliance management IPs.
# Detect large multipart/form-data uploads from appliances
ip.src = '<your_appliance_subnet>' && http.method = 'POST' && content.type = 'multipart/form-data' && bytes.dst > 1048576
# Look for base64 patterns in POST bodies (may trigger on legitimate traffic)
ip.src = '<your_appliance_subnet>' && http.method = 'POST' && payload contains 'base64'
# Hunt for SSH connections TO vCenter/ESXi management IPs
ip.dst = '<vcenter_esxi_management_ips>' && service = 22
# Look for SSH from unexpected internal sources
ip.dst = '<vcenter_esxi_management_ips>' && service = 22 && !(ip.src = '<authorized_jump_boxes>')
Log Correlation: Check vCenter audit logs (/var/log/audit/sso-events/audit_events.log) for PrincipalManagement events creating/deleting local users and SystemConfiguration.BashShellAdministrators group modifications.
# Hunt for SMB/vSphere API traffic patterns consistent with VM cloning
ip.src = '<vcenter_management_ip>' && (service = 443 || service = 902) && session.size > 10485760
Log Collection: Search vCenter VPXD logs for vim.event.VmBeingClonedEvent, vim.event.VmClonedEvent, and vim.event.VmRemovedEvent, filtering for VSPHERE.LOCAL\Administrator account during 01:00-10:00 UTC.
# Detect connections to known commercial VPN provider IP ranges
(asn = '<PIA_ASN>' || asn = '<NordVPN_ASN>' || asn = '<Surfshark_ASN>') && (ip.src = '<your_internal_subnets>' || ip.dst = '<your_internal_subnets>')
# Hunt for TLS connections to VPN provider domains
alias.host contains 'privateinternetaccess' || alias.host contains 'nordvpn' || alias.host contains 'surfshark' || alias.host contains 'vpnunlimitedapp' || alias.host contains 'privadovpn'
# Hunt for unusual Graph API access patterns
alias.host = 'graph.microsoft.com' && url contains '/mail' && http.method = 'GET'
# Detect bulk email downloads
alias.host = 'graph.microsoft.com' && url contains '/messages' && session.size > 10485760
Microsoft 365 Log Correlation: Query Unified Audit Log or Sentinel OfficeActivity table for MailItemsAccessed events with Enterprise Application ClientID, focusing on source IPs from commercial VPN ranges.
# Baseline query: Map all outbound destinations from appliances
ip.src = '<your_appliance_subnet>' && direction = 'outbound' aggregation: alias.host, ip.dst, service
# Anomaly detection: Alert on NEW destinations never seen before
ip.src = '<your_appliance_subnet>' && direction = 'outbound' && ! (alias.host = '<whitelisted_vendor_domains>')
Implementation: Run baseline weekly, export results, and create exclusion lists. Alert on any NEW connections.
BRICKSTORM File Hashes (SHA-256)
Note: UNC5221 never reuses malware samples or C2 domains across victims. Hash-based detection alone is insufficient - focus on TTP-based hunting.
This is where I want to shift your thinking. Yes, we need to hunt for IOCs and detect active compromise, but let's talk about Enablers of Compromise - the underlying weaknesses that gave UNC5221 a 12-month vacation in F5's network.
Key EOCs:Forward-Thinking Defense:
This breach isn't just about F5—it's a wake-up call about the fragility of our supply chain. When a security vendor gets compromised and their source code stolen, the downstream impact cascades to every customer running those products. With over 600,000 internet-connected F5 devices globally, the attack surface is enormous.
UNC5221's targeting of legal services, SaaS providers, BPOs, and technology companies suggests objectives beyond simple espionage:
The fact they maintained access for over a year undetected should give every CISO and security engineer pause. Traditional signature-based defenses failed. EDR didn't exist on the compromised appliances. This is why we need TTP-based hunting, behavioral analytics, and a relentless focus on Enablers of Compromise.
I know this is a heavy post, but the threat is real and active right now. UNC5221 is sophisticated, patient, and incredibly stealthy. They're not smash-and-grab criminals - they're nation-state operators playing the long game.
Your job is to make their life harder. Run these queries. Patch your systems. Lock down your appliances. Build detections around the TTPS, not just the IOCs. And most importantly, think forward - what conditions in your environment would enable an attacker to persist for 393 days? Fix those.
If you find something suspicious, don't hesitate to escalate and bring in forensics expertise. This is not the time for "wait and see".
Stay safe out there and keep those logs flowing.
Dave Glover