JA3 is a fingerprinting mechanism performed on a Client that uses TLS to connect with the Server. This is done by performing a series of operations on the ClientHello packet received in the first step of the TLS Negotiation processes.
Earlier, many websites used to fingerprint users based on the User-Agent. In recent time’s it has taken seconds to impersonate that, and JA3 fingerprint is a significantly less known fingerprint solution used by many companies like Cloudflare in their bot management tools.
Let’s explore the ClientHello packet first to understand how JA3 is calculated:
According to RFC5246 of TLSv1.2, ClientHello Packet is defined as
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
Wherein
The extensions field can have EllipticCurve,EllipticCurvePointFormat
as defined in RFC4492. Thus taking all of these things into consideration, we can have more than 2 quintillion ways of sending a ClientHello Message as
CipherPermutations = 20!
ExtensionPermutations = 15!
CurvePermutations = 4!
CurveFormatPermutations = 3!
TotalPermutations = 20! + 15! + 4! + 3! = 2432903315851008030
unique way’s to individually identify and fingerprint clients.
JA3 is calculated using the following 5 parameters taken from the ClientHello Packet as defined above:
SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat
JA3 gathers the decimal values of the bytes for the following fields in the Client Hello packet; SSL Version, Accepted Ciphers, List of Extensions, Elliptic Curves, and Elliptic Curve Formats. It then concatenates those values together in order, using a “,” to delimit each field and a “-” to delimit each value in each field.
With TLS 1.2 upgrade, RFC4492 was revised to RFC8422, and the EllipticCurve field was further referred to as supported_groups, so we use that field from the Wireshark packet to calculate JA3.
GREASE(Generate Random Extensions And Sustain Extensibility) is a technique defined by this IETF Draft introduced by Google to prevent extensibility failures in the TLS ecosystem. It introduces invalid random values in the ClientHello packet with no effect and ensures that all the newly written code handles unexpected values. For the calculation of the JA3 fingerprint, we ignore this.
BurpSuite!? Two Fingerprints?
While further investigating, I have found that BurpSuite has got two fingerprints as follows:
Here is the actual difference of the packets from Wireshark(Extensions filed part of the ClientHello packet)
In the first packet, we can observe an additional field called application_layer_protocol_negotiation as defined in RFC7301. It contains a list of protocols id’s supported by the client.
As defined in RFC7301:
“When multiple application protocols are supported on a single server-
side port number, such as port 443, the client and the server need to
negotiate an application protocol for use with each connection. It
is desirable to accomplish this negotiation without adding network
round-trips between the client and the server, as each round-trip
will degrade an end-user’s experience. Further, it would be
advantageous to allow certificate selection based on the negotiated
application protocol”
Due to this, two JA3 fingerprints were generated for BurpSuite, unlike any other browser which actually sends application_layer_protocol_negotiation in every packet. Why? Probably need to ask the creators of BurpSuite.
ja3er.com — This website should not be used to find your JA3 fingerprint since it gives a false JA3 value as outlined in this Github Issue and this tweet. To give you an idea, you can check differences as shown below:
The packet which we receive as a response from the ClientHello packet sent by the client is the ServerHello packet, and this can be used to calculate the unique fingerprint using the following fields of the ServerHello message:
TLSVersion,Cipher,Extensions
Example:
md5(769,47,65281–0–11–35–5–16) =
4835b19f14997673071435cb321f5445
Until now, JA3 and JA3s were more passive fingerprinting ways to detect, but the more active ones would be JARM.
In JARM, we send 10 Specially crafted TLS packets to get the most unique responses of the Server with varying protocol versions and ciphers. Further, the JARM fingerprint hash is a hybrid fuzzy hash; it uses a combination of a reversible and non-reversible hash algorithm to produce a 62 character fingerprint, unlike using MD5 as in JA3, JA3S case. You can read further about JARM on it here.
You can search for Server’s over the internet using the JARM fingerprint to essentially find things like C&C servers used by specific malware using the following engine’s:
JA3 and JA3s use MD5 hash to fingerprint the packet, unlike fuzzy hashing used by JARM to fingerprint the client from where the request is being sent. Using MD5 has some security implications like a Hash collision, but the authors have used MD5 to support old clients and advise logging the whole string(string before the MD5 hashing is done) for further analysis. Also, in some cases, some browsers can have the same JA3 fingerprints making them tough to identify. Still, the order of cipher’s supported by the browsers changed with every release in recent times, thus making it easy to fingerprint.
Further, with the introduction of ECH — Encrypted Client Hello, this fingerprinting can only be performed after decrypting the packet on the server-side rather than being fingerprinted by every entity involved in the transfer of the packet in clear text from Client to Server.
Some of the exciting applications of this could be as follows:
As said, “Nothing is Hack Proof,” yes you can also impersonate the JA3 fingerprints sent by your TLS Application as explained by CU Cyber in their using a tool called ja3transport or using another project called CycleTLS