Exploring JARM – An Active TLS Fingerprinting Algorithm

Mohamad Mokbel (Senior Security Researcher · Trend Micro)

HITBSecConf2023 - Amsterdam · Day 1 · CommSec Track

Overview

In this insightful talk at HITB Amsterdam, Mohamad Mokbel, a Senior Security Researcher at Trend Micro, delved into the intricacies of JARM, an active TLS fingerprinting algorithm. The presentation offered a comprehensive exploration of JARM's internal mechanics, its practical applications in threat hunting, and a critical analysis of its efficacy and limitations. Mokbel's motivation stemmed from the lack of detailed public documentation on JARM's operational dynamics and the absence of a C++ implementation, which he developed to integrate into his own threat hunting framework.

Watch on YouTube

Visual summary for Exploring JARM – An Active TLS Fingerprinting Algorithm by Mohamad Mokbel
Visual summary for Exploring JARM – An Active TLS Fingerprinting Algorithm by Mohamad Mokbel

Key moments

  1. 7:00 JARM: An active TLS fingerprinting algorithm
  2. 12:20 Practical JARM use case: detecting malicious domains
  3. 14:00 Explanation of the 10 JARM packet types
  4. 27:30 Interpreting JARM version characters (e.g., 'F')
  5. 31:00 JARM fingerprints for malware families
  6. 40:50 Statistical analysis: JARM uniqueness on Alexa top 1M
  7. 50:00 Demo of the JARM C++ tool
  8. 56:00 Q&A: Server behavior anomalies and expected responses

Exploring JARM – An Active TLS Fingerprinting Algorithm

Speakers: Mohamad Mokbel, Senior Security Researcher, Trend Micro

Conference: HITB Amsterdam

YouTube: https://www.youtube.com/watch?v=MbgM4G1Ixv0

Overview

In this insightful talk at HITB Amsterdam, Mohamad Mokbel, a Senior Security Researcher at Trend Micro, delved into the intricacies of JARM, an active TLS fingerprinting algorithm. The presentation offered a comprehensive exploration of JARM's internal mechanics, its practical applications in threat hunting, and a critical analysis of its efficacy and limitations. Mokbel's motivation stemmed from the lack of detailed public documentation on JARM's operational dynamics and the absence of a C++ implementation, which he developed to integrate into his own threat hunting framework.

The talk highlighted JARM's unique approach to interrogating TLS servers by sending a series of specially crafted Client Hello requests, observing their responses, and generating a unique 62-character fingerprint. This method proves particularly valuable in scenarios where traditional methods fall short, such as identifying malware command-and-control (C2) servers utilizing TLS 1.3, which encrypts certificate information. However, Mokbel also critically examined JARM's susceptibility to false positives, especially when dealing with common web infrastructure like Content Delivery Networks (CDNs) and proxy services, underscoring the necessity for a nuanced understanding of its output.

Ultimately, Mokbel's exploration served as both a technical deep dive and a practical guide for security professionals. He demonstrated how JARM can be leveraged to detect encrypted malicious traffic, identify misconfigured servers, and link related threat campaigns. By dissecting the algorithm, sharing his C++ implementation, and presenting real-world analysis, Mokbel equipped the audience with a clearer understanding of JARM's potential as a powerful tool in the cybersecurity arsenal, while also emphasizing the importance of contextual interpretation to avoid misattributions.

Background

▶ Watch: JARM: An active TLS fingerprinting algorithm (7:00)

The foundation of secure internet communication relies heavily on the TLS/SSL handshake. This process begins after a standard TCP three-way handshake, with the client sending a Client Hello message and the server responding with a Server Hello. Crucially, these initial handshake packets are not encrypted across any version of the TLS/SSL protocol. This unencrypted nature allows security tools to inspect and post-process these packets from network captures (PCAPs) or binary files, making them a rich source of information for fingerprinting.

A Client Hello packet is a meticulously structured message where the client advertises its capabilities and preferences to the server. Key fields within this packet include the TLS version the client wishes to use (e.g., TLS 1.2, TLS 1.3), a random 32-byte nonce, a session ID, a list of supported cipher suites (cryptographic algorithms for authentication, hashing, and encryption), compression methods, and a variety of extensions. These extensions can include the server name indication (SNI), extended master secret key, maximum fragment length, unique renegotiation info, supported groups (for elliptic curves), elliptic curve point formats, session tickets, Application Layer Protocol Negotiation (ALPN), signature algorithms, key share, and Pre-Shared Key (PSK) exchange models. The server, in turn, responds with a Server Hello, indicating its chosen TLS version, a random value, the selected cipher suite from the client's list, and its own set of accepted extensions.

