mcpField
A
analyzing-dns-logs-for-exfiltration

analyzing-dns-logs-for-exfiltration

github.com/mukul975安全35.2k529 次安装8 周前更新
代码仓库

关于 analyzing-dns-logs-for-exfiltration

面向 SOC 团队的安全分析技能,用于排查 DNS 隧道、DGA 和其他疑似数据外泄行为。提供基于 Splunk 查询、熵值分析及端点关联的调查流程。

主要功能

  1. 01分析子域长度与熵值
  2. 02检测异常 DNS 查询量
  3. 03识别 TXT 记录滥用
  4. 04匹配已知隧道工具特征
  5. 05关联端点数据并估算外泄量

适用场景

  1. 01调查疑似 DNS 隧道外泄
  2. 02检测 DGA 域名与 DNS C2
  3. 03发现 DoH 绕过本地 DNS 监控

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-dns-logs-for-exfiltration

安装后在 Claude Code 中输入/analyzing-dns-logs-for-exfiltration确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE
references/
api-reference.md
scripts/
agent.py

详细介绍

分析 DNS 日志以检测数据外泄

适用场景

在以下情况下使用本技能:

  • SOC 团队怀疑通过 DNS 隧道进行数据外泄,以绕过防火墙/代理控制
  • 威胁情报表明对手使用基于 DNS 的 C2 通道(例如 Cobalt Strike DNS beacon)
  • UEBA 检测到特定主机出现异常的 DNS 查询量
  • 恶意软件分析发现 DNS-over-HTTPS(DoH)或 DNS 隧道能力

不要用于标准 DNS 故障排查或可用性监控——本技能专注于与安全相关的 DNS 滥用检测。

前置条件

  • 已启用 DNS 查询日志记录(Windows DNS Server、Bind、Infoblox 或 Cisco Umbrella)
  • DNS 日志已接入 SIEM(Splunk 使用 Stream:DNS、dns sourcetype,或 Zeek DNS 日志)
  • 用于历史域名解析分析的被动 DNS 数据
  • 正常 DNS 行为的基线(查询量、域名分布、TXT 记录频率)
  • 用于熵计算的 Python 及 math 和 collections 库

工作流

步骤 1:通过子域长度分析检测 DNS 隧道

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
步骤 2:检测高熵域名查询(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 查询香农熵计算:

import math
from collections import Counter

def shannon_entropy(text):
    """Calculate Shannon entropy of a string"""
    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)

# Test with examples
normal_domain = "google"           # Low entropy
dga_domain = "x8kj2m9p4qw7n"      # High entropy
tunnel_subdomain = "aGVsbG8gd29ybGQ.evil.com"  # Base64 encoded data

print(f"Normal: {shannon_entropy(normal_domain)}")     # ~2.25
print(f"DGA:    {shannon_entropy(dga_domain)}")         # ~3.70
print(f"Tunnel: {shannon_entropy(tunnel_subdomain)}")   # ~3.50

# Threshold: entropy > 3.5 for subdomain = likely tunneling/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
步骤 3:检测异常的 DNS 查询量

识别产生异常 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 — Likely DNS tunneling",
    txt_queries > 500, "HIGH — Possible DNS tunneling",
    txt_queries > 100, "MEDIUM — Unusual TXT volume"
  )
| sort - txt_queries
| table src_ip, txt_queries, unique_txt_domains, suspicion
步骤 4:检测已知 DNS 隧道工具

搜索常见 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 的 DNS over HTTPS(DoH):

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 = "Possible DoH bypass — DNS queries sent over HTTPS to public resolver"
| sort - total_bytes
步骤 5:将 DNS 发现与端点数据关联

将可疑 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
步骤 6:计算数据外泄量估算

估算 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 decoding factor
| 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 监控
被动 DNSDNS 解析的历史记录,显示某个域名随时间解析到的 IP

工具与系统

  • Splunk Stream:网络流量捕获插件,提供解析后的 DNS 查询数据,用于 SIEM 分析
  • Zeek (Bro):网络安全监控器,生成详细的 DNS 事务日志以供分析
  • Cisco Umbrella (OpenDNS):云 DNS 安全平台,可阻止恶意域名并记录查询数据
  • Infoblox DNS Firewall:DNS 层安全防护,提供基于 RPZ 的阻止和详细的查询日志记录
  • Farsight DNSDB:被动 DNS 数据库,用于历史域名解析查询和基础设施映射

常见场景

  • Cobalt Strike DNS Beacon:检测向 C2 域名发送带有编码载荷的周期性 TXT 查询
  • 数据外泄:大量唯一子域查询,以 Base64/十六进制编码窃取的数据
  • DGA 恶意软件:检测对算法生成域名的 DNS 查询(高熵、无网页内容)
  • DNS-over-HTTPS 绕过:员工使用 DoH 绕过企业 DNS 过滤和监控
  • 慢速滴漏式外泄:低流量 DNS 隧道,保持在告警阈值以下(需要基线对比)

输出格式

DNS EXFILTRATION ANALYSIS — WORKSTATION-042
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Period:       2024-03-14 to 2024-03-15
Source:       192.168.1.105 (WORKSTATION-042, Finance Dept)

Findings:
  [CRITICAL] DNS tunneling detected to evil-tunnel[.]com
    Query Volume:       12,847 queries in 18 hours
    Avg Subdomain Len:  63 characters (normal: <20)
    Avg Entropy:        3.82 (threshold: 3.5)
    Query Types:        TXT (89%), A (11%)
    Estimated Data:     ~4.7 MB exfiltrated via DNS
    Rate:               0.58 kbps (slow drip pattern)

  [HIGH] DGA-like domains resolved
    Unique DGA Domains: 247 domains resolved
    Pattern:            15-char random alphanumeric.xyz TLD
    Entropy Range:      3.6 - 4.1

Process Attribution:
  Process:   svchost_update.exe (masquerading — not legitimate svchost)
  PID:       4892
  Parent:    explorer.exe
  Hash:      SHA256: a1b2c3d4... (VT: 34/72 malicious — Cobalt Strike beacon)

Containment:
  [DONE] Host isolated via EDR
  [DONE] Domain evil-tunnel[.]com added to DNS sinkhole
  [DONE] Incident IR-2024-0448 created

评论

支持 Markdown