Introducing JA4Scan: Active Server Fingerprinting for TLS and QUIC

John Althouse and Sébastien Féry

TL;DR

JA4Scan-TLS and JA4Scan-QUIC are our latest additions to the JA4+ suite of fingerprinting methods. Together they fingerprint the TLS and QUIC libraries running on any given server, uncovering both the running TLS/QUIC stack and its configuration.

You can think of JA4Scan as the modern replacement for JARM, from the same person. It can be used to:

  • Quickly verify that all servers in a group have the same TLS configuration.

  • Group disparate servers on the internet by configuration.

  • Identify default applications or infrastructure.

  • Identify malware command and control infrastructure and other malicious servers on the Internet.

JA4Scan is currently integrated in Security Scorecard's Driftnet.io, Hunt.io (Oct 1), MODAT and coming soon, if not already implemented, in Censys, Palo Alto Networks' Cortex Xpanse, Validin, and other EASM tools.

Background

JARM

Back in 2020, myself (John Althouse) and my team at Salesforce, Andrew Smart, RJ Nunnally, and Mike Brady, along with a bunch of work by Caleb Yu, created JARM, the active TLS server fingerprinting tool used throughout the industry today. And it worked great. We’ve been able to classify and track server infrastructure, including C2s, across the internet for years. But we made JARM for a TLS 1.2 world, a world where QUIC (HTTP/3) was still experimental and not officially released.

With TLS 1.3 over TCP and QUIC now accounting for the vast majority of the internet, JARM has been struggling. For example, when I searched for the JARM fingerprint of all 00s on hunt.io, it came back with over 74M results. That means the server is running TLS, the JARM scan ran, but returned no results. We found similar results on Censys and Driftnet.

In cases where there are results, the JARM fingerprints started to collide by a large amount, reducing their effectiveness.

What changed?

JARM was built entirely around the TLS 1.0-1.2 Server Hello packet. In TLS 1.3 a number of the signals are no longer in the Server Hello which now contain the bare minimum. The most segmenting signals have moved to encrypted extensions or to post-handshake messages and JARM does not look that deep. JARM was also only focused on TLS over TCP and could not scan QUIC servers (TLS over UDP), which now accounts for nearly half of all internet traffic.

It’s time for an upgrade. JA4Scan is that upgrade.

How JA4Scan Works

JA4Scan sends 17 probes to a target over both TCP and QUIC, across TLS 1.2, 1.3 and QUIC. Each probe is a specifically crafted Client Hello to elicit differentiating behavior from the server. The goal is not only to record the values a server chooses, but how it behaves: structural decisions hardcoded in the library that remain stable regardless of hardware and configuration.

The Fingerprints

Just like the rest of JA4+, JA4Scan fingerprints are meant to be human readable as well as machine usable with delimited sections allowing you to pivot on individual sections or the whole fingerprint. JA4Scan-TLS fingerprints traditional TLS over TCP servers, while JA4Scan-QUIC fingerprints QUIC servers. In the event that a server is running a dual stack, the combined JA4Scan-TLS + JA4Scan-QUIC becomes unique to that stack.

Examples:

Dual stacks

Site

JA4Scan-TLS

JA4Scan-QUIC

Stack

Cloudflare

23000h0s02s0_7c13a278e8c0_000000f0ac40_sd1c00299504

0300chlss200_8960528bd01f_000000b36f05_sd1000e9c647

boringssl + quiche (cloudflare version)

Google

23000h0s02s0_865584d8a6d5_000000f703cf_sd1c00299504

031gchlsr000_bd327ffee725_6d6a17c51f1f_se1000e9c647

boringssl + quiche (google version)

Fastly

23100h0s04s0_093a61f6842f_8ba218cede0d_sr2sssc389dc

03100hlss400_db6b5a8b860e_6d6a17001638_sr2sss473b09

picotls + quicly

Akamai

23100h0s02sn_288488037518_fa4cedcede0d_0d1cs0a10eaa

030g0hlsr20n_febdf6a4d8b3_24d9b60f20b7_0d10s05771b8

boringssl + assumed akaquic

Just like with the rest of JA4+, if a deployment differs in only one aspect, a partial fingerprint remains usable. In these examples the ciphers chosen by the servers were different, however, the first three components of the JA4Scan fingerprint remain unaffected. This allows for pivoting even when certain aspects are manually changed.

OpenSSL Version

Certificate Type

JA4Scan-TLS 

OpenSSL 3.5.5

RSA

TLS=23000h0s02sn_f6f9e45b3dd5_1b98decede0d_sr1sssbe8207

OpenSSL 3.5.5

ECDSA

