Back to Blog

Detecting DNS Over HTTPS (DoH) Tunneling via TLS Fingerprinting

Detecting DNS Over HTTPS (DoH) Tunneling via TLS Fingerprinting

The traditional visibility afforded to network defenders by inspecting DNS traffic (UDP/53) is rapidly evaporating. For decades, DNS was the "canary in the coal mine"-a clear-text protocol that allowed security practitioners to identify domain generation algorithms (DGAs), identify C2 communication, and block malicious lookups at the perimeter.

The advent of DNS over HTTPS (DoH), codified in RFC 8484, has fundamentally altered this landscape. By wrapping DNS queries within encrypted TLS sessions over port 443, DoH achieves its primary goal of privacy and integrity, but it simultaneously achieves a secondary, more nefarious goal for adversaries: obfuscation. When DNS queries are indistinguishable from standard web traffic, traditional Deep Packet Inspection (DPI) becomes blind. This visibility gap provides a perfect medium for DNS tunneling-a technique used to exfiltrate data or maintain Command and Control (C2) by embedding non-DNS payloads within the encrypted DoH stream.

To combat this, we must move away from inspecting the payload and instead focus on the handshake. This is where TLS fingerprinting becomes a critical component of a modern detection strategy.

The Anatomy of the Problem: DoH as an Obfuscation Layer

In a standard DNS tunneling attack (e.g., using `dnscat2`), the attacker encodes data into subdomains (e.g., `encoded-data.attacker.com`). Security tools can catch this by analyzing query length, entropy, or frequency.

With DoH, the entire transaction is encapsulated in an HTTPS `POST` or `GET` request. To a firewall or an Intrusion Detection System (IDS), a DoH query looks like any other encrypted HTTPS stream to a legitimate provider like Cloudflare (`1.1.1.1`) or Google (`8.8.8.8`). Because the traffic uses the same port and protocol as standard web browsing, simple port-based blocking is impossible without breaking the internet for legitimate users.

The challenge for defenders is to differentiate between a legitimate browser performing a DoH lookup and a malicious agent (like a Python script or a custom C2 implant) using DoH as a transport layer.

The Solution: TLS Fingerprinting (JA3 and JA3S)

TLS fingerprinting relies on the fact that the TLS handshake contains a wealth of unencrypted information before the encrypted tunnel is established. When a client initiates a connection, it sends a `Client Hello` packet. This packet contains a specific set of parameters that are highly characteristic of the underlying software library or application.

The JA3 Algorithm

The most prominent method for this is the JA3 fingerprinting technique. JA3 produces a hash based on five specific fields in the `Client Hello` packet:

  1. Version: The TLS version (e.g., TLS 1.2, TLS 1.3).
  2. Accepted Ciphers: The list of cipher suites the client supports.
  3. List of Extensions: The specific TLS extensions (e.g., SNI, ALPN, Supported Groups).
  4. Elliptic Curves: The curves supported by the client.
  5. Elliptic Curve Format: The format of the curves.

The string is concatenated in a specific order and MD5 hashed. The resulting fingerprint serves as a "software signature."

A standard Chrome browser on Windows will produce a very specific JA3 hash. Conversely, a DoH tunneling tool written using the Python `requests` library or a Go-based implant will produce a significantly different hash because the default TLS stacks in these languages prioritize different cipher suites and extensions than a modern browser.

The Role of JA3S

While JA3 fingerprints the client, JA3S fingerprints the server's response (`Server Hello`). In a sophisticated detection scenario, we look at the combination of JA3 and JA3S. A legitimate DoH provider (like Google) will respond with a predictable JA3S hash. If we see a known "malicious" JA3 (e.g., a Python-based tool) paired with a JA3S that indicates a non-standard or suspicious server configuration, the probability of a tunneling attempt increases significantly.

Practical Implementation: Detecting the Deviation

To implement this in a production environment, security engineers typically leverage network monitoring tools like Zeek (formerly Bro) or Suricata.

Step 1: Feature Extraction

Using Zeek, the `ja3` plugin can automatically extract these fingerprints from every TLS handshake traversing the network. This data is then logged in a structured format (JSON), making it searchable via a SIEM (like Splunk or ELK).

Step 2: Baseline Establishment

You must first establish a baseline of "known good" fingerprints. In a corporate environment, most DoH traffic should originate from known browsers (Chrome, Firefox, Edge).

  • Example: Identify the JA3 hashes for the standard company-issued browser image.
  • Example: Identify the JA3 hashes for legitimate system processes (e.g., Windows Update, OS telemetry).

Step 3: Anomaly Detection Logic

The detection logic follows a simple heuristic:

`IF (TLS_Destination == DoH_Provider_IP) AND (JA3_Hash NOT IN [Browser_Whitelist]) THEN Alert(Potential_DoH_Tunneling)`

Example Scenario

Consider an adversary using a custom Go-based agent to tunnel data.

  • Legitimate Chrome DoH: `771,4865-4866-4867...,0-23-65281...,29-23,0` $\rightarrow$ `Hash: a1b2c3d4...`
  • Malicious Go-Agent: `771,4865-4866...,0-23-65281...,29-23,0` $\rightarrow$ `Hash: e5f6g7h8...`

Even if the `Server Name Indication (SNI)` is masked or points to a legitimate-looking domain, the deviation in the `Cipher Suites

Conclusion

As shown across "The Anatomy of the Problem: DoH as an Obfuscation Layer", "The Solution: TLS Fingerprinting (JA3 and JA3S)", "Practical Implementation: Detecting the Deviation", a secure implementation for detecting dns over https (doh) tunneling via tls fingerprinting depends on execution discipline as much as design.

The practical hardening path is to enforce strict token/claim validation and replay resistance, certificate lifecycle governance with strict chain/revocation checks, and host hardening baselines with tamper-resistant telemetry. This combination reduces both exploitability and attacker dwell time by forcing failures across multiple independent control layers.

Operational confidence should be measured, not assumed: track mean time to detect and remediate configuration drift and detection precision under peak traffic and adversarial packet patterns, then use those results to tune preventive policy, detection fidelity, and response runbooks on a fixed review cadence.

Related Articles

Explore related cybersecurity topics:

Recommended Next Steps

If this topic is relevant to your organisation, use one of these paths: