DNS Exfiltration — How Attackers Tunnel Data Through Name Queries

DNS was designed to translate names to IPs — not to carry stolen data. This post explains how attackers encode files in DNS queries, why firewalls miss it, and how to detect it in a pcap.

Why DNS is the perfect exfiltration channel

Nearly every network — corporate, government, hospital — allows outbound DNS on UDP port 53. Block it and half the internet stops working. Attackers have known this for decades. DNS exfiltration abuses that trust by encoding stolen data inside the query itself, turning a protocol designed for name resolution into a covert data pipe.

A standard DNS query looks like this:

query: www.google.com → 142.250.74.100

An exfiltration query looks like this:

query: 5a65726f5472757374.attacker-c2.com → (any response)

The subdomain label 5a65726f5472757374 is hex-encoded data. The DNS server controlled by the attacker receives the query, decodes the label, and reassembles the stolen file from the stream of queries. The network logs just show "DNS traffic to attacker-c2.com" — which looks unremarkable to a firewall that only checks if port 53 traffic is reaching a real DNS server.

How encoding works

Each DNS label (the part between dots) can be up to 63 characters. The full query name can be up to 253 characters. Attackers use this space to carry encoded payloads. Common encodings:

  • Hex: Each byte becomes two characters. Simple, detectable by high-entropy labels.
  • Base32: Used when the DNS infrastructure is case-insensitive. Produces labels like mfra2mjb. Denser than hex, still high-entropy.
  • Base64url: Highest density but uses characters some DNS implementations reject.

A typical exfiltration session breaks a file into chunks, encodes each chunk as a subdomain label, and sends one query per chunk. A 100 KB file at 50 bytes per label requires roughly 2,000 DNS queries — sent slowly enough to stay below anomaly thresholds.

Detection signals

No single signal catches DNS exfiltration reliably, but these patterns together are strong indicators:

  • High query rate to a single domain: Legitimate DNS lookups are bursty and varied. Hundreds of queries to one domain in a short window is unusual.
  • Abnormal label length: Real hostnames rarely use 40+ character labels. Exfiltration labels are often at or near the 63-character maximum.
  • High entropy in the subdomain: Random-looking strings (hex, base32) have entropy close to the theoretical maximum. Human-readable subdomains do not.
  • NX or generic responses: The attacker's DNS server often returns NXDOMAIN or a static IP for all queries — it only cares about logging the query, not resolving it usefully.
  • Sequential structure: Exfiltration tools often include a sequence number in the label — like 0001.data, 0002.data — so the server can reassemble chunks in order.

Walking through a pcap

In Wireshark, filter with dns then look at the Info column. Exfiltration traffic immediately stands out because the query names are long and structurally identical — same domain, same label length, incrementing prefix.

Use dns.qry.name contains "attacker-c2.com" to isolate queries to the suspicious domain, then export the labels, strip the base domain, decode the base32/hex, and concatenate. You will recover the original file.

To calculate entropy on a set of labels from the terminal:

python3 -c "
import math, collections
label = '5a65726f5472757374'
freq = collections.Counter(label)
entropy = -sum(p/len(label) * math.log2(p/len(label)) for p in freq.values())
print(f'entropy: {entropy:.2f} bits/char')
"

A real hostname like mail.google.com has entropy around 3.0. An exfiltration label will be above 4.5.

Practice it

The Silent Channel challenge in FoilLab gives you a real packet capture with a DNS exfiltration session embedded in normal traffic. Your job is to identify the malicious queries, decode the data, and find the flag.