TLS=23000h0s02sn_f6f9e45b3dd5_1b98decede0d_se1ss0651732

quic-go 0.61.0

RSA

QUIC=031g0hlss100_5973261134f6_6d6a1784efde_sr10sc7b63be

quic-go 0.61.0

ECDSA

QUIC=031g0hlss100_5973261134f6_6d6a1784efde_se10s05444e9

Translating Fingerprints to Libraries

Clustering is useful on its own, but the objective is attribution. So we built JA4Scan-translate, a rule engine sidecar that maps JA4Scan runs to named TLS libraries and QUIC implementations, even with different configurations, the stacks used are still identifiable.

For example, Apple’s QUIC stack advertises two transport parameters not found in any RFC: 0xbabf and 0xff080808 - 0xbabf is enable_multipath - the experimental codepoint from the IETF multipath draft (still active at draft-21) that Apple adopted early and never updated. 0xff080808 is migration_version, an Apple-only parameter for client-initiated connection migration. Together they make Apple's QUIC implementation immediately identifiable on the wire. Rules like this are built into our JA4Scan-translate tool.

Identifying Infrastructure with Combined Fingerprints

The “mitmproxy” network interception tool leverages pyssl (OpenSSL) for TCP and since version 11, uses aioquic for QUIC support.

This results in the following fingerprints:

JA4Scan-TLS

23000h0s02sn_6a10a6d46e59_1b98decede0d_sr1sssbe8207

JA4Scan-QUIC

0310000ss000_2a673bc4abf8_aee409e4882a_sr2s0seb0750

This combination of stacks are unique, making the combination of JA4Scan-TLS AND JA4Scan-QUIC fingerprints unique to the tool.

Selective servers 

Depending on their setup, TLS servers can admit a request based on SNI (domain name, common for reverse proxies) or ALPN (protocol-specific). If a request does not have the necessary domain name in the SNI or the correct ALPN, the server may refuse the connection.

JA4Scan-TLS and JA4Scan-QUIC record the shape of the refusal. This means that even if a server refuses the scanning probes, JA4Scan will still produce a pivotable fingerprint for that infrastructure and configuration.

SNI-gating:

Correct SNI

23200h0s02sn_82383ca4b028_45f45ecede0d_0r1cscbd627c

Wrong / No SNI

0010000s0000_904985729b75_06203a000000_000000000000

nginx 1.27.5 / OpenSSL, ssl_reject_handshake on

Correct SNI

23200h0s01s0_26ec5e416bec_d10823cede0d_0r1csca57cca

Wrong / No SNI

03100h0s00s0_070958e7790e_db7b01d72666_00000040811f

Caddy 2.11.4 / Go crypto/tls, default

Correct SNI

23100h0s01s0_26ec5e416bec_0c479acede0d_001cs0bd627c

Wrong / No SNI

03100h0s00s0_070958e7790e_65cd35d72666_00000040811f

Traefik 2.11.54 / Go crypto/tls, sniStrict: true

Note that despite using the same runtime, the error profiles of Caddy and Traefik differ, yielding the same structural JA4Scan fingerprint with differing c sections.

ALPN-gating:

DOQ, DNS over QUIC, listeners gate on ALPN, they accept only “doq” in the Application Protocol Negotiation extension and refuse “h3”. This leads to unique JA4Scan-QUIC fingerprints.

Implementation

Stack

JA4Scan-QUIC

Dnsproxy

Go, quic-go

032g0hlss100_93b413a26a43_1165e672744b_0r10s04e82ca

sdns

Go, quic-go

032g0hlss100_93b413a26a43_1165e672744b_0r10s04e82ca

mosdns

Go, quic-go

032g0hlss100_93b413a26a43_1165e672744b_0r10s04e82ca

Resisting Evasion - Sliver C2 Detection

Offensive tooling increasingly ships fingerprint-evasion features. Sliver, BishopFox’s C2 framework, offers a randomization option on its HTTPS listener that shuffles the server's cipher suite list and lowers the minimum TLS version on each start.

Four independent randomizations, each producing a different server configuration:

Config

JA4Scan-TLS

TLS 1.1, 18 ciphers

23100h0s01s0_10ec34d82fca_6d6a17cede0d_se0cs0b920bb

TLS 1.1, 19 ciphers

23100h0s01s0_10ec34d82fca_6d6a17cede0d_se0ss09c7d1d

TLS 1.1, 20 ciphers

23100h0s01s0_10ec34d82fca_6d6a17cede0d_se0cs0b920bb

TLS 1.1, 16 ciphers

23100h0s01s0_10ec34d82fca_6d6a17cede0d_se0cs0b4d286

TLS 1.0, 20 ciphers

