Cobalt Strike remains the dominant C2 framework among ransomware affiliates and nation-state actors despite being a commercial penetration testing tool. Its default TLS configuration produces a stable JARM fingerprint that has been incorporated into every major threat intelligence blocklist since 2020. In 2026, operators are systematically rotating malleable C2 profiles to generate different JARM and JA3S fingerprints on a per-campaign basis, effectively defeating fingerprint-based network blocking. This report documents the rotation patterns observed, the countermeasures that work, and the ones that don't.

[INFO]
Analysis based on 78 confirmed Cobalt Strike C2 servers identified via honeypot connections and incident response telemetry, January - July 2026. JARM fingerprints collected via active probing of confirmed servers. JA3S data from TLS session captures in incident response environments.

//JARM Fingerprinting Background

JARM, developed by Salesforce researchers in 2020, fingerprints TLS servers by sending 10 specially crafted ClientHello packets that probe different aspects of the server's TLS implementation: cipher suite preferences, extension handling, session resumption behaviour, and version negotiation. The server's responses are hashed into a 62-character fingerprint that is highly stable for a given TLS implementation and configuration.

Default Cobalt Strike 4.x listeners use the Java TLS stack with no custom certificate or cipher configuration, producing a well-known JARM fingerprint. This fingerprint has been added to Suricata rule sets, Palo Alto Wildfire, and commercial threat intel feeds.

JA3S Fingerprinting

JA3S fingerprints the TLS server from the ServerHello response: TLS version, chosen cipher suite, and extensions present in the server response. Like JARM, default Cobalt Strike produces a stable JA3S fingerprint. Unlike JARM (which requires active probing), JA3S is passively collectible from any position in the network with TLS visibility.

//Profile Rotation Patterns

In 2026, operators rotate malleable C2 profiles on a per-campaign or per-week cadence to change the TLS fingerprint before it can be added to blocklists. Three rotation strategies have been observed.

Strategy 1: Cipher Suite Reordering

The simplest rotation changes only the order of cipher suites in the TLS ClientHello (from the beacon side) and the server's preference list (via malleable profile ssl-cert block). Since JARM uses cipher suite preferences as a key input, reordering completely changes the fingerprint with minimal operational effort.

# Malleable C2 profile: cipher suite rotation example
# Profile A (week 1)
https-certificate {
  set cipher_suite "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256";
}
# JARM fingerprint A: 2ad2ad0002ad2ad00042d42d0000002ad2ad...

# Profile B (week 2) - same certs, different suite order
https-certificate {
  set cipher_suite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384";
}
# JARM fingerprint B: 07d14d16d21d21d07c42d43d000000f5...
# Different fingerprint, same underlying C2, same beacon

Strategy 2: CDN Proxying

A growing proportion of Cobalt Strike infrastructure routes beacon traffic through Cloudflare or other CDN providers using domain fronting or standard CDN proxying. The beacon communicates with a Cloudflare IP, and Cloudflare proxies requests to the actual C2 backend. The JARM fingerprint collected from the Cloudflare IP is Cloudflare's fingerprint, not the C2's, effectively hiding the C2 behind a legitimate infrastructure provider.

Strategy 3: Self-Hosted JVM TLS Customisation

Operators with technical sophistication are rebuilding the Cobalt Strike team server with custom JVM TLS configurations (JSSE provider substitution) to produce arbitrary JARM fingerprints. This requires modifying the team server JAR but is documented in operator communities and GitHub repositories.

//Countermeasures That Work

Since TLS-level fingerprinting is defeated by configuration changes, durable detection must operate on behavioural patterns that are harder to modify.

Beacon Timing Analysis

Cobalt Strike beacons have configurable sleep intervals with jitter. Even with jitter, the statistical distribution of inter-connection intervals is characteristic. Beacons with 60-second sleep + 20% jitter produce connections in the 48-72 second range. Over 20+ connections, the distribution is identifiable even when individual intervals overlap with legitimate traffic patterns.

# Beacon timing fingerprint (Zeek/Bro analysis)
# Look for periodic HTTPS connections with consistent interval distribution
event connection_established(c: connection) {
    if (c$resp$port == 443 && is_external_ip(c$resp$h)) {
        record_connection_timing(c$id$orig_h, c$resp$h, network_time());
    }
}
# Post-hoc analysis: for each (src, dst) pair with >10 connections,
# compute coefficient of variation of inter-arrival times
# CS beacon with 20% jitter: CV typically 0.12-0.22
# Legitimate browser traffic: CV typically > 0.5

HTTP Host Header Patterns

Malleable C2 profiles that mimic CDN or software update traffic produce distinctive Host header values that can be fingerprinted: the Host header value does not match the SNI in the TLS handshake (a common domain fronting tell), or the Host header follows a fixed pattern across all beacon connections regardless of the claimed content type.

[TECHNICAL NOTE]
The most robust detection combines: (1) beacon timing distribution analysis, (2) Host/SNI mismatch detection, (3) HTTP response size consistency (CS team server returns very consistent response sizes for beacon check-in acknowledgements regardless of profile customisation), and (4) certificate subject anomalies (newly issued certs, mismatched org/CN values). No single signal is reliable, but all four together have a very low false positive rate.
[IOC] Cobalt Strike C2 - 2026 Fingerprints
JARM fingerprints (rotated, July 2026 observed):
2ad2ad0002ad2ad00042d42d0000002ad2ad2ad2ad2ad2ad2ad2ad2ad2ad2ad2
07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0888a5
29d29d00029d29d00041d41d000000aa99ce74e2c6d013c745aa52b5cc042d

Default CS listener JARM (still observed on unpatched operators):
07d14d16d21d21d07c07d14d07d21d9b2f70a47ccd78d39cb2f6c70a47ccd78

Beacon check-in HTTP response size range (consistent across profiles):
1250-1380 bytes (Content-Length + headers)