Analyzes DNS query logs using entropy analysis, query volume anomalies, and subdomain length detection to identify DNS tunneling exfiltration, DGA domains, and covert C2 channels in SIEM like Splunk. For SOC teams hunting DNS threats.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
在以下情况下使用本技能:
Analyzes DNS query logs in SIEM like Splunk to detect exfiltration via tunneling, DGA domains, and C2 using entropy, query volume anomalies, and subdomain lengths.
Analyzes DNS query logs in SIEM like Splunk to detect exfiltration via DNS tunneling, DGA domains, and C2 channels using entropy analysis, query volume anomalies, and subdomain length. For SOC threat hunting.
Detects DNS tunnel data exfiltration via passive DNS monitoring, analyzing query entropy, subdomain lengths, query volumes, TXT record abuse, and response payload sizes.
Share bugs, ideas, or general feedback.
在以下情况下使用本技能:
不适用于标准 DNS 故障排除或可用性监控——本技能专注于与安全相关的 DNS 滥用检测。
Stream:DNS、dns 数据源或 Zeek DNS 日志)math 和 collections 库)用于熵值计算DNS 隧道将数据编码在子域名标签中,产生异常长的查询:
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
| where queries > 20
| sort - avg_subdomain_len
| table registered_domain, queries, unique_queries, avg_subdomain_len, max_subdomain_len, sources
域名生成算法(DGA)产生看似随机的域名:
index=dns sourcetype="stream:dns"
| eval domain_parts = split(query, ".")
| eval sld = mvindex(domain_parts, -2)
| eval sld_len = len(sld)
| eval char_count = sld_len
| eval vowels = len(replace(sld, "[^aeiou]", ""))
| eval consonants = len(replace(sld, "[^bcdfghjklmnpqrstvwxyz]", ""))
| eval digits = len(replace(sld, "[^0-9]", ""))
| eval vowel_ratio = if(char_count > 0, vowels / char_count, 0)
| eval digit_ratio = if(char_count > 0, digits / char_count, 0)
| where sld_len > 12 AND (vowel_ratio < 0.2 OR digit_ratio > 0.3)
| stats count AS queries, dc(query) AS unique_domains, values(src_ip) AS sources
by query
| where unique_domains > 10
| sort - queries
基于 Python 的 DNS 查询香农熵(Shannon Entropy)计算:
import math
from collections import Counter
def shannon_entropy(text):
"""计算字符串的香农熵"""
if not text:
return 0
counter = Counter(text.lower())
length = len(text)
entropy = -sum(
(count / length) * math.log2(count / length)
for count in counter.values()
)
return round(entropy, 4)
# 测试示例
normal_domain = "google" # 低熵
dga_domain = "x8kj2m9p4qw7n" # 高熵
tunnel_subdomain = "aGVsbG8gd29ybGQ.evil.com" # Base64 编码的数据
print(f"正常: {shannon_entropy(normal_domain)}") # ~2.25
print(f"DGA: {shannon_entropy(dga_domain)}") # ~3.70
print(f"隧道: {shannon_entropy(tunnel_subdomain)}") # ~3.50
# 阈值:子域名熵值 > 3.5 = 可能是隧道/DGA
Splunk 熵值评分实现:
index=dns sourcetype="stream:dns"
| eval domain_parts = split(query, ".")
| eval check_string = mvindex(domain_parts, 0)
| eval check_len = len(check_string)
| where check_len > 8
| eval chars = split(check_string, "")
| stats count AS total_chars, dc(chars) AS unique_chars by query, src_ip, check_string, check_len
| eval entropy_estimate = log(unique_chars, 2) * (unique_chars / check_len)
| where entropy_estimate > 3.5
| stats count AS high_entropy_queries, dc(query) AS unique_queries by src_ip
| where high_entropy_queries > 50
| sort - high_entropy_queries
识别产生异常 DNS 流量的主机:
index=dns sourcetype="stream:dns" earliest=-24h
| bin _time span=1h
| stats count AS queries, dc(query) AS unique_domains by src_ip, _time
| eventstats avg(queries) AS avg_queries, stdev(queries) AS stdev_queries by src_ip
| eval z_score = (queries - avg_queries) / stdev_queries
| where z_score > 3 OR queries > 5000
| sort - z_score
| table _time, src_ip, queries, unique_domains, avg_queries, z_score
检测 TXT 记录滥用(常见隧道方法):
index=dns sourcetype="stream:dns" query_type="TXT"
| stats count AS txt_queries, dc(query) AS unique_txt_domains,
values(query) AS domains by src_ip
| where txt_queries > 100
| eval suspicion = case(
txt_queries > 1000, "CRITICAL — 可能是 DNS 隧道",
txt_queries > 500, "HIGH — 可能是 DNS 隧道",
txt_queries > 100, "MEDIUM — 异常 TXT 查询量"
)
| sort - txt_queries
| table src_ip, txt_queries, unique_txt_domains, suspicion
搜索常见 DNS 隧道工具的特征:
index=dns sourcetype="stream:dns"
| eval query_lower = lower(query)
| where (
match(query_lower, "\.dnscat\.") OR
match(query_lower, "\.dns2tcp\.") OR
match(query_lower, "\.iodine\.") OR
match(query_lower, "\.dnscapy\.") OR
match(query_lower, "\.cobalt.*\.beacon") OR
query_type="NULL" OR
(query_type="TXT" AND len(query) > 100)
)
| stats count by src_ip, query, query_type
| sort - count
检测 DNS over HTTPS(DoH)绕过本地 DNS:
index=proxy OR index=firewall
dest IN ("1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4",
"9.9.9.9", "149.112.112.112", "208.67.222.222")
dest_port=443
| stats sum(bytes_out) AS total_bytes, count AS connections by src_ip, dest
| where connections > 100 OR total_bytes > 10485760
| eval alert = "可能的 DoH 绕过 — 通过 HTTPS 将 DNS 查询发送到公共解析器"
| sort - total_bytes
将可疑 DNS 与进程数据进行交叉参考:
index=dns src_ip="192.168.1.105" query="*.evil-tunnel.com" earliest=-24h
| stats count AS dns_queries, earliest(_time) AS first_query, latest(_time) AS last_query
by src_ip, query
| join src_ip [
search index=sysmon EventCode=3 DestinationPort=53 Computer="WORKSTATION-042"
| stats count AS connections, values(Image) AS processes by SourceIp
| rename SourceIp AS src_ip
]
| table src_ip, query, dns_queries, first_query, last_query, processes
估算 DNS 查询中编码数据的体积:
index=dns src_ip="192.168.1.105" query="*.evil-tunnel.com" earliest=-24h
| eval domain_parts = split(query, ".")
| eval encoded_data = mvindex(domain_parts, 0)
| eval encoded_bytes = len(encoded_data)
| eval decoded_bytes = encoded_bytes * 0.75 -- Base64 解码因子
| stats sum(decoded_bytes) AS total_bytes_estimated, count AS total_queries,
earliest(_time) AS first_seen, latest(_time) AS last_seen
| eval estimated_kb = round(total_bytes_estimated / 1024, 1)
| eval estimated_mb = round(total_bytes_estimated / 1048576, 2)
| eval duration_hours = round((last_seen - first_seen) / 3600, 1)
| eval rate_kbps = round(estimated_kb / (duration_hours * 3600) * 8, 2)
| table total_queries, estimated_mb, duration_hours, rate_kbps, first_seen, last_seen
| 术语 | 定义 |
|---|---|
| DNS 隧道 | 将数据编码在 DNS 查询/响应中,通过 DNS 外泄数据或建立 C2 信道的技术 |
| DGA | 域名生成算法——恶意软件技术,生成伪随机域名以提高 C2 韧性 |
| 香农熵 | 字符串随机性的数学度量——域名中高熵(>3.5)表明存在 DGA 或隧道 |
| TXT 记录滥用 | 利用 DNS TXT 记录(设计用于文本数据)作为数据隧道的高带宽信道 |
| DNS over HTTPS(DoH) | 通过 HTTPS(端口 443)加密的 DNS 查询,绕过传统 DNS 监控 |
| 被动 DNS | 历史 DNS 解析记录,显示某域名随时间解析到的 IP 地址 |
DNS 外泄分析 — WORKSTATION-042
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
时间段: 2024-03-14 至 2024-03-15
来源: 192.168.1.105(WORKSTATION-042,财务部门)
发现:
[CRITICAL] 检测到 DNS 隧道至 evil-tunnel[.]com
查询量: 18 小时内 12,847 次查询
平均子域名长: 63 字符(正常值:<20)
平均熵值: 3.82(阈值:3.5)
查询类型: TXT(89%)、A(11%)
估算数据量: 约 4.7 MB 通过 DNS 外泄
速率: 0.58 kbps(慢速滴漏模式)
[HIGH] 已解析 DGA 类域名
唯一 DGA 域名: 247 个域名已解析
模式: 15 字符随机字母数字.xyz TLD
熵值范围: 3.6 - 4.1
进程归因:
进程: svchost_update.exe(伪装——非合法 svchost)
PID: 4892
父进程: explorer.exe
哈希: SHA256: a1b2c3d4...(VT: 34/72 恶意 — Cobalt Strike Beacon)
遏制措施:
[已完成] 主机已通过 EDR 隔离
[已完成] 域名 evil-tunnel[.]com 已添加到 DNS 沉洞
[已完成] 事件 IR-2024-0448 已创建