Prior to JARM, passive TLS fingerprinting techniques like GA3 and GA3S, introduced by Salesforce, were commonly used. GA3 passively parses the TLS version, list of cipher suites (their word values, not string representations), extension types, and elliptic curve details from a Client Hello message. These values are converted to decimal, delimited, and then MD5 hashed to produce a fingerprint. GA3S applies a similar process to the Server Hello message. However, as Mohamad Mokbel noted, these passive methods are highly prone to false positives. The limited attributes considered by GA3/GA3S are often insufficient to uniquely identify a specific client or server, leading to many different entities sharing the same fingerprint. This inherent lack of specificity paved the way for the development of more robust, active fingerprinting algorithms like JARM.

Key Findings

▶ Watch: Explanation of the 10 JARM packet types (14:00)

Mohamad Mokbel's deep dive into JARM revealed several critical findings regarding its operation, effectiveness, and limitations. At its core, JARM distinguishes itself as an active fingerprinting algorithm by sending 10 specially crafted TLS Client Hello requests to a server. Each request varies parameters such as cipher suite order, TLS versions, and extension inclusion, designed to "interrogate" the server and observe its responses to these deliberate variations. The server's responses (the Server Hello packets) are then parsed for the chosen cipher suite, the TLS minor version, and the list of extensions. This parsed data undergoes a hybrid hashing process: a fuzzy hash is generated for the cipher suite and TLS minor version, while the list of extension types is SHA256 hashed, with only the first 32 characters taken. These two hashes are concatenated to form the final 62-character JARM fingerprint.

Mokbel's primary motivation for this research was the lack of publicly available documentation detailing the internal dynamics of JARM and the absence of a C++ implementation. His own C++ implementation allowed him to thoroughly assess the algorithm and integrate it into his threat hunting framework. He highlighted that numerous organizations and tools, including VirusTotal, Shodan, BinaryEdge, Censys, GitHub, and libraries like PyJARM by Palo Alto Networks and HD Moore's Go implementation, have adopted JARM for various security applications.

A notable use case Mokbel presented was the "works like a charm" tool by "sketchy moose." This tool leverages JARM in conjunction with VirusTotal APIs to identify malicious domains involved in search engine optimization (SEO) poisoning campaigns. By filtering domains based on creation date and then matching their JARM hashes, the tool effectively groups related malicious infrastructure, proving its worth in linking threat campaigns and reducing false positives by adding contextual constraints.

However, Mokbel's analysis also exposed significant limitations. His statistical scanning of the top 1 million Alexa websites revealed that only approximately 5,000 unique JARM hashes were identified. This stark figure indicates that JARM, when used in isolation, is highly prone to false positives. Many servers, particularly those fronted by common infrastructure like Cloudflare or using default configurations, share identical JARM hashes. For instance, some hashes were found to be shared by over 138,000 servers, making it difficult to pinpoint specific malicious entities without additional context.

The decoding of the JARM hash itself offered insights into server behavior. The first 30 characters of the hash encode the index of the chosen cipher suite (1-based) and the TLS minor version (mapped to A-F). Mokbel pointed out that an 'F' in the TLS version field, signifying TLS 1.4 or higher, should immediately flag a server for further investigation as such versions are not yet standard. Furthermore, JARM proved effective in identifying servers still using insecure or weak cipher suites like RC4 encryption or MD5 for HMAC digestion, and even those supporting SSL version 3, an outdated and vulnerable protocol.

Mokbel's investigation also uncovered fascinating anomalies in server responses:

  • Order Sensitivity: The order of cipher suites in the Client Hello significantly influenced the server's selection, indicating that some servers are not strictly prioritizing the strongest available options.
  • Invalid Request Handling: Servers sometimes accepted intentionally malformed requests (e.g., inconsistent TLS record and handshake versions), revealing potential implementation flaws or permissive configurations. The Trickbot malware C2 servers, for example, consistently accepted invalid requests and stuck to TLS 1.0, making their JARM hash unique.
  • Inconsistent Responses: For the same server, JARM sometimes observed inconsistencies, such as the ALPN extension being present in some responses but absent in others during a short scanning window. The JARM hash for a given server could even change over time, suggesting dynamic server behavior or load balancing.

