Introduction
DNS is one of the most critical yet often overlooked attack surfaces in infrastructure. DNS cache poisoning, DNS hijacking, and DNS-based data exfiltration are real threats in production environments. DNSSEC (DNS Security Extensions) adds cryptographic signatures to DNS records, preventing spoofing. This guide covers both DNS security threats and defenses, including DNSSEC deployment.
DNS Attack Types
Cache Poisoning (Kaminsky Attack):TEXT
1. Attacker floods resolver with forged responses for bank.com
2. Attacker guesses the Query ID (16-bit number)
3. If attacker's response arrives before real response:
Resolver caches attacker's fake IP for bank.com
4. All clients using this resolver now go to attacker's server
Mitigations:
- Source port randomization (RFC 5452) — increases attack space
- DNSSEC validation
- DNS-over-HTTPS or DNS-over-TLSTEXT
Attacker compromises the authoritative nameserver or registry account
→ Changes A record for victim.com to attacker's IP
→ All traffic goes to attackerTEXT
Malware on compromised host encodes stolen data in DNS queries:
dns-query: data-chunk1.attacker-controlled-domain.com
dns-query: data-chunk2.attacker-controlled-domain.com
...
(firewall allows DNS, doesn't inspect content)
Detection: unusually long subdomain names, high query ratesDNSSEC: How It Works
TEXT
Without DNSSEC:
Client → DNS Resolver → "A record: 203.0.113.50" (could be spoofed)
With DNSSEC:
Zone owner signs records with private key
Client validates signature with zone's public key
DNS response with DNSSEC:
A record: 203.0.113.50
RRSIG: [cryptographic signature over the A record]
Client verifies: signature is valid → trust the A recordSigning a Zone with DNSSEC
BASH
# BIND: Sign a zone
cd /var/named/
# Generate Zone Signing Key (ZSK) - rotates frequently
dnssec-keygen -a RSASHA256 -b 2048 -n ZONE company.com
# Creates: Kcompany.com.+008+12345.key and .private
# Generate Key Signing Key (KSK) - long-lived
dnssec-keygen -a RSASHA256 -b 4096 -n ZONE -f KSK company.com
# Creates: Kcompany.com.+008+67890.key and .private
# Add keys to zone file
cat Kcompany.com.*.key >> /var/named/company.com.zone
# Sign the zone
dnssec-signzone -A -3 $(head -c 1000 /dev/urandom | sha1sum | cut -b 1-16) -N increment -o company.com -t company.com.zone
# This creates: company.com.zone.signed
# Update BIND to use signed zone
# /etc/named.conf:
zone "company.com" {
type master;
file "company.com.zone.signed";
auto-dnssec maintain;
inline-signing yes;
};Deploying DNSSEC with PowerDNS (Modern Approach)
BASH
# PowerDNS with SQLite backend
apt install pdns-server pdns-backend-sqlite3
# Enable DNSSEC
pdnsutil secure-zone company.com
# Check signing status
pdnsutil check-zone company.com
# Get DS record to provide to registrar
pdnsutil show-zone company.com | grep DS
# Rectify zone after changes
pdnsutil rectify-zone company.comConfiguring DNSSEC Validation on Resolvers
BASH
# BIND resolver: enable DNSSEC validation
# /etc/named.conf
options {
dnssec-enable yes;
dnssec-validation auto; # Uses built-in trust anchors
dnssec-lookaside auto;
};
# Test DNSSEC validation
dig +dnssec A sigfail.verteiltesysteme.net
# If you see "ad" flag in response: authentication done
# SERVFAIL response means signature validation failed
# Cloudflare DNS (1.1.1.1) validates DNSSEC by default
dig @1.1.1.1 +dnssec +short A company.comDNS Filtering and RPZ (Response Policy Zones)
BASH
# Block malicious domains using RPZ
# /etc/named.conf
response-policy {
zone "rpz.company.local"; # Your blacklist zone
zone "rpz.surbl.org"; # External threat intelligence
};
# /var/named/rpz.company.local.zone
$TTL 60
@ SOA rpz.company.local. admin.company.local. 2024010101 3600 900 86400 60
; Block known malware domains
malware-site.com.rpz.company.local CNAME . ; Return NXDOMAIN
phishing-bank.net.rpz.company.local CNAME .DNS-over-HTTPS and DNS-over-TLS
BASH
# Set up unbound as DoT resolver
apt install unbound
# /etc/unbound/unbound.conf
server:
interface: 127.0.0.1
port: 53
verbosity: 1
# Validate DNSSEC
val-clean-additional: yes
dnssec-mode: "auto"
# Forward to CloudFlare DoT
forward-zone:
name: "."
forward-tls-upstream: yes
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 1.0.0.1@853#cloudflare-dns.com
# Test DoT
kdig @1.1.1.1 +tls company.comMonitoring DNS for Threats
PYTHON
#!/usr/bin/env python3
# dns_monitor.py - Detect DNS exfiltration attempts
import subprocess
import re
from collections import defaultdict
def analyze_dns_log(logfile):
query_counts = defaultdict(int)
long_subdomains = []
with open(logfile) as f:
for line in f:
# Parse BIND query log format
match = re.search(r'query: (S+) IN', line)
if match:
domain = match.group(1)
parts = domain.split('.')
# Flag unusually long subdomains (exfiltration indicator)
if parts and len(parts[0]) > 40:
long_subdomains.append(domain)
# Count queries per base domain
if len(parts) >= 2:
base = '.'.join(parts[-2:])
query_counts[base] += 1
# Report anomalies
print("=== High-frequency domains ===")
for domain, count in sorted(query_counts.items(), key=lambda x: -x[1])[:10]:
print(f" {count:5d} queries: {domain}")
if long_subdomains:
print("
=== SUSPICIOUS: Long subdomains (possible exfiltration) ===")
for domain in long_subdomains[:20]:
print(f" {domain}")
if __name__ == "__main__":
analyze_dns_log("/var/log/named/query.log")DNS security is a layered problem: DNSSEC prevents spoofing, DNS filtering blocks known-bad domains, DoT/DoH encrypts queries in transit, and log monitoring detects abuse. Each layer addresses different threat vectors.
