DNS TUNNEL
ENTROPY
SUBDOMAINS
THROUGHPUT
DetectionBlue TeamSOCOctober 12, 2026•9 min read

Detecting DNS Tunneling: Throughput, Entropy and Record-Type Shape

Command-and-control over DNS is about small, scheduled messages. A DNS tunnel is about throughput: a stream of data pushed through the resolver as fast as the record sizes allow.

Scroll

A DNS tunnel encodes arbitrary traffic into hostnames and record data so that it travels through the recursive resolver path to an authoritative server the operator controls. Where our DNS C2 pack focuses on beaconing messages, this pack focuses on the transport: volume, shape and statistics that betray a sustained bidirectional channel.

Signals at a Glance

SignalWhereATT&CK
Very high count of unique subdomains under one parent zoneDNS logs, Zeek dns.logT1572
Long query names near the 253-character limit with encoded labelsDNS logsT1572
High-entropy labels (base32, base64 or hex-looking)DNS logsT1048
Unusual record-type mix: heavy TXT, NULL, CNAME or MX from a workstationDNS logsT1071.004
Sustained query rate from one client to one zone for hoursDNS logs, resolver metricsT1572

Statistical Detection

Legitimate zones have bounded, repeated names. A tunnel generates a new name for nearly every packet, so the number of distinct subdomains per client and zone grows without bound. Start with cardinality and length over a rolling window:

# Splunk (Zeek dns.log) - subdomain cardinality and length by client and zone
index=zeek sourcetype=bro_dns
| eval labels=split(query,".")
| eval zone=mvindex(labels,-2).".".mvindex(labels,-1)
| eval sub_len=len(query)-len(zone)
| bin _time span=1h
| stats count AS queries, dc(query) AS unique_names, avg(sub_len) AS avg_sub_len,
        dc(qtype_name) AS qtypes BY _time, id.orig_h, zone
| where unique_names > 500 AND avg_sub_len > 30
| sort - unique_names
# tune/validate: exclude CDNs, anti-virus lookups and DNS-based blocklists;
# for country-code second-level zones use a public-suffix lookup instead.

Record Types and Throughput

Tunnel tools pick the record type that carries the most data per response. TXT, NULL and CNAME answers are common; ordinary workstation traffic is dominated by A and AAAA. Compare the record-type mix and response sizes against what you see across the fleet:

// Microsoft Sentinel (KQL) - non-A/AAAA heavy clients
DnsEvents
| where TimeGenerated > ago(1d)
| summarize total=count(),
            txt=countif(QueryType in ("TXT","NULL","CNAME","MX")),
            uniq=dcount(Name) by ClientIP, bin(TimeGenerated, 1h)
| extend txt_ratio = todouble(txt) / total
| where total > 300 and txt_ratio > 0.5 and uniq > 200
| order by uniq desc
// tune/validate: mail servers and security agents produce legitimate MX/TXT
// bursts; scope to endpoints and user-subnets.
Vetted sources

Use Zeek dns.log, Splunk ESCU DNS exfiltration and tunneling analytics, Elastic DNS tunneling rules, SigmaHQ DNS rules and MITRE CAR analytics for DNS. Always baseline your own environment — thresholds are zone- and tenant-specific and need tuning against your resolver telemetry.

Build Detections That Fire

Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.

Detection EngineeringManaged Detection & ResponseThreat HuntingIncident ResponsePurple Teaming
  • Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
  • Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
  • 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Written by: Mjolnir Threat Research (MTAC)  |  Published: October 12, 2026  |  Last reviewed: October 12, 2026