These findings underscore that while JARM is a powerful tool for discerning subtle differences in TLS stack implementations, its output must be interpreted with an understanding of its active nature and potential for false positives arising from shared infrastructure or dynamic server configurations.

Technical Deep Dive

▶ Watch: JARM fingerprints for malware families (31:00)

JARM's technical prowess lies in its ability to actively probe a server's TLS stack using a sequence of 10 distinct Client Hello requests, each meticulously crafted to test specific aspects of the server's configuration and behavior. Mohamad Mokbel detailed the construction and purpose of each of these requests:

  1. Forward: This request sends a list of 69 standard cipher suites ordered from strongest to weakest. It assesses how the server prioritizes and selects ciphers from an optimally ordered list.
  2. Reverse: The same 69 cipher suites are sent, but in reverse order (weakest to strongest). This tests if the server's cipher selection logic is sensitive to the client's preferred order.
  3. Top Half: This request reorders only the first 35 cipher suites while keeping the remaining 34 in their original sequence. It investigates the server's handling of partial order changes within the cipher suite list.
  4. Bottom Half: Conversely, this request reorders the last 34 cipher suites, leaving the first 35 untouched. It complements the "Top Half" test by examining the impact of changes in the latter part of the cipher suite list.
  5. Middle Out (Grease): This request introduces "grease" values—reserved, invalid cipher suite values (e.g., 0x?a, where the first nibble is between 0 and F, and the second is 'a'). These values are designed to test a server's compatibility and adherence to standards; a compliant server should ignore them. It helps detect servers that might exhibit anomalous behavior when encountering unknown or reserved values.
  6. TLS 1.1: This Client Hello explicitly requests communication using TLS 1.1. It assesses the server's support for this older, but still common, TLS version.
  7. TLS 1.2 ALPN: This request uses TLS 1.2 and includes the Application Layer Protocol Negotiation (ALPN) extension, with cipher suites ordered strongest to weakest. ALPN is used for performance reasons, allowing the client to advertise the underlying application protocols (e.g., HTTP/2, QUIC) it supports on top of TLS. This probes the server's ALPN capabilities.
  8. TLS 1.2 ALPN (Reverse): Similar to request #7, but the cipher suites are ordered weakest to strongest. This again checks for order sensitivity, specifically in the context of TLS 1.2 and ALPN.
  9. Invalid: This is a deliberately malformed request. It sets the TLS record version to 1.0 but the handshake version to 1.2. This inconsistency tests the server's error handling and how it resolves conflicting version information. A robust server should reject such a request or at least handle it predictably.
  10. TLS 1.3: This Client Hello specifically requests communication using TLS 1.3, the latest widely adopted TLS version. It checks for server support and preferred cipher suites under TLS 1.3.

From each of the server's 10 Server Hello responses, JARM extracts specific data points to construct the raw fingerprint: the chosen cipher suite (a 16-bit word value), the TLS version (major and minor bytes), the presence and value of the ALPN extension, and the types of all other extensions. These values are then concatenated, delimited by a pipe (|). If a value is absent, 00 is used as a placeholder.

The final 62-character JARM fingerprint is generated through a two-part hashing process:

  1. Fuzzy Hashing (First 30 characters): For each of the 10 requests, two characters representing the chosen cipher suite and one character representing the TLS minor version are derived.
  • Cipher Suite Encoding: The chosen cipher suite's 16-bit word value (e.g., c02b) is looked up in a predefined, ordered array of 69 standard cipher suites. Its 1-based index in this array (e.g., c02b might be at index 27) forms the two-character representation. If no cipher suite is chosen, 00 is used.
  • TLS Minor Version Encoding: The TLS minor version (e.g., 03 for TLS 1.2, which is 03 03 in hex) is mapped to a single character from A to F. For example, 00 maps to A (SSLv3), 01 to B (TLS 1.0), 02 to C (TLS 1.1), 03 to D (TLS 1.2), 04 to E (TLS 1.3). An F would indicate TLS 1.4 or higher, serving as an immediate flag for unusual behavior.

These three characters (two for cipher, one for version) are concatenated for each of the 10 requests, resulting in the first 30 characters of the JARM hash.

  1. SHA256 Hashing (Last 32 characters): The concatenated list of all extension types (excluding ALPN, which is handled in the fuzzy hash) from all 10 Server Hello responses is treated as a single string. This string is then SHA256 hashed, and only the first 32 characters of the resulting hash are taken.

The combination of the 30-character fuzzy hash and the 32-character SHA256 hash forms the complete 62-character JARM fingerprint. This hybrid approach allows JARM to capture both specific server choices (cipher, TLS version) and a broader representation of its extension support.

Mohamad Mokbel's C++ implementation of JARM utilized several third-party libraries: hash_sliver for SHA256 computations, color_console for console output, and cpp_optparse for command-line argument parsing. Notably, he mentioned facing challenges with the SFML library for TCP socket communications, particularly with connection timeouts. He had to implement a custom threading solution to monitor connections and enforce timeouts, highlighting a practical hurdle in building robust network tools.

Demo / Proof of Concept

▶ Watch: Statistical analysis: JARM uniqueness on Alexa top 1M (40:50)

During the presentation, Mohamad Mokbel provided a live demonstration of his C++ JARM tool, showcasing its functionality and the insights it can provide. The tool, run from the command line, allows users to generate JARM fingerprints for specified domains and to "demangle" or reverse-engineer existing JARM hashes to understand their underlying server responses.

Mokbel first demonstrated generating a JARM fingerprint for hitb.com. The command jarm domain hitb.com executed the 10 specially crafted Client Hello requests, processed the server's responses, and outputted the resulting 62-character JARM hash.

Following this, he used the inverse (or demangle) option to interpret the hitb.com hash: jarm -i domain hitb.com. The output was highly informative, detailing:

  • Which of the 10 JARM packets the server rejected (e.g., for hitb.com, packets 6, 9, and 10 were rejected). This immediately signals a unique server behavior.
  • The specific cipher suite chosen by the server for each accepted request.
  • The TLS version picked by the server for each accepted request.
  • An indication of whether the selected cipher suites were insecure (I), weak (W), or recommended (R). For hitb.com, all chosen ciphers were recommended, which is a positive security indicator.

Mokbel highlighted that the fact hitb.com rejected packets 6, 9, and 10 made its fingerprint "actually unique" in comparison to many other servers he scanned, which typically accept most requests. He also pointed out how the server's cipher choice sometimes changed between requests based solely on the ordering of cipher suites, despite the client advertising the same set of ciphers.

Beyond these core functions, Mokbel mentioned other capabilities of his tool:

  • Batch Scanning: The tool can process a list of domains from a file, saving the results to a CSV file for large-scale analysis.
  • Timeout Configuration: Users can specify connection timeouts to manage unresponsive or slow servers.
  • Verbose Output: A verbose mode provides more detailed information during the scanning process.
  • Raw Fingerprint Generation: The tool can output the intermediate "raw fingerprint" representation, which is the concatenated string of parsed server responses before the final hashing. This allows for manual inspection or for users to feed manually constructed raw fingerprints back into the tool to generate a final JARM hash.

The demo effectively illustrated JARM's power in revealing nuanced server behaviors that would be invisible to passive fingerprinting, making it a valuable asset for detailed security analysis.

Defensive Implications

▶ Watch: Q&A: Server behavior anomalies and expected responses (56:00)

JARM offers several crucial defensive implications for security professionals, enabling enhanced threat intelligence, improved detection capabilities, and better understanding of server configurations.

  1. Advanced Threat Hunting and Malware C2 Detection: JARM is particularly potent in identifying malware Command and Control (C2) servers, especially those leveraging TLS 1.3. With TLS 1.3, the server's certificate is encrypted as part of the handshake, rendering traditional certificate-based fingerprinting ineffective. JARM's active probing, however, can still generate a unique fingerprint based on the underlying TLS stack's behavior. This allows defenders to identify C2 infrastructure even when traffic is fully encrypted, offering a critical advantage against sophisticated threats like Trickbot and AsyncRAT, which have shown unique JARM hashes.
  1. Campaign Identification and Infrastructure Linking: By combining JARM with other contextual data, defenders can effectively link related malicious campaigns. As demonstrated by "sketchy moose's" tool, filtering domains by creation date and then matching JARM hashes can uncover phishing or malware campaigns using similar infrastructure. This helps security teams move beyond individual indicators of compromise (IOCs) to understand the broader adversary infrastructure.
  1. Vulnerability and Misconfiguration Detection: JARM can act as an auditing tool to identify servers running outdated or insecure TLS configurations. It can pinpoint servers that:
  • Support SSL version 3 or older TLS 1.0/1.1 versions, which are known to be vulnerable.
  • Utilize weak or insecure cipher suites, such as RC4 encryption or MD5 for HMAC digestion, which are susceptible to attacks.
  • Exhibit anomalous behavior, such as accepting invalid Client Hello requests or showing inconsistent ALPN extension responses, which could indicate non-standard or poorly configured TLS stacks. This information allows organizations to proactively patch and harden their internet-facing assets.
  1. Server Hardening and Baseline Establishment: Organizations can use JARM to fingerprint their own server infrastructure. By understanding the JARM hash of their properly configured servers, they can establish a baseline. Deviations from this baseline could indicate misconfigurations, unauthorized changes, or even compromise. It also provides insights into how different server software (e.g., Nginx, Apache) or operating systems handle TLS negotiations, allowing for more informed security decisions.

