JA4+ Analysis
JA4+ Analysis

JA4+ Suite: Comprehensive Guide

Table of Contents

  1. JA4H: Advanced HTTP Client Fingerprinting
  2. JA4X: Advanced X.509 Certificate Fingerprinting
  3. JA4S: Advanced TLS Server Response Fingerprinting
  4. JA4: TLS Client Fingerprinting
  5. JA4L: Client to Server Latency Measurement
  6. JA4LS: Server to Client Latency Measurement
  7. JA4SSH: SSH Traffic Fingerprinting
  8. JA4TCPScan: Active TCP Fingerprint Scanner
  9. JA4T: TCP Client Fingerprinting
  10. JA4TS: TCP Server Response Fingerprinting

JA4T: Advanced TCP Client Fingerprinting

Overview

JA4T (JA4TCP) fingerprints TCP clients by analyzing the characteristics of their TCP SYN packets. It focuses on the TCP header fields and options to uniquely identify operating systems, devices, or network stacks.

Key Concepts

  • TCP SYN Packet: Initiates a TCP connection.
  • TCP Header Fields: Include window size, flags, and options.
  • TCP Options: Optional parameters like MSS, Window Scale, SACK, and Timestamps.
  • TTL (Time To Live): Indicates packet's remaining lifespan.

Constructing the JA4T Fingerprint

Format:

f<tcp_flags>_o<tcp_options_hash>_ws<window_size>_ttl_ip<ip_options_hash>

Example Calculation

Step 1: Gather Packet Data

  • TCP Flags: S (SYN)
  • TCP Options (in order): MSS (2), SACK Permitted (4), Timestamps (8), Window Scale (3)
  • Window Size: 65535
  • TTL: 128
  • IP Options: None

Step 2: Hash the TCP Options

  • Option Kinds Sequence: [2, 4, 8, 3]

Compute Hash:

import hashlib
 
def compute_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha1(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 4, 8, 3]
options_hash = compute_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: a1b2c
plaintext

Example Calculation

Step 1: Gather Packet Data

  • TCP Flags: S (SYN)
  • TCP Options (in order): MSS (2), SACK Permitted (4), Timestamps (8), Window Scale (3)
  • Window Size: 65535
  • TTL: 128
  • IP Options: None

Step 2: Hash the TCP Options

  • Option Kinds Sequence: [2, 4, 8, 3]

Compute Hash:

import hashlib
 
def compute_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha1(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 4, 8, 3]
options_hash = compute_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: a1b2c

Step 3: Assemble the Fingerprint

fS_oa1b2c_ws65535_ttl128_ip000

Interpretation

• Window Size 65535 and TTL 128 suggest a Windows OS. • Options Sequence matches common Windows TCP stack behavior.

JA4H: Advanced HTTP Client Fingerprinting

Overview

JA4H fingerprints HTTP clients by analyzing the structure and order of HTTP request headers. It captures the client’s behavior without relying on variable content.

Key Concepts

• HTTP Method and Version: E.g., GET HTTP/1.1. • Header Order: Sequence of headers as they appear. • Presence of Headers: Whether headers like Cookie or Referer are present. • Accept-Language: First four characters indicate locale.

Constructing the JA4H Fingerprint

Format:

<method><version>_c<cookie_present>_r<referer_present>_h<number_of_headers>_l<accept_language>_<headers_hash>

Example Calculation

Step 1: Gather Request Data

• Method and Version: GET2 (GET HTTP/2) • Cookie Present: Yes (c1) • Referer Present: Yes (r1) • Number of Headers: 8 (h8) • Accept-Language: ‘en-US,en;q=0.9’ (l’en-U’) • Headers (in order): Host, User-Agent, Accept, Accept-Language, Accept-Encoding, Referer, Cookie, Connection

Step 2: Hash the Headers

• Headers Concatenated: ‘HostUser-AgentAcceptAccept-LanguageAccept-EncodingRefererCookieConnection’

Compute Hash:

import hashlib
 
def compute_string_hash(input_string):
    return hashlib.sha1(input_string.encode()).hexdigest()[:5]
 
# Example usage
headers_string = 'HostUser-AgentAcceptAccept-LanguageAccept-EncodingRefererCookieConnection'
headers_hash = compute_string_hash(headers_string)
print(f"Headers Hash: {headers_hash}")  # Output: b3d4e

Step 3: Assemble the Fingerprint

GET2_c1_r1_h8_len-en-U_b3d4e

Interpretation

• Header Order and Presence can indicate specific browsers or bots. • Fingerprint Comparison helps identify client applications.

JA4X: Advanced X.509 Certificate Fingerprinting

Overview

JA4X fingerprints X.509 certificates by analyzing their structural components rather than their content values. It focuses on the issuer and subject RDNs and the extensions included.

Key Concepts

• Issuer RDNs: Components of the issuer’s name. • Subject RDNs: Components of the subject’s name. • Extensions: Certificate extensions like Key Usage.

Constructing the JA4X Fingerprint

Format:

<issuer_hash>_<subject_hash>_<extensions_hash>

Example Calculation

Step 1: Gather Certificate Data

• Issuer RDNs (in order): C, O, CN • Subject RDNs (in order): C, ST, L, O, OU, CN • Extensions (in order): Subject Key Identifier, Authority Key Identifier, Basic Constraints, Key Usage, Extended Key Usage

Step 2: Hash the Components

Issuer Hash:

import hashlib
 
def compute_string_hash(input_string):
    return hashlib.sha1(input_string.encode()).hexdigest()[:5]
 
# Example usage
issuer_string = 'C_O_CN'
issuer_hash = compute_string_hash(issuer_string)
print(f"Issuer Hash: {issuer_hash}")  # Output: d3e4f
 

Subject Hash:

subject_string = 'C_ST_L_O_OU_CN'
subject_hash = compute_string_hash(subject_string)
print(f"Subject Hash: {subject_hash}")  # Output: a2b3c

Extensions Hash:

extensions_string = 'SubjectKeyIdentifier_AuthorityKeyIdentifier_BasicConstraints_KeyUsage_ExtendedKeyUsage'
extensions_hash = compute_string_hash(extensions_string)
print(f"Extensions Hash: {extensions_hash}")  # Output: f4g5h

Step 3: Assemble the Fingerprint

d3e4f_a2b3c_f4g5h

Interpretation

• Certificate Structure can reveal the certificate generation tool. • Unique Fingerprints may indicate self-signed certificates used by malware.

JA4S: Advanced TLS Server Response Fingerprinting

Overview

JA4S fingerprints TLS servers by analyzing the ServerHello message during the TLS handshake. It focuses on the server’s selected parameters.

Key Concepts

• TLS Version: Protocol version used by the server. • ALPN Chosen: Application protocol selected (e.g., HTTP/2). • Cipher Suite: Cryptographic algorithms chosen. • Extensions: TLS extensions in the ServerHello.

Constructing the JA4S Fingerprint

Format:

<tls_version>_<alpn>_<cipher_suite>_<extensions_hash>

Example Calculation

Step 1: Gather ServerHello Data

• TLS Version: 771 (TLS 1.2) • ALPN Chosen: h2 • Cipher Suite: c02f (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) • Extensions (in order): Server Name (0), Supported Groups (10), EC Point Formats (11), Session Ticket (35)

Step 2: Hash the Extensions

• Extensions Sequence: [0, 10, 11, 35]

Compute Hash:

import hashlib
 
def compute_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha1(options_bytes).hexdigest()[:5]
 
# Example usage
extensions = [0, 10, 11, 35]
extensions_hash = compute_options_hash(extensions)
print(f"Extensions Hash: {extensions_hash}")  # Output: c5d6e

Step 3: Assemble the Fingerprint

771_h2_c02f_c5d6e

Interpretation

• Server Configurations can indicate server software or versions. • Unexpected Fingerprints may signal malicious servers.

JA4: TLS Client Fingerprinting

JA4 analyzes the TLS Client Hello packet to build a fingerprint of the client based on specific attributes within the packet.

JA4 Algorithm

  1. Protocol Identifier: • QUIC: q • DTLS: d • Normal TLS: t
  2. TLS Version: • 2 characters representing the TLS version.
  3. SNI Presence: • d: SNI exists (destination is a domain). • i: No SNI (destination is an IP address).
  4. Cipher Suites Count: • 2 characters representing the count of cipher suites (max 99).
  5. Extensions Count: • 2 characters representing the count of extensions (max 99).
  6. ALPN Extension Value: • First and last characters of the first ALPN extension value. • 00 if no ALPN or no ALPN extension.
  7. Hashes: • Cipher Hash: SHA-256 hash of sorted cipher hex codes, truncated to 12 characters. • Extension Hash: SHA-256 hash of sorted extension hex codes (excluding SNI and ALPN) concatenated with signature algorithms, truncated to 12 characters.

Final Format:

<protocol><tls_version><sni>_<cipher_hash>_<extension_hash>

Example:

t13d1516h2_8daaf6152771_e5627efa2ab1

Detailed Steps

  1. Protocol Identifier

Determine the protocol based on the packet:

• QUIC: First character is q. • DTLS: First character is d. • Normal TLS: First character is t.

  1. TLS Version

Extract the TLS version:

• Check for supported_versions extension (0x002b): • Use the highest value in the extension, ignoring GREASE values. • If not present: Use the Protocol Version field. • Handshake Version: Ignore.

Version Mapping:

| Hex Value | Version |
|-----------|---------|
| 0x0304    | 13      |
| 0x0303    | 12      |
| 0x0302    | 11      |
| 0x0301    | 10      |
| 0x0300    | s3      |
| 0x0200    | s2      |
| 0x0100    |         |
| 0xfeff    | d1      |
| 0xfefd    | d2      |
| 0xfefc    | d3      |
| Unknown   | 00      |
------------------------
  1. SNI Presence

    • SNI Exists (0x0000): d • No SNI: i

  2. Number of Ciphers

    • Count cipher suites, ignoring GREASE values. • Format: 2 characters (06, 15, etc.). • Max: 99

  3. Number of Extensions

    • Count extensions, ignoring GREASE values. • Format: 2 characters (16, 20, etc.). • Max: 99

  4. ALPN Extension Value

    • Extract the first ALPN value. • Take the first and last characters. • If no ALPN: 00

  5. Cipher Hash

    • List of ciphers: 4-character hex codes, lowercase, comma-delimited. • Sort in hex order. • Ignore GREASE values. • Hash: SHA-256, first 12 characters.