23100h0s01s0_10ec34d82fca_6d6a17cede0d_se0cs0b920bb

Notice the first three components are identical across all six, including the configuration that dropped to TLS 1.0

Sliver's mutual-TLS listener carries this comment:

// We're not going to randomize the JARM on this one, the traffic
// going over mTLS needs to be secure, and the JARM is fairly
// common Golang TLS server so it's not going to be too suspicious
// We're not going to randomize the JARM on this one, the traffic
// going over mTLS needs to be secure, and the JARM is fairly
// common Golang TLS server so it's not going to be too suspicious
// We're not going to randomize the JARM on this one, the traffic
// going over mTLS needs to be secure, and the JARM is fairly
// common Golang TLS server so it's not going to be too suspicious

The configuration is TLS 1.3-only with RequireAndVerifyClientCert which produces this fingerprint:

At the time of writing, filtering that fingerprint to Sliver's default mTLS port, port 8888, narrows a broad configuration class down to only 59 hosts. 

Diving into these on Hunt.io and some are very obviously Sliver with port 31337 also open and clearly showing all the signs of a Sliver C2. For example: 35.212.172.98

While others do not wave the Sliver flag so overtly. For example: 67.207.95.215

We can still confirm that these are Sliver C2s by matching the JA4X fingerprint. JA4X is a fingerprint of the X509 certificate structure, essentially fingerprinting the tool which generated the certificate and not the certificate details themselves. Known Sliver mTLS X509 certificates have the following fingerprints:




With this additional piece of pivot information, we can now expand our search beyond the known Sliver port of 8888 and find the really interesting IPs.







These IPs and ports have been independently validated by Hunt.io as either confirmed Sliver C2s or high confidence.

While these fingerprints, in isolation, collide with benign servers, in combination they become… sliver bullets... I’m sorry, I’m a dad. My point is that JA4+ fingerprints are designed to be used in combination as that is the key to high fidelity detection. So whenever you encounter malicious servers with self-signed certificates, I especially encourage you to combine JA4Scan + JA4X to find more of the same infrastructure. 

This is just an example and none of this is meant to bash on Sliver or my friends at BishopFox. If you’re in the market for a Red Team engagement, I recommend you check them out!

Interesting QUIC Fingerprints

Datagrams

Implementation

Stack

JA4Scan-QUIC

hysteria

Go, quic-go fork

032g0hlss100_52347523195b_d1082384efde_0e1cs05444e9

gomoqt

Go, quic-go

031g0hlss000_5973261134f6_6d6a17ca3fbe_se1cs05444e9

moq-relay

Rust, quinn / rustls

031g0hlsr200_8960528bd01f_6d6a17121544_se1cs0fecef0

moq-rs

Rust, quinn / rustls

031g0hlsr200_8960528bd01f_6d6a17121544_sr1csccfa1a9

moq and hysteria make use of datagrams and advertise it via the max_datagram_frame_size transport parameter, leading to unique JA4Scan fingerprints compared to a QUIC listener serving HTTP/3.

MASQUE

MASQUE allows proxying UDP inside HTTP/3 datagrams. VPN providers and others use it as a WireGuard obfuscation transport on port 443 with a publicly issued certificate to act as an ordinary server.

Deployment

JA4Scan-TLS

JA4Scan-QUIC

masque-go v0.4.0

-

031g0hlss000_5973261134f6_6d6a1784efde_sr1csc7b63be

Mullvad Hong Kong node

-

031g0hlss000_5973261134f6_6d6a1784efde_sr1csc7b63be

NordVPN af8 (nordwhisper_udp)

03100h0s01s0_9d52559f55bc_d06dc4cede0d_sr00sc82d654

031g0hlss000_5973261134f6_6d6a1784efde_sr1csc7b63be

CTYun (China Telecom Cloud)

2000000s00s0_0d2c87c1f885_8eddc28b041c_s01s0015f721

031g0hlss000_5973261134f6_6d6a1784efde_sr1csc7b63be

JA4Scan

JA4Scan was 100% human created with over a year of iteration and testing and is currently integrated into Security Scorecard's Driftnet.io, Hunt.io (Oct 1), MODAT and coming soon, if not already implemented, in Censys, Palo Alto Networks' Cortex Xpanse, Validin, and other EASM tools.

If you would like to do the scanning yourself, JA4Scan is free and provided under the FoxIO License, just like the rest of JA4+. However, we’ve decided not to make the source code available for general AI consumption at this time. As such, if you would like access to the JA4Scan tool, please just send your github username to info@foxio.io and we’ll gladly add you to the repo!

JA4Scan was created by Sébastien Féry and John Althouse (author of JARM).