Analyzes DNS query logs to detect data exfiltration via DNS tunneling, DGA domain communication, and covert C2 channels using entropy analysis, query volume anomalies, and subdomain length detection in SIEM platforms.
SkillScore41Maintained
Automatic
◆Security & AppSec pack
Last verified 7/27/2026
What it changes
Passed 9 of 21 test cases with the skill, and 1 of 21 without it.
Without skill5%
With skill41%
8 fixed1 passed either way13 still failing0 broke
Pass-rate lift
+36 pp
Tokens
+128%
Agent turns
0%
Response time
-32%
Model gemini-3.6-flashMeasured 7/27/2026v19 of 22 cases passed with skill · 21 comparable
Tokens, turns and time describe resource use, not a dollar price.
What's inside
The instructions your model reads when the skill loads.
SKILL.md273 lines3 filesincludes scripts
Analyzing DNS Logs for Exfiltration
When to Use
Use this skill when:
SOC teams suspect data exfiltration through DNS tunneling to bypass firewall/proxy controls
Threat intelligence indicates adversaries using DNS-based C2 channels (e.g., Cobalt Strike DNS beacon)
UEBA detects anomalous DNS query volumes from specific hosts
Malware analysis reveals DNS-over-HTTPS (DoH) or DNS tunneling capabilities
Do not use for standard DNS troubleshooting or availability monitoring — this skill focuses on security-relevant DNS abuse detection.
Prerequisites
DNS query logging enabled (Windows DNS Server, Bind, Infoblox, or Cisco Umbrella)
DNS logs ingested into SIEM (Splunk with Stream:DNS, dns sourcetype, or Zeek DNS logs)
Passive DNS data for historical domain resolution analysis
Baseline of normal DNS behavior (query volume, domain distribution, TXT record frequency)
Python with math and collections libraries for entropy calculation
Workflow
Step 1: Detect DNS Tunneling via Subdomain Length Analysis
DNS tunneling encodes data in subdomain labels, creating unusually long queries:
index=dns sourcetype="stream:dns" query_type IN ("A", "AAAA", "TXT", "CNAME", "MX")
| eval domain_parts = split(query, ".")
| eval subdomain = mvindex(domain_parts, 0, mvcount(domain_parts)-3)
| eval subdomain_str = mvjoin(subdomain, ".")
| eval subdomain_len = len(subdomain_str)
| eval tld = mvindex(domain_parts, -1)
| eval registered_domain = mvindex(domain_parts, -2).".".tld
| where subdomain_len > 50
| stats count AS queries, dc(query) AS unique_queries,
avg(subdomain_len) AS avg_subdomain_len,
max(subdomain_len) AS max_subdomain_len,
values(src_ip) AS sources
by registered_domain