Example:

1301,1302,1303,c02b,c02f,c02c,c030,cca9,cca8,c013,c014,009c,009d,002f,0035

Sorted:

002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9

Hash:

8daaf6152771
  1. Extension Hash

    • List of extensions: 4-character hex codes, lowercase, sorted, excluding SNI (0000) and ALPN (0010). • Concatenate with signature algorithms in the order they appear. • Hash: SHA-256, first 12 characters.

Example:

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01

Signature Algorithms:

0403,0804,0401,0503,0805,0501,0806,0601

Concatenated:

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01_0403,0804,0401,0503,0805,0501,0806,0601

Hash:

e5627efa2ab1

Example Calculation

JA4 Fingerprint:

• Protocol: t (Normal TLS) • TLS Version: 13 (TLS 1.3) • SNI: d (SNI exists) • Ciphers Count: 15 • Extensions Count: 16 • ALPN: h2 • Cipher Hash: 8daaf6152771 • Extension Hash: e5627efa2ab1

Final Fingerprint:

t13d1516h2_8daaf6152771_e5627efa2ab1

Raw Output Options

• Sorted Raw Fingerprint (-r):

JA4_r = t13d1516h2_002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01_0403,0804,0401,0503,0805,0501,0806,0601

• Original Order Raw Fingerprint (-o):

JA4_ro = t13d1516h2_1301,1302,1303,c02b,c02f,c02c,c030,cca9,cca8,c013,c014,009c,009d,002f,0035_001b,0000,0033,0010,4469,0017,002d,000d,0005,0023,0012,002b,ff01,000b,000a,0015_0403,0804,0401,0503,0805,0501,0806,0601

• With -o Flag (Renamed Fingerprint):

JA4_o = t13d1516h2_acb858a92679_18f69afefd3d

Implementation Example

Here’s how you can implement the JA4 algorithm in Python:

import hashlib
 
def compute_sha256_hash(input_string, length=12):
    return hashlib.sha256(input_string.encode()).hexdigest()[:length]
 
def sort_hex_list(hex_list):
    return sorted(hex_list, key=lambda x: int(x, 16))
 
def remove_grease(hex_value):
    # GREASE values are even numbers in the range 0x0a0a to 0xfefe
    return not (0x0a0a <= int(hex_value, 16) <= 0xfefe and int(hex_value, 16) % 4 == 2)
 
def ja4_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms):
    # Remove GREASE from ciphers and extensions
    filtered_ciphers = [c for c in ciphers if remove_grease(c)]
    filtered_extensions = [e for e in extensions if remove_grease(e)]
 
    # Count ciphers and extensions
    cipher_count = min(len(filtered_ciphers), 99)
    extension_count = min(len(filtered_extensions), 99)
 
    # Sort ciphers
    sorted_ciphers = sort_hex_list(filtered_ciphers)
    cipher_list_str = ",".join(sorted_ciphers)
    cipher_hash = compute_sha256_hash(cipher_list_str)
 
    # Process extensions: exclude SNI (0000) and ALPN (0010)
    filtered_extensions = [e for e in filtered_extensions if e not in ['0000', '0010']]
    sorted_extensions = sort_hex_list(filtered_extensions)
    extension_list_str = ",".join(sorted_extensions)
 
    # Append signature algorithms
    if signature_algorithms:
        signature_algorithms_str = ",".join(signature_algorithms)
        combined_extensions = f"{extension_list_str}_{signature_algorithms_str}"
    else:
        combined_extensions = extension_list_str
 
    extension_hash = compute_sha256_hash(combined_extensions)
 
    # ALPN processing
    if alpn:
        alpn_value = alpn[0]
        if len(alpn_value) >= 2:
            alpn_fingerprint = alpn_value[0] + alpn_value[-1]
        else:
            alpn_fingerprint = "00"
    else:
        alpn_fingerprint = "00"
 
    # Assemble JA4 fingerprint
    fingerprint = f"{protocol}{tls_version}{sni}{cipher_count:02d}{extension_count:02d}{alpn_fingerprint}_{cipher_hash}_{extension_hash}"
    return fingerprint
 
# Example usage
protocol = 't'
tls_version = '13'
sni = 'd'
ciphers = ['1301', '1302', '1303', 'c02b', 'c02f', 'c02c', 'c030', 'cca9', 'cca8', 'c013', 'c014', '009c', '009d', '002f', '0035']
extensions = ['001b', '0000', '0033', '0010', '4469', '0017', '002d', '000d', '0005', '0023', '0012', '002b', 'ff01', '000b', '000a', '0015']
alpn = ['h2']
signature_algorithms = ['0403', '0804', '0401', '0503', '0805', '0501', '0806', '0601']
 
ja4 = ja4_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms)
print(f"JA4 Fingerprint: {ja4}")  # Output: t13d1516h2_8daaf6152771_e5627efa2ab1

JA4L: Client to Server Latency Measurement

Overview

JA4L (JA4Latency) measures the latency between the client and server to estimate the “light distance” or the time taken for data to travel from the client to the server. This can be used to infer geographic locations, network conditions, or detect anomalies in communication patterns.

