John Althouse, Director of Threat Detection, Salesforce
Network threat detection is a moving target. Those of us in the threat detection corner of the security universe are always on the lookout for better ways to identify and prevent “evil on the network.” With JA3/S and HASSH detecting malicious encrypted channels on the network can be, in some cases, exceedingly easy.
Recently, I held a tech talk titled Finding Evil on the Network Using JA3/S and HASSH. This blog is a very high-level overview of that talk, so you can decide without spending too much time whether it’s something you’d be interested in watching. I also have a more detailed blog on the subject with code samples that you can find here.
The JA3 Standard
JA3 is a standard for creating secure sockets layer/transport layer security (SSL/TLS) client fingerprints in an easy to produce and shareable way. The primary concept for fingerprinting TLS clients came from Lee Brotherston’s 2015 research and his DerbyCon talk. If it weren’t for Lee’s research and the open sourcing of it, we wouldn’t have started work on JA3. JA3 was created by John Althouse, Jeff Atkinson, and Josh Atkins.
TLS and its predecessor, SSL, are used to encrypt communication by common applications, to keep data secure, and by malware, so it can hide in the noise. To initiate a TLS session, a client sends a TLS Client Hello packet following the TCP 3-way handshake. This packet and the way in which it is generated are dependent on packages and methods used when building the client application.
If accepting TLS connections, the server will respond with a TLS Server Hello packet, which is formulated from server-side libraries and configurations as well as details in the Client Hello. Because TLS negotiations are transmitted in the clear (unencrypted), it’s possible to fingerprint and identify client applications using the details in the TLS Client Hello packet.
The JA3 method gathers the decimal values of the bytes for the following fields in the Client Hello packet: Version, Accepted Ciphers, List of Extensions, Elliptic Curves, and Elliptic Curve Formats. It then concatenates those values using a “,” to delimit each field and a “-” to delimit each value in each field. It then hashes the string into an easily consumable and shareable fingerprint.
We hash the fingerprint string because there’s no limit to how many ciphers or extensions can be added to the Client or Server Hello. Our rule of thumb is that if the fingerprint cannot fit in a tweet, it’s too long. We also hash the JA3 fingerprint so it can be more easily integrated into existing technologies.
The JA3S Standard
After creating JA3 we started playing with the same method to fingerprint the server side of the TLS handshake — the TLS Server Hello message. The JA3S method gathers the decimal values of the bytes for these fields in the Server Hello packet: Version, Accepted Cipher, and List of Extensions. It concatenates and hashes those values in the same way JA3 does on the client side.
Working on JA3S, we found the same server will generate its Server Hello message differently depending on the Client Hello message and its contents. It’s not possible to fingerprint a server based only on its Hello message as we could with clients and JA3. Nevertheless, we learned that although servers will respond to different clients differently, they always respond to the same client in the same way. This allows us to identify particular TLS clients and TLS flows with much greater fidelity.
I go into all of this much more deeply in the tech talk, covering:
- How TLS works
- Fingerprinting TLS with JA3/S
- Threats that can be detected with fingerprinting
- How SSH works
- Fingerprinting SSH and detecting threats with HASSH