Despite its strengths, defenders must also be aware of JARM's limitations:

  • False Positives with Shared Infrastructure: As Mohamad Mokbel's research showed, JARM fingerprints can be highly non-unique across the internet. Servers fronted by CDNs (like Cloudflare) or other proxy services will often share the same JARM hash, as the fingerprint reflects the proxy's TLS stack, not the origin server's. Defenders must correlate JARM data with other intelligence (e.g., IP address, domain reputation, passive DNS) to avoid misattributions.
  • Evasion Techniques: The existence of tools like the JARM Randomizer (presented at HITB 2021) demonstrates that adversaries are already developing methods to manipulate JARM fingerprints to evade detection. This necessitates a continuous evolution of defensive strategies.
  • Context is King: A JARM hash alone is rarely sufficient for definitive attribution. It provides a strong signal about the TLS stack's behavior but needs to be interpreted within a broader context of network traffic analysis, threat intelligence, and behavioral patterns.

In conclusion, JARM is a powerful, active fingerprinting algorithm that adds a crucial layer to a defender's toolkit, particularly for encrypted traffic analysis and identifying server misconfigurations. However, its effective application requires a deep understanding of its technical underpinnings and an awareness of its inherent limitations, ensuring that its insights are leveraged responsibly and accurately.

Key Takeaways

  • Active TLS Fingerprinting: JARM is an active fingerprinting algorithm that sends 10 specially crafted Client Hello requests to a server to elicit unique responses, differentiating it from passive methods like GA3/GA3S.
  • Hybrid Hashing for Uniqueness: The JARM fingerprint is a 62-character string derived from a hybrid hashing process: a fuzzy hash of chosen cipher suites and TLS minor versions, concatenated with the SHA256 hash of all extension types from server responses.
  • Reveals Server Behavior: JARM effectively exposes nuanced server behaviors, such as sensitivity to cipher suite order, handling of invalid requests, and support for specific TLS versions and extensions (e.g., ALPN, Grease values).
  • Valuable for Threat Hunting: It is a potent tool for identifying malware C2 servers, particularly those using TLS 1.3 where certificate information is encrypted, and for linking related malicious campaigns based on shared infrastructure.
  • Prone to False Positives: JARM fingerprints can be highly non-unique across the internet, especially for servers behind common CDNs or proxies (e.g., Cloudflare), necessitating contextual analysis and correlation with other intelligence.
  • Identifies Misconfigurations: Defenders can use JARM to audit their own infrastructure or identify external servers using outdated TLS versions (SSLv3, TLS 1.0) or insecure/weak cipher suites (RC4, MD5 HMAC).

About the Speaker(s)

Mohamad Mokbel is a Senior Security Researcher at Trend Micro, where he works in the Digital Vaccine Lab. His role involves analyzing various security threats, including malware and vulnerabilities, to enhance intrusion prevention systems. Mohamad's primary interests lie in the fields of reverse engineering, malware research, and the development of intrusion detection and prevention systems. He also has a particular passion for C++ programming, compiler optimizations, and exploring exotic communication protocols across diverse underlying channels. Mohamad hails from Toronto, Canada, and this was his third or fourth time visiting Amsterdam.

Reviews

Dr. Zero (Offensive Security Researcher) — SOLID

Competent walkthrough of JARM internals that fills a documentation gap, but this is implementation archaeology, not novel research. Mokbel built a C++ implementation and explained the algorithm clearly — useful for practitioners who want to understand what's under the hood, but nothing here advances the state of the art.

Heather Calloway (CISO) — SOLID

A competent technical breakdown of JARM internals that fills a documentation gap, but the strategic value for security programs is limited. The key insight—JARM has massive false positive rates against shared infrastructure—is important, but most mature threat intel teams already know this. Worth a look for detection engineers building TLS fingerprinting into their hunting workflows.

→ Top-rated talks at HITBSecConf2023 - Amsterdam

All talks from HITBSecConf2023 - Amsterdam