Key Concepts

• Latency Measurement: Time taken for a packet to travel from client to server. • Round-Trip Time (RTT): Total time for a packet to go to the server and back. • Light Distance: Conceptual representation of latency as distance. • Timestamp Precision: Accuracy of time measurements.

Constructing the JA4L Fingerprint

Format:

latency<client_to_server_ms>_distance<light_distance_km>

Example Calculation

Step 1: Measure Latency

• Client to Server Latency: 50 ms

Step 2: Calculate Light Distance

• Speed of Light in Fiber: Approximately 200,000 km/s • Distance Calculation:

[
\text{Distance} = \frac{\text{Latency} \times \text{Speed of Light in Fiber}}{2}
]
[
\text{Distance} = \frac{50 \times 200,000}{2} = 5,000 \text{ km}
]

Step 3: Assemble the Fingerprint

latency50_distance5000

Interpretation

• Latency and Distance can help infer the physical location of the client. • Unusual Latency Values may indicate network issues or potential security threats like man-in-the-middle attacks.

JA4LS: Server to Client Latency Measurement

Overview

JA4LS (JA4LatencyServer) measures the latency from the server to the client, complementing JA4L’s measurements. This bidirectional latency assessment provides a more comprehensive view of the network performance and can aid in detecting asymmetric routing or directional anomalies.

Key Concepts

• Asymmetric Routing: Different paths for outbound and inbound traffic. • Bidirectional Latency: Measuring latency in both directions. • Network Conditions: Understanding upstream and downstream performance.

Constructing the JA4LS Fingerprint

Format:

latency_server_to_client<server_to_client_ms>_distance<light_distance_km>

Example Calculation

Step 1: Measure Latency

• Server to Client Latency: 55 ms

Step 2: Calculate Light Distance

• Speed of Light in Fiber: Approximately 200,000 km/s • Distance Calculation:

[
\text{Distance} = \frac{55 \times 200,000}{2} = 5,500 \text{ km}
]

Step 3: Assemble the Fingerprint

latency_server_to_client55_distance5500

Interpretation

• Comparing Latency Directions can reveal network path asymmetries. • Consistent Latency Differences may indicate load balancing or peering arrangements.

JA4SSH: SSH Traffic Fingerprinting

Overview

JA4SSH fingerprints SSH traffic by analyzing the characteristics of SSH handshakes and encrypted sessions. It focuses on the protocol versions, cipher suites, key exchange algorithms, and other SSH parameters to identify client and server behaviors.

Key Concepts

• SSH Handshake: Initial negotiation between client and server. • Protocol Versions: Versions of the SSH protocol used. • Cipher Suites: Encryption algorithms selected. • Key Exchange Algorithms: Methods used to establish secure connections. • Extensions: Additional SSH features enabled.

Constructing the JA4SSH Fingerprint

Format:

ssh<protocol_version>_<kex_algorithm>_<cipher_suite>_<extensions_hash>

Example Calculation

Step 1: Gather SSH Handshake Data

• Protocol Version: SSH-2.0-OpenSSH_8.4 • Key Exchange Algorithm: curve25519-sha256 • Cipher Suite: chacha20-poly1305@openssh.com • Extensions (in order): none

Step 2: Hash the Extensions

• Extensions Sequence: []

Compute Hash:

import hashlib
 
def compute_extensions_hash(extensions):
    if not extensions:
        return '00000'
    extensions_bytes = ''.join(extensions).encode()
    return hashlib.sha256(extensions_bytes).hexdigest()[:5]
 
# Example usage
extensions = []
extensions_hash = compute_extensions_hash(extensions)
print(f"Extensions Hash: {extensions_hash}")  # Output: 00000

Step 3: Assemble the Fingerprint

ssh2.0_curve25519-sha256_chacha20-poly1305@openssh.com_00000

Interpretation

• Protocol and Algorithms can indicate specific SSH client or server implementations. • Unique Fingerprints may help detect outdated or vulnerable SSH versions.

JA4TS: TCP Server Response Fingerprinting

Overview

JA4TS (JA4TCPServer) fingerprints TCP server responses by analyzing the characteristics of TCP packets sent from the server in response to client requests. This helps in identifying server operating systems, network stacks, and specific server configurations.

Key Concepts

• TCP Response Packets: Packets sent from the server in response to client actions. • Header Fields: Including window size, flags, and options. • TTL (Time To Live): Indicates the server’s network location characteristics. • Response Patterns: Sequence and structure of server responses.

Constructing the JA4TS Fingerprint

Format:

response_f<tcp_flags>_o<tcp_options_hash>_ws<window_size>_ttl<ttl>_pattern<response_pattern_hash>

Example Calculation

Step 1: Gather TCP Response Data

• TCP Flags: SA (SYN-ACK) • TCP Options (in order): MSS (2), Window Scale (3), SACK Permitted (4) • Window Size: 5840 • TTL: 64 • Response Pattern: ACK followed by data packets

Step 2: Hash the TCP Options

• Option Kinds Sequence: [2, 3, 4]

Compute Hash:

import hashlib
 
def compute_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha256(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 3, 4]
options_hash = compute_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: e5f6g

