Hunting C2 channels in DNS traffic

A practical guide to detecting command-and-control infrastructure hidden in DNS traffic using passive analysis techniques.

Responsible Use

This content is published for defensive and educational purposes only. Do not use this information for unauthorized access or malicious activities.

Introduction

DNS is the backbone of the internet—and a favorite hiding spot for adversaries. Command-and-control (C2) channels embedded in DNS traffic are notoriously difficult to detect because they abuse a protocol that every network must allow.

This article documents our approach to hunting DNS-based C2 activity using passive traffic analysis, statistical anomaly detection, and threat intelligence correlation.

Why DNS for C2?

Attackers love DNS for C2 because:

  • Ubiquitous: DNS is allowed through virtually every firewall
  • High volume: Easy to blend into legitimate traffic
  • Protocol flexibility: TXT, NULL, and CNAME records can carry arbitrary data
  • Caching complexity: Makes blocking and detection harder

Common DNS C2 techniques include:

TechniqueDescription
DNS tunnelingEncoding data in subdomains (e.g., base64data.malware.com)
TXT record exfiltrationUsing large TXT responses to extract data
Fast fluxRapidly rotating A records to evade blocking
Domain generation algorithms (DGA)Programmatically generating domain names

Detection approach

Our methodology combines three detection strategies:

1. Statistical analysis

Legitimate DNS traffic has predictable statistical properties. C2 traffic often violates these norms:

IndicatorNormalSuspicious
Subdomain length< 30 chars> 50 chars
Query frequencyVariablePeriodic/constant
Entropy of subdomainLow-mediumHigh
Record type distributionA, AAAA, MXTXT, NULL heavy

2. Behavioral patterns

We look for behavioral anomalies:

  • Beaconing: Regular intervals between queries (e.g., every 60 seconds)
  • Volume spikes: Sudden increase in queries to a single domain
  • Unusual hours: Activity during non-business hours
  • Failed queries: High rate of NXDOMAIN responses (possible DGA)

3. Threat intelligence

Cross-referencing with known-bad indicators:

  • Known C2 domains from malware analysis
  • DGA patterns from reverse-engineered malware
  • Infrastructure fingerprints (registrar patterns, hosting ASNs)

Practical detection

High-entropy subdomain detection

DNS tunneling often produces high-entropy subdomains. Here’s a detection approach:

import math
from collections import Counter

def entropy(s):
    """Calculate Shannon entropy of a string."""
    p, lns = Counter(s), float(len(s))
    return -sum(count/lns * math.log2(count/lns) for count in p.values())

def is_suspicious(subdomain):
    """Flag high-entropy subdomains."""
    # Normalize
    subdomain = subdomain.lower().replace('-', '')

    # Skip short subdomains
    if len(subdomain) < 20:
        return False

    ent = entropy(subdomain)

    # Threshold based on empirical analysis
    # Normal domains: entropy ~3.0-3.5
    # Encoded data: entropy ~4.0-5.0
    return ent > 4.0 and len(subdomain) > 30

Beaconing detection

C2 beacons often have regular timing patterns:

import numpy as np

def detect_beaconing(timestamps, threshold=0.1):
    """
    Detect regular beaconing behavior.

    Returns True if timestamps show periodic pattern.
    """
    if len(timestamps) < 10:
        return False

    # Calculate intervals
    intervals = np.diff(sorted(timestamps))

    # Check for consistent intervals
    # Low coefficient of variation suggests beaconing
    cv = np.std(intervals) / np.mean(intervals)

    return cv < threshold

DGA detection

Domain generation algorithms produce domains with distinctive characteristics:

  • High consonant-to-vowel ratio
  • Unusual character distribution
  • Length patterns matching known DGA families
import re

def dga_score(domain):
    """Score a domain for DGA-like characteristics."""
    score = 0

    # Remove TLD
    name = domain.split('.')[0]

    # Length check
    if len(name) > 12:
        score += 1

    # Vowel ratio (normal words: ~40% vowels)
    vowels = len(re.findall(r'[aeiou]', name.lower()))
    ratio = vowels / len(name) if name else 0
    if ratio < 0.25:
        score += 2

    # Digit presence in middle
    if re.search(r'[a-z][0-9]+[a-z]', name.lower()):
        score += 1

    # Consecutive consonants
    if re.search(r'[bcdfghjklmnpqrstvwxyz]{5}', name.lower()):
        score += 2

    return score

Case study: Detecting Cobalt Strike DNS

During a recent investigation, we identified Cobalt Strike beacon traffic exhibiting:

  1. Regular 60-second intervals — Classic beacon timing
  2. TXT record queries — Data exfiltration channel
  3. Base64-encoded subdomains — Encoded commands/responses

Query pattern observed:

aGVsbG8gd29ybGQ=.cdn.example-c2.com  TXT
YW5vdGhlciBtZXNzYWdl.cdn.example-c2.com  TXT
c29tZSBtb3JlIGRhdGE=.cdn.example-c2.com  TXT

The Base64-encoded subdomains immediately stood out in our entropy analysis, with scores consistently above 4.5.

Infrastructure observations

Analyzing the C2 infrastructure revealed:

  • Registrar: Namecheap (commonly abused)
  • Hosting: Bulletproof VPS in Moldova
  • SSL: Let’s Encrypt certificate (legitimate but low-friction)
  • Age: Domain registered 48 hours before activity

Pattern: Short-lived domains, privacy-protected registration, budget hosting in permissive jurisdictions.

Defensive recommendations

Detection rules

Implement alerts for:

  1. High-entropy queries: Subdomain entropy > 4.0 with length > 30
  2. Unusual record types: Spike in TXT/NULL queries
  3. NXDOMAIN patterns: High rate of failed queries to random-looking domains
  4. Beaconing: Regular query intervals to single domains

Blocking strategies

  1. DNS response filtering: Block responses containing encoded data
  2. Sinkholing: Redirect known-bad domains to internal monitoring
  3. Query logging: Maintain searchable DNS query logs (30+ days)
  4. Split-horizon DNS: Force all DNS through internal resolvers

Monitoring setup

# Example Suricata rule for high-entropy DNS
alert dns any any -> any any (
  msg:"Possible DNS tunnel - high entropy subdomain";
  dns.query;
  pcre:"/^[a-z0-9]{30,}\./i";
  threshold: type threshold, track by_src, count 10, seconds 60;
  sid:1000001;
  rev:1;
)

Conclusion

DNS-based C2 remains an effective evasion technique because it exploits the trust networks place in DNS traffic. Defense requires:

  1. Comprehensive DNS logging
  2. Statistical analysis capabilities
  3. Threat intelligence integration
  4. Baseline understanding of normal traffic

The techniques described here won’t catch every DNS C2 channel, but they significantly raise the bar for attackers and provide valuable detection coverage for the most common techniques.


All analysis was performed on traffic collected from our own infrastructure. Domain names in examples have been sanitized.