Jacob Krasnov | Anthony Rose

JA3/S signatures have become a popular Indicator of Compromise (IOC) and have been incorporated into everything from Splunk to advanced IDS/IPS products like Darktrace. We presented a JA3 signature evasion technique at DEF CON 27 as part of a talk at the Recon Village but wanted to share more info on what JA3 signatures are, and why they can be effective, especially against mass deployed malware. The instrumental success of JA3 signatures is unquestionable, however, it is trivial for an Advanced Persistent Threat (APT) to modify these signatures to evade detection.

TLS/SSL Handshakes and JA3

The TLS/SSL protocol enables encrypted comms, whether that be HTTPS, SSH, or any other. The obvious benefit of this encryption is that it prevents others from being able to see what you are doing. This has made it a popular choice for malware as IDS systems are often unable to detect what is going on. A secure connection is initiated through a 3-way handshake that occurs immediately after the initial TCP handshake. However, there is a significant amount of additional information transmitted in the various stages of this handshake (e.g., cipher suites, keys, and certificates).

The process is started by the client sending a Client Hello packet to the server. This packet includes the set of cipher suites the client accepts, what TLS version is expected, and other details required to negotiate the secure connection. The second step is the reply from the server with the Server Hello packet. This packet contains the selected cipher suite, any accepted extensions, a few other bits of information, and the server certificate. The final step is the client verifying the server’s certificate and then passing the session keys in the Client Finished message.

Image from TheSSLStore.com

JA3 is a method of fingerprinting this handshake that was first published by John Althouse, Jeff Atkinson, and Josh Atkins from Salesforce, hence the name, back in 2017. It came about as a proposed solution to identifying malicious encrypted traffic. Research published by the Akamai Threat Research group has found that more than 80% of malicious traffic is now conducted over encrypted channels.

Salesforce’s analysis of TLS/SSL traffic initially developed a method for identifying the client application. They wanted to create a technique that resulted in an MD5 hash due to the simplicity and compatibility with a vast number of existing products. They quickly identified that hashing the entire Client Hello didn’t work because of unpredictable changes in the packet fields. However, they were able to locate that some of the fields are dictated by libraries and methods used to build the application. As a result, these fields are consistent between each connection. Specifically, they identified that the TLS version, cipher suites, elliptical curves extensions, Elliptic Curve point formats, and the length of the extensions could be used to produce an MD5 hash that is cataloged to identify the application. For a more detailed explanation of how exactly the MD5 hash is computed, check out the Salesforce article on it here. That article is also where we got this nifty image below that shows the fields from a Wireshark capture.

Image from https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967

However, this is only one piece of the puzzle when it comes to identifying malicious actors because the same application can be used for a multitude of purposes. For example, a JA3 hash could be used to identify that Internet Explorer was the application establishing an encrypted connection, but there would be no way to determine if the traffic was a user surfing the internet or malware using Internet Explorer for Command and Control (C2). To help address this problem, Salesforce also developed the JA3S signature to pair with JA3.

The researchers attempted to use the same principles in the JA3S signature as in the JA3, but it turns out that all fields in the Server Hello packet change based on the contents of the Client Hello. This was problematic because the whole concept of JA3 is that a single MD5 hash can be used to identify the application and server conducting the handshake quickly. After further research though, Salesforce found that while a server’s response changes between different applications, the response remains constant to any single application. For example, an Apache server will respond to an Internet Explorer’s Client Hello, in the same way, every time. The JA3/JA3S pairing allows for future identification of the application and server pairing even though the JA3S signature varies depending upon the Client Hello.

How well do JA3/JA3S signatures work?

Salesforce provides a couple of use cases for JA3/JA3S and an anecdote of how they were able to use it for hunting Pen Testers during an engagement. The first use case they give is identifying anomalous activity since custom malware will often have a unique JA3 signature. This is a result of many malware developers taking shortcuts in the robustness of their TLS negotiation (they only need it to be compatible with their C2 server and not a wide range of applications/servers). Salesforce acknowledges that JA3 alone becomes problematic when the attacker uses something like common python SSL libraries or a Windows secure socket, a problem JA3S helps solve.