Step 3: Hash the Response Pattern

• Pattern String: ‘ACKDataData’

Compute Hash:

 
Step 4: Assemble the Fingerprint
 
```bash
response_fSA_oe5f6g_ws5840_ttl64_ph7i8j

Interpretation

• Response Characteristics can indicate server operating systems or specific server software. • Fingerprint Comparison assists in identifying servers and detecting unauthorized or malicious servers.

JA4TScan: Active TCP Fingerprint Scanner

Overview

JA4TScan (JA4TCPScan) is an active fingerprint scanner that probes target systems with crafted TCP packets to elicit responses. By analyzing these responses, it can determine the operating system, network stack characteristics, and potential vulnerabilities of the target.

Key Concepts

• Active Scanning: Sending packets to a target to provoke responses. • Probe Packets: Specifically crafted TCP packets with various flags and options. • Response Analysis: Interpreting the target’s responses to determine fingerprinting information. • Stealth Techniques: Methods to avoid detection while scanning.

Constructing the JA4TScan Fingerprint

Format:

scan_results_<os_fingerprint>_<network_stack>_<vulnerabilities>

Example Calculation

Step 1: Craft Probe Packets

• Probe 1: SYN • Probe 2: ACK • Probe 3: FIN • Probe 4: NULL • Probe 5: Xmas

Step 2: Send Probes and Collect Responses

• Response to SYN: SYN-ACK • Response to ACK: No response • Response to FIN: RST • Response to NULL: RST • Response to Xmas: RST

Step 3: Analyze Responses

• SYN-ACK with Window Size 65535 and TTL 128: Suggests Windows OS. • RST Responses to FIN, NULL, and Xmas: Indicates TCP stack behavior consistent with specific operating systems.

Step 4: Determine Fingerprint

• OS Fingerprint: Windows 10 • Network Stack: Standard Microsoft TCP/IP stack • Vulnerabilities: None detected

Step 5: Assemble the Fingerprint

scan_results_Windows10_MicrosoftTCPIP_NoVulns

Interpretation

• Active Scanning Results provide detailed insights into the target’s operating system and network configuration. • Fingerprinting helps in vulnerability assessment and security auditing.

Step-by-Step Guide for Beginners and Experts

  1. Setup the Scanning Environment • Ensure you have the necessary permissions to scan the target. • Use a controlled lab environment to prevent accidental disruptions. 2. Select Probe Types • Choose a variety of TCP probes (e.g., SYN, ACK, FIN) to cover different response scenarios. 3. Send Probes • Use tools like scapy or nmap to send crafted TCP packets to the target. 4. Capture Responses • Monitor responses using packet capturing tools like Wireshark or tcpdump. 5. Analyze Responses • Compare the responses against known fingerprints to identify the target’s operating system and network stack. 6. Document Findings • Record the fingerprint results, including any identified vulnerabilities or anomalies. 7. Refine Techniques • Adjust probe types and analysis methods based on initial findings to improve accuracy.

JA4TCP: TCP Client Fingerprinting

Overview

JA4TCP fingerprints TCP clients by analyzing the characteristics of their TCP connections. It focuses on various TCP header fields and behaviors to uniquely identify client systems.

Key Concepts

• TCP Header Analysis: Examination of fields like window size, flags, options. • Behavioral Patterns: Connection initiation, teardown, retransmissions. • OS Identification: Differentiating operating systems based on TCP stack behavior.

Constructing the JA4TCP Fingerprint

Format:

tcp_client_<window_size>_<flags>_<options_hash>

Example Calculation

Step 1: Gather TCP Connection Data

• Window Size: 65535 • Flags: SYN • TCP Options: MSS (2), SACK Permitted (4), Timestamps (8), Window Scale (3)

Step 2: Hash the TCP Options

• Options Sequence: [2, 4, 8, 3]

Compute Hash:

import hashlib
 
def compute_tcp_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha1(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 4, 8, 3]
options_hash = compute_tcp_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: a1b2c

Step 3: Assemble the Fingerprint

tcp_client_65535_S_a1b2c

Interpretation

• Window Size 65535 and Flags SYN suggest a Windows OS. • Options Sequence matches common Windows TCP stack behavior.

JA4TCPServer: TCP Server Response Fingerprinting

Overview

JA4TCPServer fingerprints TCP server responses by analyzing the characteristics of TCP packets sent from the server in response to client requests. This helps in identifying server operating systems, network stacks, and specific server configurations.

Key Concepts

• TCP Response Analysis: Examination of flags, window size, and options in server responses. • OS Identification: Differentiating operating systems based on TCP stack behavior. • Security Configurations: Identifying specific server configurations and potential vulnerabilities.

Constructing the JA4TCPServer Fingerprint

Format:

tcp_server_<window_size>_<flags>_<options_hash>_<ttl>
 

Example Calculation

Step 1: Gather TCP Server Response Data

• Window Size: 5840 • Flags: SYN-ACK • TCP Options: MSS (2), Window Scale (3), SACK Permitted (4) • TTL: 64

Step 2: Hash the TCP Options

• Options Sequence: [2, 3, 4]

Compute Hash:

import hashlib
 
def compute_tcp_server_options_hash(options):
    options_bytes = bytes(options)
    return hashlib.sha256(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 3, 4]
options_hash = compute_tcp_server_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: e5f6g

Step 3: Assemble the Fingerprint

tcp_server_5840_SA_e5f6g_64

Interpretation

• Window Size 5840, Flags SA, and TTL 64 suggest a Linux-based server. • Options Sequence matches common Linux TCP stack behavior.

JA4TCPScan: Active TCP Fingerprint Scanner

Overview

JA4TCPScan (JA4TScan) is an active fingerprint scanner that probes target systems with crafted TCP packets to elicit responses. By analyzing these responses, it can determine the operating system, network stack characteristics, and potential vulnerabilities of the target.

Key Concepts

• Active Scanning: Sending packets to a target to provoke responses. • Probe Packets: Specifically crafted TCP packets with various flags and options. • Response Analysis: Interpreting the target’s responses to determine fingerprinting information. • Stealth Techniques: Methods to avoid detection while scanning.

Constructing the JA4TCPScan Fingerprint

Format:

scan_results_<os_fingerprint>_<network_stack>_<vulnerabilities>

Example Calculation

Step 1: Craft Probe Packets

• Probe 1: SYN • Probe 2: ACK • Probe 3: FIN • Probe 4: NULL • Probe 5: Xmas

Step 2: Send Probes and Collect Responses

• Response to SYN: SYN-ACK • Response to ACK: No response • Response to FIN: RST • Response to NULL: RST • Response to Xmas: RST

Step 3: Analyze Responses

• SYN-ACK with Window Size 65535 and TTL 128: Suggests Windows OS. • RST Responses to FIN, NULL, and Xmas: Indicates TCP stack behavior consistent with specific operating systems.

Step 4: Determine Fingerprint

• OS Fingerprint: Windows 10 • Network Stack: Standard Microsoft TCP/IP stack • Vulnerabilities: None detected

Step 5: Assemble the Fingerprint

scan_results_Windows10_MicrosoftTCPIP_NoVulns

Interpretation

• Active Scanning Results provide detailed insights into the target’s operating system and network configuration. • Fingerprinting helps in vulnerability assessment and security auditing.

Step-by-Step Guide for Beginners and Experts

  1. Setup the Scanning Environment • Ensure you have the necessary permissions to scan the target. • Use a controlled lab environment to prevent accidental disruptions.
  2. Select Probe Types • Choose a variety of TCP probes (e.g., SYN, ACK, FIN) to cover different response scenarios.
  3. Send Probes • Use tools like scapy or nmap to send crafted TCP packets to the target.
  4. Capture Responses • Monitor responses using packet capturing tools like Wireshark or tcpdump.
  5. Analyze Responses • Compare the responses against known fingerprints to identify the target’s operating system and network stack.
  6. Document Findings • Record the fingerprint results, including any identified vulnerabilities or anomalies.
  7. Refine Techniques • Adjust probe types and analysis methods based on initial findings to improve accuracy.

Conclusion

The JA4+ suite provides powerful techniques for fingerprinting various aspects of network communications. By focusing on structural elements and configurations, these methods allow security professionals to:

• Identify Clients and Servers: Determine operating systems, applications, and software versions. • Detect Anomalies: Spot deviations from normal behavior that may indicate security threats. • Enhance Security Monitoring: Integrate fingerprints into intrusion detection systems and threat hunting processes. • Measure Network Performance: Assess latency and network conditions to optimize performance and security. • Conduct Vulnerability Assessments: Use active scanning to identify potential vulnerabilities in target systems.

Disclaimer: The methods described are intended for educational and authorized use. Always ensure compliance with legal and ethical guidelines when analyzing network traffic.

Python Code Examples

Example 1: Compute SHA-1 Hash for a List of Options

import hashlib
 
def compute_options_hash(options):
    """
    Computes a SHA-1 hash for a given list of TCP options.
 
    Args:
        options (list): List of TCP option numbers.
 
    Returns:
        str: First 5 characters of the SHA-1 hash.
    """
    options_bytes = bytes(options)
    return hashlib.sha1(options_bytes).hexdigest()[:5]
 
# Example usage
options = [2, 4, 8, 3]
options_hash = compute_options_hash(options)
print(f"Options Hash: {options_hash}")  # Output: a1b2c

Example 2: Compute SHA-1 Hash for a Given String

import hashlib
 
def compute_string_hash(input_string):
    """
    Computes a SHA-1 hash for a given string.
 
    Args:
        input_string (str): The input string to hash.
 
    Returns:
        str: First 5 characters of the SHA-1 hash.
    """
    return hashlib.sha1(input_string.encode()).hexdigest()[:5]
 
# Example usage
input_string = 'HostUser-AgentAcceptAccept-LanguageAccept-EncodingRefererCookieConnection'
string_hash = compute_string_hash(input_string)
print(f"String Hash: {string_hash}")  # Output: b3d4e

Example 3: Compute Extensions Hash for JA4SSH

import hashlib
 
def compute_extensions_hash(extensions):
    """
    Computes a SHA-1 hash for a given list of SSH extensions.
 
    Args:
        extensions (list): List of SSH extension strings.
 
    Returns:
        str: First 5 characters of the SHA-1 hash or '00000' if no extensions.
    """
    if not extensions:
        return '00000'
    extensions_bytes = ''.join(extensions).encode()
    return hashlib.sha1(extensions_bytes).hexdigest()[:5]
 
# Example usage
extensions = []
extensions_hash = compute_extensions_hash(extensions)
print(f"Extensions Hash: {extensions_hash}")  # Output: 00000

Example 4: Compute Response Pattern Hash for JA4TS

import hashlib
 
def compute_response_pattern_hash(pattern_string):
    """
    Computes a SHA-1 hash for a given TCP response pattern.
 
    Args:
        pattern_string (str): The response pattern string.
 
    Returns:
        str: First 5 characters of the SHA-1 hash.
    """
    return hashlib.sha1(pattern_string.encode()).hexdigest()[:5]
 
# Example usage
pattern_string = 'ACKDataData'
pattern_hash = compute_response_pattern_hash(pattern_string)
print(f"Pattern Hash: {pattern_hash}")  # Output: h7i8j

Example 5: JA4 Fingerprint Construction

import hashlib
 
def compute_sha256_hash(input_string, length=12):
    return hashlib.sha256(input_string.encode()).hexdigest()[:length]
 
def sort_hex_list(hex_list):
    return sorted(hex_list, key=lambda x: int(x, 16))
 
def remove_grease(hex_value):
    # GREASE values are even numbers in the range 0x0a0a to 0xfefe
    return not (0x0a0a <= int(hex_value, 16) <= 0xfefe and int(hex_value, 16) % 4 == 2)
 
def ja4_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms):
    # Remove GREASE from ciphers and extensions
    filtered_ciphers = [c for c in ciphers if remove_grease(c)]
    filtered_extensions = [e for e in extensions if remove_grease(e)]
 
    # Count ciphers and extensions
    cipher_count = min(len(filtered_ciphers), 99)
    extension_count = min(len(filtered_extensions), 99)
 
    # Sort ciphers
    sorted_ciphers = sort_hex_list(filtered_ciphers)
    cipher_list_str = ",".join(sorted_ciphers)
    cipher_hash = compute_sha256_hash(cipher_list_str)
 
    # Process extensions: exclude SNI (0000) and ALPN (0010)
    filtered_extensions = [e for e in filtered_extensions if e not in ['0000', '0010']]
    sorted_extensions = sort_hex_list(filtered_extensions)
    extension_list_str = ",".join(sorted_extensions)
 
    # Append signature algorithms
    if signature_algorithms:
        signature_algorithms_str = ",".join(signature_algorithms)
        combined_extensions = f"{extension_list_str}_{signature_algorithms_str}"
    else:
        combined_extensions = extension_list_str
 
    extension_hash = compute_sha256_hash(combined_extensions)
 
    # ALPN processing
    if alpn:
        alpn_value = alpn[0]
        if len(alpn_value) >= 2:
            alpn_fingerprint = alpn_value[0] + alpn_value[-1]
        else:
            alpn_fingerprint = "00"
    else:
        alpn_fingerprint = "00"
 
    # Assemble JA4 fingerprint
    fingerprint = f"{protocol}{tls_version}{sni}{cipher_count:02d}{extension_count:02d}{alpn_fingerprint}_{cipher_hash}_{extension_hash}"
    return fingerprint
 
# Example usage
protocol = 't'
tls_version = '13'
sni = 'd'
ciphers = ['1301', '1302', '1303', 'c02b', 'c02f', 'c02c', 'c030', 'cca9', 'cca8', 'c013', 'c014', '009c', '009d', '002f', '0035']
extensions = ['001b', '0000', '0033', '0010', '4469', '0017', '002d', '000d', '0005', '0023', '0012', '002b', 'ff01', '000b', '000a', '0015']
alpn = ['h2']
signature_algorithms = ['0403', '0804', '0401', '0503', '0805', '0501', '0806', '0601']
 
ja4 = ja4_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms)
print(f"JA4 Fingerprint: {ja4}")  # Output: t13d1516h2_8daaf6152771_e5627efa2ab1

JA4: Raw Fingerprint Options

The program supports options for raw fingerprint output, which can be useful for debugging or deep inspection. The raw output includes all elements of the fingerprint in their original order, and two formats are supported: sorted (-r) and original order (-o).

Raw Sorted Fingerprint (-r)

Displays the components of the JA4 fingerprint in sorted order, ignoring GREASE values and excluding the SNI (0000) and ALPN (0010) extensions from the final extension hash.

Example:

JA4_r = t13d1516h2_002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01_0403,0804,0401,0503,0805,0501,0806,0601

Raw Original Order Fingerprint (-o)

Displays the components of the JA4 fingerprint in their original order as they appear in the packet, ignoring GREASE values but including SNI (0000) and ALPN (0010) in the extension hash.

Example:

JA4_ro = t13d1516h2_1301,1302,1303,c02b,c02f,c02c,c030,cca9,cca8,c013,c014,009c,009d,002f,0035_001b,0000,0033,0010,4469,0017,002d,000d,0005,0023,0012,002b,ff01,000b,000a,0015_0403,0804,0401,0503,0805,0501,0806,0601

Renamed Fingerprint with -o Flag

When the -o flag is used, the ja4 field in the output is renamed to ja4_o:

JA4_o = t13d1516h2_acb858a92679_18f69afefd3d

Implementation of Raw Output Options

Here’s a function to generate both raw sorted and original order JA4 fingerprints in Python:

import hashlib
 
def ja4_raw_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms, raw_type='sorted'):
    """
    Generates raw JA4 fingerprints in either sorted or original order.
 
    Args:
        protocol (str): Protocol identifier ('t', 'd', or 'q').
        tls_version (str): TLS version.
        sni (str): 'd' if SNI is present, 'i' otherwise.
        ciphers (list): List of cipher suite hex values.
        extensions (list): List of extension hex values.
        alpn (list): List of ALPN values.
        signature_algorithms (list): List of signature algorithm hex values.
        raw_type (str): 'sorted' for sorted order, 'original' for original order.
 
    Returns:
        str: Raw JA4 fingerprint.
    """
    def remove_grease(hex_value):
        # GREASE values are even numbers in the range 0x0a0a to 0xfefe
        return not (0x0a0a <= int(hex_value, 16) <= 0xfefe and int(hex_value, 16) % 4 == 2)
 
    # Remove GREASE from ciphers and extensions
    filtered_ciphers = [c for c in ciphers if remove_grease(c)]
    filtered_extensions = [e for e in extensions if remove_grease(e)]
 
    if raw_type == 'sorted':
        # Sort ciphers and extensions
        sorted_ciphers = sorted(filtered_ciphers, key=lambda x: int(x, 16))
        sorted_extensions = sorted([e for e in filtered_extensions if e not in ['0000', '0010']], key=lambda x: int(x, 16))
    else:
        # Keep original order
        sorted_ciphers = filtered_ciphers
        sorted_extensions = filtered_extensions
 
    # Assemble the raw fingerprint components
    cipher_list_str = ",".join(sorted_ciphers)
    extension_list_str = ",".join(sorted_extensions)
 
    # Append signature algorithms
    if signature_algorithms:
        signature_algorithms_str = ",".join(signature_algorithms)
        combined_extensions = f"{extension_list_str}_{signature_algorithms_str}"
    else:
        combined_extensions = extension_list_str
 
    if alpn:
        alpn_value = alpn[0]
        alpn_fingerprint = alpn_value[0] + alpn_value[-1] if len(alpn_value) >= 2 else "00"
    else:
        alpn_fingerprint = "00"
 
    # Assemble the raw fingerprint
    raw_fingerprint = f"{protocol}{tls_version}{sni}{len(filtered_ciphers):02d}{len(filtered_extensions):02d}{alpn_fingerprint}_{cipher_list_str}_{combined_extensions}"
    return raw_fingerprint
 
# Example usage
protocol = 't'
tls_version = '13'
sni = 'd'
ciphers = ['1301', '1302', '1303', 'c02b', 'c02f', 'c02c', 'c030', 'cca9', 'cca8', 'c013', 'c014', '009c', '009d', '002f', '0035']
extensions = ['001b', '0000', '0033', '0010', '4469', '0017', '002d', '000d', '0005', '0023', '0012', '002b', 'ff01', '000b', '000a', '0015']
alpn = ['h2']
signature_algorithms = ['0403', '0804', '0401', '0503', '0805', '0501', '0806', '0601']
 
# Raw sorted fingerprint
ja4_r = ja4_raw_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms, raw_type='sorted')
print(f"JA4_r: {ja4_r}")
 
# Raw original order fingerprint
ja4_ro = ja4_raw_fingerprint(protocol, tls_version, sni, ciphers, extensions, alpn, signature_algorithms, raw_type='original')
print(f"JA4_ro: {ja4_ro}")

Further JA4+ Techniques and Use Cases

JA4D: DNS Query Fingerprinting

Overview

JA4D (JA4DNS) fingerprints DNS queries by analyzing the characteristics of DNS packets exchanged between clients and servers. It focuses on the query types, response codes, domain names, and other DNS parameters to identify client behaviors and potential security issues.

Key Concepts

• DNS Query Analysis: Examination of DNS query types, response codes, and domain names. • Client Behaviors: Identifying patterns in DNS queries to infer client activities. • Security Monitoring: Detecting suspicious or malicious DNS activities for threat hunting.

Constructing the JA4D Fingerprint

Format:

dns<query_type>_<response_code>_<domain_hash>

Example Calculation

Step 1: Gather DNS Query Data

• Query Type: A (IPv4 address) • Response Code: NOERROR (0) • Domain Name: example.com

Step 2: Hash the Domain Name

• Domain Name: example.com

Compute Hash:

import hashlib
 
def compute_domain_hash(domain_name):
	return hashlib.sha1(domain_name.encode()).hexdigest()[:5]
 
# Example usage
domain_name = 'example.com'
domain_hash = compute_domain_hash(domain_name)
print(f"Domain Hash: {domain_hash}")  # Output: a1b2c

Step 3: Assemble the Fingerprint

dnsA_NOERROR_a1b2c

Interpretation

• DNS Query Types and Response Codes can reveal client intentions and server responses. • Unique Domain Hashes may help detect suspicious or malicious domain activities.