It turns out that the way the C2 server in Kali responds is unique compared to how a typical server would respond. As a result, they were able to use the unique JA3/JA3S signature pairing to identify and remove the Pen Testers regardless of the domain, IP address, or certificates. At first glance, it is a robust detection method, especially when you aren’t aware of it. We first encountered this method last summer during an engagement, and it gave us a run for our money. After the engagement, we began doing some research on how we could potentially evade it.

Evading JA3 signatures

Before getting into the evasion example, we want to clarify that we are only talking about breaking the cataloged signatures before we get into evading JA3/S Signatures. In extremely locked-down environments, the SOC could still theoretically hunt for threats by looking for uncatalogued pairing but as described here there are legitimate reasons that JA3 signatures for an application can change, so trying to hunt for any anomalous pairings would likely be very noisy. As a result, merely changing the pairing signature is typically enough to evade detection. It is theoretically possible to rebuild the entire handshake signature, but that is a much more involved project then we will be discussing.

Two significant factors make evading known signatures relatively trivial for attackers. The aforementioned fact that neither the attacker’s server nor their client has to be compatible with anything except the attack infrastructure. Besides, the attackers (in most cases) have access to the source code of their tools. Given these two conditions, it becomes trivial to evade hunting via cataloged JA3. Now let’s retake a look at the fields used in the Client Hello for the JA3 hash.

Image from https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967

The Cipher Suites list is the most likely candidate to change from all the fields. That is because the C2 server can be located anywhere in this list without negatively impacting the connection. However, the order of the list and location of the cipher can drastically affect the hash. This gives us a lot of entropy to make sure our signature doesn’t match.

For example, Powershell Empire works by deploying a Powershell based agent directly into memory. We would need to be able to modify the list of cipher suites that the target OS uses for negotiation if we wanted to change our JA3 signature. Powershell has a built-in Cmdlet for precisely this purpose. Enable-TLSCipher Suite can be used to modify the ciphers that Windows will use for secure sockets and the priority order of the ciphers. Unfortunately, Windows requires that you be an Administrator to be able to modify the secure cipher list and our research did not reveal any published methods of circumventing this restriction. Fortunately, though, there is another field that is extremely easy to modify, and it doesn’t require Admin privileges to do so: TLS version field. The default setting for Powershell Empire is to use TLS 1.1. We can add a single line of code to the stager to force it to use TLS 1.2 instead which changes our JA3 signature.

JA3/S Pairing and Evasion

Simply changing to TLS 1.2 will most likely not gain you much because Windows 10 typically won’t allow TLS 1.1 connections. As a result, people have made this modification to get Empire working again in the labs. More than likely, the JA3/S pairing with the TLS 1.2 modification probably exists and would be caught. So, instead let’s modify our JA3S signature as well and see the result.

If you remember earlier, we said the Server Hello response is dictated by the Client Hello, but this is only partially true. In reality, the Client Hello limits what cipher the server can select. It looks at the Client Hello and optimizes the cipher chosen to be the highest desired cipher by comparing the respective lists from the server and client. Powershell Empire uses a Python flask server for the HTTP server, and it supports a large number of ciphers to ensure the broadest cross-section of compatibility. The Python library allows us to set the cipher list that we wish to use. We bypass the selection process by setting our server list to a single cipher since we only need to compatible with the Powershell secure socket.

We performed a Wireshark capture and selected ECDHE-RSA-AES128-GCM-SHA256 due to it being used across webpages and not being used for any Powershell server connections. Choosing an uncommon pair would allow us to maximize our chances of having unique JA3/JA3S signatures. However, any non-default selection for the Python flask server and Powershell would suffice. The modification to the Empire server requires entering context.set_ciphers(“EDHE-RSA-AES128-GSM-SHA256”) into the http.py file.

And that’s it, and now we have an implementation for Empire that is not in a JA3/S database and won’t be flagged as malicious immediately.

Wrap-Up