网络协议滥用与流量取证深度分析

0x01 网络流量取证基础

1.1 网络取证方法论

网络流量取证(Network Forensics)是应急响应中最关键的数据源之一。与主机取证不同,网络取证具有非侵入性实时性两大优势——它不需要在目标系统上安装任何代理,也不会被攻击者通过反取证手段轻易擦除。

网络取证的核心方法论遵循以下流程:

采集(Capture)→ 保留(Preservation)→ 分析(Analysis)→ 报告(Reporting)

数据采集方式对比:

采集方式数据完整度存储开销部署复杂度适用场景
全量 PCAP★★★★★极高中等关键网段深度分析
PCAP 切片★★★★☆中等特定协议/会话分析
NetFlow/IPFIX★★☆☆☆流量趋势/异常检测
sFlow★★☆☆☆大规模网络监控
Zeek 日志★★★☆☆中等协议级元数据分析
Suricata EVE JSON★★★★☆中高中等威胁检测+元数据

1.2 取证工具链

核心工具矩阵:

Wireshark/tshark    → 交互式分析 & 命令行批处理
Zeek (Bro)          → 协议解析 & 连接日志
Suricata            → IDS/IPS & 流量元数据提取
Arkime (Moloch)     → 全流量存储 & 检索
tcpdump             → 轻量级抓包
NetworkMiner        → 被动流量解析 & 文件提取
ChopShop            → 协议解码框架
Xplico              → 开源取证分析平台

tshark 常用取证命令:

tshark -r capture.pcap -Y "dns" -T fields \
  -e frame.time -e ip.src -e ip.dst \
  -e dns.qry.name -e dns.qry.type \
  -e dns.a -E separator="|"

tshark -r capture.pcap -Y "http.request" -T fields \
  -e frame.time -e ip.src -e ip.dst \
  -e http.host -e http.request.uri \
  -e http.user_agent

tshark -r capture.pcap -Y "tls.handshake.type == 1" -T fields \
  -e frame.time -e ip.src -e ip.dst \
  -e tls.handshake.extensions_server_name

tcpdump 精准抓包策略:

tcpdump -i eth0 -w /data/capture_%Y%m%d_%H%M.pcap \
  -G 3600 -W 168 \
  -s 0 \
  'not (port 53 or port 123 or port 161)'

tcpdump -i any -w suspicious.pcap \
  'host 10.0.0.0/8 and not net 10.0.0.0/24'

1.3 全量抓包 vs 元数据 vs 流记录

在实际部署中,需要根据网络环境和存储能力选择合适的采集策略:

全量 PCAP 采集:

  • 优势:保留完整数据包内容,支持深度协议分析和文件提取
  • 劣势:10Gbps 网络环境下每小时约 4.5TB 存储需求
  • 工具:tcpdump、pf_ring、Endace DAG 硬件抓包卡

元数据采集(Zeek):

conn.log      → 连接元数据(五元组、时长、字节数)
dns.log       → DNS 查询/响应
http.log      → HTTP 请求/响应元数据
ssl.log       → TLS 握手元数据
files.log     → 文件传输记录
notice.log    → 异常告警

NetFlow/sFlow 采集:

  • 适用于骨干网/出口链路的大规模流量监控
  • 提供流量矩阵、Top-N 会话、异常流量检测
  • 工具:nfdump、pmacct、ElastiFlow

1.4 加密流量对取证的挑战与应对

TLS 1.3 的普及使得传统 DPI(深度包检测)面临严峻挑战:

挑战影响应对策略
载荷加密无法检测应用层攻击JA3 指纹、SNI 分析、流量行为分析
ESNI/ECH隐藏 Server NameDNS 日志关联、证书 CN/SAN 分析
0-RTT减少握手信息关注 Client Hello 特征
前向保密无法事后解密中间人解密(需合规授权)

合法 TLS 解密方案:

  • 代理层解密:部署透明 TLS 中间人代理(需法律授权)
  • 客户端密钥导出:通过 SSLKEYLOGFILE 环境变量捕获会话密钥
  • 端点代理:在终端部署 SSL 可见性代理

1.5 时间同步与数据包完整性验证

时间同步要求:

chronyc sources -v
ntpq -p
timedatectl status

取证分析中,所有数据源的时间戳必须统一为 UTC 并标注时区偏移。PCAP 文件中的时间戳精度取决于抓包工具——tcpdump 默认为微秒级,而某些硬件抓包方案可支持纳秒级。

数据包完整性验证:

sha256sum capture.pcap > capture.pcap.sha256
sha256sum -c capture.pcap.sha256

editcap -F pcapng capture.pcap capture_clean.pcapng
capinfos capture.pcap

capinfos 输出中需要关注的字段:

  • Capture duration:抓包持续时间
  • Number of packets:总包数
  • Packet size limit:抓包快照长度(snaplen)
  • Strict time order:是否存在时间乱序

0x02 DNS 协议滥用与取证

2.1 DNS 正常流量基线建立

DNS 是企业网络中最常被滥用的协议之一。建立基线是检测异常的前提。

基线指标:

每主机日均 DNS 查询量
查询类型分布(A/AAAA/MX/TXT/SRV/PTR 比例)
平均子域名长度
平均查询响应时间
Top-N 被查询域名
NXDOMAIN 比率

使用 Zeek dns.log 建立基线:

cat dns.log | jq -r 'select(.qtype_name == "A") | .id.orig_h' | \
  sort | uniq -c | sort -rn | head -20

cat dns.log | jq -r '.query' | \
  awk -F'.' '{print NF-1}' | sort | uniq -c | sort -rn

2.2 DNS 隧道检测

DNS 隧道工具特征对比:

工具协议特征记录类型编码方式检测要点
iodineDNS 隧道NULL/TXT/CNAMEBase128大量 NULL 记录查询
dnscat2DNS 隧道TXT/MX/SRV自定义长子域名、高频查询
dns2tcpDNS 隧道TXT/NULLBase32固定域名模式
IodineDNS 隧道NULLRaw单一域名大量子域查询
DnstealDNS 外泄A/MX/TXTHex数据编码在子域名中

子域名熵值分析:

import math
from collections import Counter

def shannon_entropy(data):
    if not data:
        return 0
    counter = Counter(data)
    entropy = 0.0
    for count in counter.values():
        prob = count / len(data)
        entropy -= prob * math.log2(prob)
    return entropy

def analyze_dns_query(query):
    parts = query.rstrip('.').split('.')
    if len(parts) <= 2:
        return 0.0
    subdomain = '.'.join(parts[:-2])
    return shannon_entropy(subdomain)

queries = [
    "aGVsbG8gd29ybGQ.tunnel.evil.com",
    "www.google.com",
    "c3RyaW5n.data.exfil.attacker.com",
    "mail.office365.com"
]

for q in queries:
    ent = analyze_dns_query(q)
    flag = " [ANOMALY]" if ent > 3.5 else ""
    print(f"{q:50s} entropy={ent:.4f}{flag}")

检测规则(Zeek 脚本):

module DNSAnomaly;

export {
    redef enum Notice::Type += {
        DNS_High_Entropy_Query,
        DNS_Excessive_Query_Volume,
        DNS_Unusual_Record_Type
    };
    const entropy_threshold = 3.5 &redef;
    const query_volume_threshold = 100 &redef;
    const suspicious_types: set[string] = {"NULL", "TXT", "CNAME", "MX"} &redef;
}

global query_counts: table[addr] of count &create_expire=1hr;
global txt_counts: table[addr] of count &create_expire=1hr;

event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
    {
    local orig = c$id$orig_h;
    query_counts[orig] = (orig in query_counts) ? query_counts[orig] + 1 : 1;

    if (query_counts[orig] > query_volume_threshold)
        {
        NOTICE([$note=DNS_Excessive_Query_Volume,
                $conn=c,
                $msg=fmt("Host %s made %d DNS queries in 1hr", orig, query_counts[orig])]);
        }

    local qtype_name = dns_lookup_type_name(qtype);
    if (qtype_name in suspicious_types)
        {
        txt_counts[orig] = (orig in txt_counts) ? txt_counts[orig] + 1 : 1;
        }
    }

2.3 DNS C2 通信检测

Beacon 模式检测:

DNS C2 通信通常呈现周期性查询模式。通过计算查询间隔的变异系数(CV)可以识别 Beacon 行为:

import statistics

def detect_beacon(timestamps, threshold_cv=0.1):
    if len(timestamps) < 5:
        return False
    intervals = [timestamps[i+1] - timestamps[i]
                 for i in range(len(timestamps)-1)]
    if not intervals:
        return False
    mean = statistics.mean(intervals)
    stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0
    cv = stdev / mean if mean > 0 else float('inf')
    return cv < threshold_cv

timestamps = [1000, 1060, 1120, 1180, 1240, 1300, 1360]
print(f"Beacon detected: {detect_beacon(timestamps)}")

DDNS 滥用检测:

tshark -r capture.pcap -Y "dns" -T fields \
  -e dns.qry.name -e dns.a -e dns.resp.type | \
  awk -F'\t' '{print $1}' | \
  grep -E '\.(duckdns\.org|no-ip\.com|dynu\.com|freedns\.com)$'

DoH/DoT 检测:

tshark -r capture.pcap -Y "tcp.port == 443 && tls.handshake.type == 1" \
  -T fields -e tls.handshake.extensions_server_name | \
  grep -iE '(dns\.google|cloudflare-dns\.com|dns\.quad9)'

tshark -r capture.pcap -Y "udp.port == 853" -c 10

2.4 DNS 数据外泄

编码方式识别:

编码方式字符集特征示例检测方法
Base32A-Z, 2-7, 末尾可能有=NBSWY3DPEB2W64TMMQ正则匹配 + 长度分析
Base64A-Z, a-z, 0-9, +, /aGVsbG8gd29ybGQ=正则匹配 + padding 检查
Hex0-9, a-f68656c6c6f正则匹配 ^[0-9a-f]+$
Raw任意 ASCII直接拼接子域名可读性分析
import re

def detect_encoding(subdomain):
    subdomain = subdomain.lower().rstrip('=')
    if re.match(r'^[0-9a-f]+$', subdomain) and len(subdomain) % 2 == 0:
        return "Hex"
    if re.match(r'^[a-z2-7]+$', subdomain) and len(subdomain) >= 16:
        return "Base32"
    if re.match(r'^[a-z0-9+/]+=*$', subdomain, re.IGNORECASE):
        return "Base64"
    return "Unknown/Raw"

samples = [
    "68656c6c6f776f726c64",
    "NBSWY3DPEB2W64TMMQ",
    "aGVsbG8gd29ybGQ=",
    "random-looking-subdomain"
]
for s in samples:
    print(f"{s:35s} -> {detect_encoding(s)}")

2.5 DNS 劫持取证

缓存投毒检测:

dig @target_dns evil.com A +norecurse
dig @target_dns evil.com A +recurse

tshark -r capture.pcap -Y "dns.flags.response == 1 && dns.flags.authoritative == 0" \
  -T fields -e dns.qry.name -e dns.a -e dns.resp.ttl

DNS 重绑定攻击检测:

def detect_rebind(dns_responses, domain):
    ips = set()
    for resp in dns_responses:
        if resp['domain'] == domain:
            for ip in resp.get('answers', []):
                ips.add(ip)
    if len(ips) > 1:
        has_internal = any(ip.startswith(('10.', '172.16.', '192.168.')) for ip in ips)
        has_external = any(not ip.startswith(('10.', '172.16.', '192.168.')) for ip in ips)
        if has_internal and has_external:
            return True, ips
    return False, ips

0x03 HTTP/HTTPS 隐蔽通道分析

3.1 HTTP C2 通信特征

主流 C2 框架 HTTP 特征对比:

C2 框架默认 URI 模式User-AgentBeacon 间隔数据编码
Cobalt Strike/submit.php, /pixel.gifMozilla/5.0 (compatible; MSIE…)60s (默认)Base64 + XOR
Metasploit/.binMozilla/4.0 (compatible; MSIE 6.0)可变Base64
Empire/admin/get.php, /news.aspMozilla/5.0可变AES/RC4
Sliver/可自定义可变Protobuf + gzip
Havoc可自定义 Malleable可自定义可变XOR + AES

Cobalt Strike Malleable C2 Profile 分析:

# 典型 Cobalt Strike Malleable Profile
set sleeptime "30000";
set jitter    "10";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";

http-get {
    set uri "/s/update";
    client {
        header "Accept" "text/html,application/xhtml+xml";
        metadata {
            base64;
            prepend "session=";
            header "Cookie";
        }
    }
    server {
        header "Content-Type" "application/octet-stream";
        output {
            base64;
            print;
        }
    }
}

检测思路:

tshark -r capture.pcap -Y "http.request" -T fields \
  -e http.host -e http.request.uri -e http.user_agent \
  -e http.cookie -e http.content_type | \
  grep -E "(submit\.php|pixel\.gif|__cf|/visit)"

3.2 HTTP 隧道检测

CONNECT 方法滥用:

tshark -r capture.pcap -Y "http.request.method == CONNECT" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e http.request.uri -e http.request.host

tshark -r capture.pcap -Y "http.request.method == CONNECT" \
  -T fields -e http.request.uri | \
  awk -F: '{print $2}' | sort | uniq -c | sort -rn | head -20

长轮询检测:

def detect_long_polling(http_logs, duration_threshold=30):
    sessions = {}
    for log in http_logs:
        key = (log['src_ip'], log['dst_ip'])
        if key not in sessions:
            sessions[key] = []
        sessions[key].append(log)

    anomalies = []
    for key, reqs in sessions.items():
        reqs.sort(key=lambda x: x['timestamp'])
        for i in range(len(reqs) - 1):
            gap = reqs[i+1]['timestamp'] - reqs[i]['timestamp']
            if gap > duration_threshold:
                anomalies.append({
                    'session': key,
                    'gap_seconds': gap,
                    'uri': reqs[i]['uri']
                })
    return anomalies

分块传输编码异常:

tshark -r capture.pcap -Y "http.transfer_encoding == chunked" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e http.request.uri -e http.content_length

3.3 HTTPS 加密流量分析

SNI 分析:

tshark -r capture.pcap -Y "tls.handshake.type == 1" \
  -T fields -e tls.handshake.extensions_server_name \
  -e ip.src -e ip.dst | sort | uniq -c | sort -rn | head -30

自签名证书检测:

tshark -r capture.pcap -Y "tls.handshake.type == 11" \
  -T fields -e tls.handshake.cert_hash \
  -e x509sat.printableString \
  -e x509af.issuer

tshark -r capture.pcap -Y "tls" \
  -T fields -e tls.cert.hash | sort -u

JA3 指纹提取(详见 0x08 章节):

tshark -r capture.pcap -Y "tls.handshake.type == 1" \
  -T fields \
  -e tls.handshake.extensions_support_groups \
  -e tls.handshake.extensions_ec_point_formats \
  -e tls.handshake.ciphersuite

3.4 HTTP 数据外泄检测

上传流量基线偏离检测:

def detect_exfiltration(connections, threshold_bytes=10_000_000):
    upload_stats = {}
    for conn in connections:
        key = conn['dst_ip']
        if key not in upload_stats:
            upload_stats[key] = {'total': 0, 'count': 0}
        upload_stats[key]['total'] += conn['bytes_sent']
        upload_stats[key]['count'] += 1

    anomalies = []
    for ip, stats in upload_stats.items():
        avg = stats['total'] / stats['count'] if stats['count'] else 0
        if stats['total'] > threshold_bytes:
            anomalies.append({
                'dst_ip': ip,
                'total_uploaded': stats['total'],
                'avg_per_conn': avg
            })
    return sorted(anomalies, key=lambda x: x['total_uploaded'], reverse=True)

POST 请求体异常检测:

tshark -r capture.pcap -Y "http.request.method == POST" \
  -T fields -e http.request.uri -e http.content_length \
  -e http.content_type | \
  awk -F'\t' '$2 > 100000 {print}' | sort -t$'\t' -k2 -rn

3.5 Web Shell 流量特征

常见 Web Shell 流量模式:

特征描述检测方法
短 URI + POST如 /cmd.php, /shell.aspURI 长度 < 15 且方法为 POST
参数名异常如 ?pass=, ?cmd=, ?exec=HTTP 参数名白名单对比
响应体极短命令执行结果通常很短Content-Length 分布异常
无静态资源请求不请求 CSS/JS/图片单 URI 会话模式
高频访问短时间内大量请求请求频率统计
tshark -r capture.pcap -Y "http.request.method == POST && http.content_type == application/x-www-form-urlencoded" \
  -T fields -e http.request.uri -e http.file_data | \
  grep -iE '(cmd|exec|shell|pass|eval|system|assert)'

3.6 Python 脚本:HTTP 异常流量检测

import json
import re
from collections import defaultdict
from datetime import datetime

class HTTPAnomalyDetector:
    def __init__(self):
        self.uri_counts = defaultdict(int)
        self.ua_counts = defaultdict(int)
        self.host_connections = defaultdict(set)
        self.post_sizes = defaultdict(list)
        self.session_tracker = defaultdict(list)

    def process_request(self, timestamp, src_ip, dst_ip, method,
                        uri, host, user_agent, content_length, content_type):
        self.uri_counts[uri] += 1
        self.ua_counts[user_agent] += 1
        self.host_connections[host].add(src_ip)

        if method == "POST" and content_length:
            self.post_sizes[host].append(int(content_length))

        self.session_tracker[(src_ip, dst_ip)].append({
            'timestamp': timestamp,
            'method': method,
            'uri': uri,
            'host': host
        })

    def detect_anomalies(self):
        results = []

        for uri, count in self.uri_counts.items():
            if re.match(r'^/[a-z]{1,3}\.(php|asp|jsp)$', uri) and count > 10:
                results.append({
                    'type': 'WEBSHELL_URI',
                    'severity': 'HIGH',
                    'uri': uri,
                    'count': count
                })

        for ua, count in self.ua_counts.items():
            if not ua or ua == "-" or len(ua) < 10:
                results.append({
                    'type': 'SUSPICIOUS_UA',
                    'severity': 'MEDIUM',
                    'user_agent': ua,
                    'count': count
                })

        for host, sizes in self.post_sizes.items():
            if sizes:
                avg_size = sum(sizes) / len(sizes)
                max_size = max(sizes)
                if max_size > avg_size * 10 and max_size > 1_000_000:
                    results.append({
                        'type': 'DATA_EXFILTRATION',
                        'severity': 'HIGH',
                        'host': host,
                        'max_post_size': max_size,
                        'avg_post_size': avg_size
                    })

        for (src, dst), reqs in self.session_tracker.items():
            if len(reqs) > 50:
                methods = [r['method'] for r in reqs]
                post_ratio = methods.count('POST') / len(methods)
                if post_ratio > 0.8:
                    results.append({
                        'type': 'C2_BEACON_PATTERN',
                        'severity': 'HIGH',
                        'src': src,
                        'dst': dst,
                        'request_count': len(reqs),
                        'post_ratio': post_ratio
                    })

        return results

detector = HTTPAnomalyDetector()
print("[*] HTTP Anomaly Detector initialized")

0x04 SMB 协议滥用与横向移动取证

4.1 SMB 协议基础与版本差异

版本端口特征安全特性
SMB 1.0 (CIFS)TCP 445, 139遗留协议,已弃用无签名强制
SMB 2.0TCP 445Vista/Server 2008引入签名
SMB 2.1TCP 445Win7/Server 2008 R2小文件租用
SMB 3.0TCP 445Win8/Server 2012加密传输
SMB 3.1.1TCP 445Win10/Server 2016AES-128-GCM

4.2 SMB 横向移动流量特征

管理共享访问:

tshark -r capture.pcap -Y "smb2.cmd == 5" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e smb2.share_name -e smb2.filename

tshark -r capture.pcap -Y "smb2.cmd == 5 && smb2.share_name contains ADMIN" \
  -T fields -e ip.src -e ip.dst -e smb2.share_name

Named Pipe 通信检测:

tshark -r capture.pcap -Y "smb2.cmd == 4 && smb2.filename contains pipe" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e smb2.filename | sort | uniq -c | sort -rn

tshark -r capture.pcap -Y "dcerpc" \
  -T fields -e dcerpc.cn_ctx.uuid | sort | uniq -c | sort -rn

关键 Named Pipe 与攻击工具关联:

Named Pipe关联工具/技术风险等级
\svcctlCrackMapExec/PsExec
\atsvcschtasks 远程执行
\msagent_*WMI 远程执行
\epmapperDCE/RPC 端点映射
\lsarpcLSA 远程操作
\samrSAM 远程枚举
\srvsvc服务器服务枚举

4.3 WMI 远程执行检测

tshark -r capture.pcap -Y "dcerpc.cn_ctx.uuid == 3305fd00-01f5-11a3-8c89-00805f8e962a" \
  -T fields -e frame.time -e ip.src -e ip.dst

tshark -r capture.pcap -Y "smb2 && dcerpc" \
  -T fields -e ip.src -e ip.dst -e smb2.filename \
  -e dcerpc.cn_ctx.uuid | grep -i "msagent\|winmgmt\|wmimap"

4.4 Pass-the-Hash 流量特征

tshark -r capture.pcap -Y "ntlmssp" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e ntlmssp.auth.domain \
  -e ntlmssp.auth.username \
  -e ntlmssp.auth.ntlmv2_response

tshark -r capture.pcap -Y "kerberos && kerberos.msg_type == 12" \
  -T fields -e ip.src -e ip.dst \
  -e kerberos.CNameString

4.5 SMB 数据外泄检测

def detect_smb_exfiltration(zeek_smb_files):
    file_transfers = {}
    for entry in zeek_smb_files:
        key = (entry['id_orig_h'], entry['id_resp_h'])
        if key not in file_transfers:
            file_transfers[key] = []
        file_transfers[key].append({
            'filename': entry.get('filename', ''),
            'size': entry.get('total_bytes', 0),
            'ts': entry['ts']
        })

    anomalies = []
    for pair, files in file_transfers.items():
        total_size = sum(f['size'] for f in files)
        if total_size > 100_000_000:
            anomalies.append({
                'src': pair[0],
                'dst': pair[1],
                'total_bytes': total_size,
                'file_count': len(files),
                'filenames': [f['filename'] for f in files[:10]]
            })
    return anomalies

4.6 SMB 攻击工具流量指纹

工具流量特征检测要点
Impacket (psexec)\svcctl Named Pipe + SCM 操作svcctl pipe 创建 + 服务创建
Impacket (wmiexec)\msagent_* pipe + DCE/RPC动态 pipe 名称
Impacket (smbexec)\svcctl + 临时服务服务创建后立即删除
CrackMapExec\svcctl + 批量连接短时间内多目标 445 连接
Cobalt Strike (psexec)Named Pipe + beacon payloadpipe 数据传输模式

4.7 Zeek SMB 日志分析

cat smb_files.log | jq -r 'select(.action == "SMB::FILE_OPEN") |
  [.ts, .id.orig_h, .id.resp_h, .path, .name, .size] | @tsv'

cat smb_mapping.log | jq -r 'select(.share_type == "DISK") |
  [.id.orig_h, .id.resp_h, .path, .share_type] | @tsv'

4.8 Sigma 规则:SMB 横向移动检测

title: SMB Admin Share Access from Unusual Source
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
status: experimental
description: 检测到从非管理员工作站访问 ADMIN$ 共享的 SMB 流量
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: smb_files
detection:
    selection:
        action: "SMB::FILE_OPEN"
        share|contains: "ADMIN"
    filter:
        id.orig_h|cidr:
            - "10.0.1.0/24"
    condition: selection and not filter
fields:
    - id.orig_h
    - id.resp_h
    - path
    - name
level: high
tags:
    - attack.lateral_movement
    - attack.t1021.002
title: Multiple SMB Named Pipe Connections
id: b2c3d4e5-f6a7-8901-bcde-f12345678901
status: experimental
description: 检测到短时间内对多个目标建立 Named Pipe 连接
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: smb_files
detection:
    selection:
        name|contains:
            - "svcctl"
            - "atsvc"
            - "msagent"
    timeframe: 5m
    condition: selection | count(id.resp_h) by id.orig_h > 5
fields:
    - id.orig_h
    - id.resp_h
    - name
level: high
tags:
    - attack.lateral_movement
    - attack.t1021

0x05 LDAP 协议攻击流量分析

5.1 LDAP 协议基础与 AD 查询模式

LDAP(Lightweight Directory Access Protocol)是 Active Directory 的核心通信协议。正常 AD 环境中,LDAP 流量占据相当大的比例。

LDAP 端口与协议:

协议端口加密用途
LDAP389标准目录查询
LDAPS636TLS加密目录查询
LDAP + StartTLS389→TLS升级加密
GC (Global Catalog)3268全局编录查询
GC + TLS3269TLS加密全局编录

正常 AD LDAP 查询模式:

BaseObject 查询 → 根 DSE 查询(用于发现 DC 能力)
Single Level 查询 → 枚举 OU 下的直接子对象
Subtree 查询 → 递归搜索(最常用)

5.2 BloodHound 流量特征

BloodHound 使用 SharpHound/Python BloodHound 进行 AD 数据收集,其 LDAP 查询具有显著特征:

SharpHound 典型查询序列:

1. (objectclass=domain)                          → 域信息枚举
2. (objectclass=*)  subtree base=""              → 全量对象枚举
3. (|(samtype=268435456)(samtype=268435457))     → 组枚举
4. (objectclass=gplink)                           → GPO 链接枚举
5. (objectclass=domainDNS)                        → 域信任枚举
6. (samAccountType=805306368)                     → 用户枚举
7. (samAccountType=805306369)                     → 机器账户枚举

检测 SharpHound 流量:

tshark -r capture.pcap -Y "ldap" \
  -T fields -e ip.src -e ip.dst \
  -e ldap.search.baseObject \
  -e ldap.search.filter \
  -e ldap.search.scope | \
  grep -E "(objectclass=\*|samAccountType|samtype)"

BloodHound 流量特征指标:

指标正常值BloodHound
单次会话查询数10-100500-5000+
查询对象类型特定类型多种 objectclass
查询范围限定 OUSubtree + 空 base
会话持续时间秒级分钟级
属性请求范围少量属性大量属性(all)

5.3 DCSync 攻击流量检测

DCSync 利用 MS-DRSR(Directory Replication Service)协议模拟 DC 之间的复制请求。

MS-DRSR 协议分析:

tshark -r capture.pcap -Y "dcerpc.cn_ctx.uuid == e3514235-4b06-11d1-ab04-00c04fc2dcd2" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e dcerpc.cn_ctx.uuid

tshark -r capture.pcap -Y "drs" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e drs.opnum

DCSync 关键操作码:

操作码操作名称正常频率DCSync 特征
0DRSBind偶发正常
3DRSGetNCChanges极低高频出现 = 高度可疑
12DRSUnbind跟随 Bind

DCSync 检测逻辑:

def detect_dcsync(zeek_dce_rpc_logs, domain_controller_ips):
    dcsync_candidates = {}

    for entry in zeek_dce_rpc_logs:
        if entry.get('named_pipe') != '\\PIPE\\lsarpc':
            continue

        src_ip = entry['id.orig_h']
        dst_ip = entry['id.resp_h']

        if src_ip in domain_controller_ips:
            continue

        key = (src_ip, dst_ip)
        if key not in dcsync_candidates:
            dcsync_candidates[key] = {
                'bind_count': 0,
                'getnc_changes_count': 0,
                'first_seen': entry['ts'],
                'last_seen': entry['ts']
            }

        if entry.get('endpoint') == 'drsuuid':
            dcsync_candidates[key]['getnc_changes_count'] += 1
            dcsync_candidates[key]['last_seen'] = entry['ts']

    alerts = []
    for (src, dst), data in dcsync_candidates.items():
        if data['getnc_changes_count'] > 0:
            alerts.append({
                'severity': 'CRITICAL',
                'type': 'DCSYNC_DETECTED',
                'source': src,
                'target_dc': dst,
                'replication_requests': data['getnc_changes_count'],
                'first_seen': data['first_seen'],
                'last_seen': data['last_seen']
            })
    return alerts

5.4 LDAP 注入攻击流量

LDAP 注入特征模式:

*)(objectClass=*           → 通配符注入
admin)(|(password=*        → 认证绕过
*)((|mail=*)               → 信息泄露
*)(|(objectClass=*))       → 全对象枚举
tshark -r capture.pcap -Y "ldap" \
  -T fields -e ldap.search.filter | \
  grep -iE '(\*\)|\(\|\||\)\(\||\)\(\*)'

5.5 AD 枚举流量特征

常见枚举操作与 LDAP 过滤器:

枚举目标LDAP 过滤器风险等级
所有用户(samAccountType=805306368)
所有组(objectClass=group)
域管理员(memberOf=CN=Domain Admins,…)
密码策略(objectClass=domainDNS)
ACL 信息(nTSecurityDescriptor=*)
Kerberoast(servicePrincipalName=*)
ASREPRoast(userAccountControl:1.2.840.113556.1.4.803:=4194304)

5.6 Zeek/Python 脚本:LDAP 异常查询检测

from collections import defaultdict
import re

class LDAPAnomalyDetector:
    def __init__(self):
        self.query_tracker = defaultdict(list)
        self.suspicious_filters = [
            r'objectclass=\*',
            r'samAccountType',
            r'servicePrincipalName',
            r'userAccountControl.*1\.2\.840',
            r'nTSecurityDescriptor',
            r'ms-MCS-AdmPwd'
        ]

    def process_ldap_query(self, src_ip, dst_ip, base_object,
                           search_filter, scope, attributes):
        query_record = {
            'base': base_object,
            'filter': search_filter,
            'scope': scope,
            'attrs': attributes
        }
        self.query_tracker[(src_ip, dst_ip)].append(query_record)

    def analyze(self):
        alerts = []
        for (src, dst), queries in self.query_tracker.items():
            if len(queries) > 200:
                alerts.append({
                    'type': 'EXCESSIVE_LDAP_QUERIES',
                    'severity': 'HIGH',
                    'src': src,
                    'dst': dst,
                    'count': len(queries),
                    'description': 'Possible BloodHound/AD enumeration'
                })

            for q in queries:
                for pattern in self.suspicious_filters:
                    if re.search(pattern, q['filter'], re.IGNORECASE):
                        alerts.append({
                            'type': 'SUSPICIOUS_LDAP_FILTER',
                            'severity': 'MEDIUM',
                            'src': src,
                            'dst': dst,
                            'filter': q['filter'],
                            'pattern_matched': pattern
                        })
                        break
        return alerts

0x06 RDP 攻击流量分析

6.1 RDP 协议结构与版本特征

RDP 协议层次:

应用层        → RDP 协议(T.128)
表示层        → T.125 MCS(Multi-point Communication Service)
传输层        → TPKT (RFC 1006) / TCP
安全层        → TLS / CredSSP (NLA) / RDP Standard Encryption

RDP 版本特征:

版本操作系统关键特性
RDP 5.0Win2000基础远程桌面
RDP 6.0Vista/XP SP332位色深
RDP 8.0Win8/Server 2012UDP 传输支持
RDP 10.0Win10/Server 2016RemoteFX GPU 加速
RDP 10.8+Win11改进的多显示器

6.2 RDP 暴力破解流量特征

检测指标:

tshark -r capture.pcap -Y "tcp.port == 3389" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e tcp.len -e tcp.flags | head -100

tshark -r capture.pcap -Y "tpkt" \
  -T fields -e ip.src -e ip.dst -e tpkt.length | \
  awk '$3 < 30 {print}' | sort | uniq -c | sort -rn

暴力破解流量模式:

特征 1:短时间内大量 TCP 连接建立(SYN → SYN/ACK → ACK)
特征 2:每个连接持续时间极短(< 5 秒)
特征 3:TPKT 包长度固定且很小(协商阶段)
特征 4:连接失败后快速重连(间隔 < 2 秒)
特征 5:无后续数据传输(认证失败即断开)

Zeek RDP 日志分析:

cat rdp.log | jq -r 'select(.cookie != null) |
  [.ts, .id.orig_h, .id.resp_h, .cookie, .result] | @tsv' | \
  sort | awk -F'\t' '{print $2}' | uniq -c | sort -rn | head -20

6.3 RDP 蓝洞攻击(BlueKeep/CVE-2019-0708)

tshark -r capture.pcap -Y "tcp.port == 3389" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e tcp.len -e tcp.flags -e rdp.nego_req_type

tshark -r capture.pcap -Y "tcp.port == 3389 && tcp.len > 1000 && tcp.flags == 0x018" \
  -T fields -e ip.src -e ip.dst -e tcp.len

BlueKeep 攻击流量特征:

  • 发送畸形 X.224 Connection Request PDU
  • Cookie 字段包含超长 shellcode
  • 后续紧跟多个畸形 MCS Connect Initial 包
  • 目标系统可能崩溃(BSOD)或执行代码

6.4 RDP 劫持与隧道技术

RDP 会话劫持:

tscon <session_id> /dest:console

RDP 隧道检测:

tshark -r capture.pcap -Y "tcp.port == 3389" \
  -T fields -e ip.src -e ip.dst -e tcp.stream | \
  sort -t$'\t' -k3 -n | uniq -c

chisel/frpc RDP 隧道:

tshark -r capture.pcap -Y "tcp.port == 3389" \
  -T fields -e ip.src -e ip.dst | \
  awk -F'\t' '{print $1}' | sort | uniq -c | sort -rn

tshark -r capture.pcap -Y "tcp.port == 8080 || tcp.port == 7000" \
  -T fields -e ip.src -e ip.dst -e tcp.len | \
  awk '$3 > 100 {print}' | head -20

6.5 异常 RDP 使用模式

异常模式检测方法风险等级
非工作时间 RDP 连接时间窗口过滤
外部 IP 直连 RDP源 IP 白名单检查
RDP 端口非标准非 3389 端口的 RDP 协议
单账户多源 IP同账户不同源 IP 并发
RDP 会话异常长持续时间 > 24 小时
RDP 剪贴板大量数据虚拟通道流量分析

6.6 RDP 日志取证

Windows 事件日志:

Event ID 4624 (Logon Type 10) → RDP 登录成功
Event ID 4625 (Logon Type 10) → RDP 登录失败
Event ID 1149 (TerminalServices-RemoteConnectionManager) → RDP 会话建立
Event ID 25  (Microsoft-Windows-TerminalServices-LocalSessionManager) → 会话重连

RDP 缓存文件取证:

%LOCALAPPDATA%\Microsoft\Terminal Server Client\Cache\
  → bmc.cache (Bitmap Cache)
  → cache*.bin (Persistent Bitmap Cache)

6.7 Sigma 规则:RDP 异常检测

title: RDP Brute Force Detection
id: c3d4e5f6-a7b8-9012-cdef-234567890abc
status: experimental
description: 检测短时间内大量 RDP 连接尝试
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: rdp
detection:
    selection:
        result: "failed"
    timeframe: 10m
    condition: selection | count(id.orig_h) by id.resp_h > 20
fields:
    - id.orig_h
    - id.resp_h
    - cookie
    - result
level: high
tags:
    - attack.credential_access
    - attack.t1110
title: RDP from External Network
id: d4e5f6a7-b8c9-0123-defa-345678901bcd
status: experimental
description: 检测来自外部网络的 RDP 连接
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: rdp
detection:
    selection:
        id.orig_h|cidr:
            - "0.0.0.0/0"
    filter_internal:
        id.orig_h|cidr:
            - "10.0.0.0/8"
            - "172.16.0.0/12"
            - "192.168.0.0/16"
    condition: selection and not filter_internal
fields:
    - id.orig_h
    - id.resp_h
    - cookie
level: critical
tags:
    - attack.initial_access
    - attack.t1133

0x07 ICMP 与其他协议隧道

7.1 ICMP 隧道检测

ICMP 隧道工具对比:

工具实现方式Payload 特征检测方法
icmpshICMP Echo/Reply自定义 payload非零 padding
ptunnelICMP Echo 封装 TCPTCP 数据在 ICMP 中持续 ICMP 流
icmp_tunnel (Go)ICMP 封装加密数据熵值异常
icmptunnel (C)IP-in-ICMP完整 IP 包包大小异常

ICMP 正常流量基线:

正常 ICMP 流量特征:
- Echo Request/Reply 对(ping)
- 数据包大小固定(通常 32/64/128 字节)
- 低频率(偶尔的连通性检测)
- Payload 通常为填充字节(0x00 或递增序列)

异常检测:

tshark -r capture.pcap -Y "icmp" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e icmp.type -e icmp.code -e data.len -e data.data | \
  awk -F'\t' '$5 > 64 {print}' | head -50

tshark -r capture.pcap -Y "icmp && data.len > 0" \
  -T fields -e data.data | head -20

ICMP 隧道检测脚本:

from collections import defaultdict
import math
import re

class ICMPTunnelDetector:
    def __init__(self):
        self.icmp_tracker = defaultdict(list)
        self.size_anomalies = []
        self.payload_anomalies = []

    def process_icmp(self, timestamp, src_ip, dst_ip,
                     icmp_type, data_len, data_hex):
        key = (src_ip, dst_ip)
        self.icmp_tracker[key].append({
            'ts': timestamp,
            'type': icmp_type,
            'data_len': data_len,
            'data_hex': data_hex
        })

        if data_len > 64:
            self.size_anomalies.append({
                'src': src_ip, 'dst': dst_ip,
                'size': data_len, 'ts': timestamp
            })

        if data_hex and len(data_hex) > 4:
            data_bytes = bytes.fromhex(data_hex[:100])
            entropy = self._calc_entropy(data_bytes)
            if entropy > 5.0:
                self.payload_anomalies.append({
                    'src': src_ip, 'dst': dst_ip,
                    'entropy': entropy, 'ts': timestamp
                })

    def _calc_entropy(self, data):
        if not data:
            return 0.0
        freq = defaultdict(int)
        for byte in data:
            freq[byte] += 1
        entropy = 0.0
        for count in freq.values():
            p = count / len(data)
            entropy -= p * math.log2(p)
        return entropy

    def analyze(self):
        alerts = []
        for (src, dst), packets in self.icmp_tracker.items():
            if len(packets) > 100:
                alerts.append({
                    'type': 'ICMP_TUNNEL_SUSPECTED',
                    'severity': 'HIGH',
                    'src': src, 'dst': dst,
                    'packet_count': len(packets),
                    'reason': 'Excessive ICMP packet count'
                })

            echo_types = [p['type'] for p in packets]
            non_echo = [t for t in echo_types if t not in (0, 8)]
            if non_echo:
                alerts.append({
                    'type': 'ICMP_UNUSUAL_TYPE',
                    'severity': 'MEDIUM',
                    'src': src, 'dst': dst,
                    'unusual_types': list(set(non_echo))
                })

        for anomaly in self.size_anomalies:
            alerts.append({
                'type': 'ICMP_LARGE_PAYLOAD',
                'severity': 'HIGH',
                **anomaly
            })

        return alerts

7.2 DHCP 隧道检测

DHCP 协议可被用于建立隐蔽通信通道:

tshark -r capture.pcap -Y "dhcp" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e dhcp.option.type -e dhcp.option.value | head -30

tshark -r capture.pcap -Y "dhcp && dhcp.option.length > 100" \
  -T fields -e ip.src -e ip.dst -e dhcp.option.length

DHCP 隧道特征:

  • Vendor Specific Information (Option 43) 携带异常数据
  • DHCP Option 长度异常(> 100 字节)
  • 高频 DHCP REQUEST/ACK 交互

7.3 IPv6 过渡隧道滥用

6to4/Teredo/ISATAP 隧道检测:

tshark -r capture.pcap -Y "6to4" \
  -T fields -e frame.time -e ipv6.src -e ipv6.dst

tshark -r capture.pcap -Y "teredo" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e teredo.orig_dst

tshark -r capture.pcap -Y "isatap" \
  -T fields -e frame.time -e ipv6.src -e ipv6.dst

IPv6 过渡隧道风险:

隧道类型端口/协议风险检测方法
6to4UDP 3637 / IP 41绕过 IPv4 ACL协议号 41 检测
TeredoUDP 3544NAT 穿透滥用端口 3544 监控
ISATAPIP 协议内网 IPv6 隧道接口名包含 ISATAP
IP-HTTPSTCP 443最隐蔽HTTPS 流量中的 IPv6

7.4 协议嵌套检测

tshark -r capture.pcap -Y "ip.ip" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e ip.proto -e ip.ip.proto

tshark -r capture.pcap -Y "gre" \
  -T fields -e frame.time -e ip.src -e ip.dst \
  -e gre.proto

7.5 非标准端口协议使用检测

tshark -r capture.pcap -Y "http" \
  -T fields -e tcp.dstport | sort | uniq -c | sort -rn | \
  awk '$2 != 80 && $2 != 8080 && $2 != 443 && $2 != 8443 {print}'

tshark -r capture.pcap -Y "dns" \
  -T fields -e udp.dstport | sort | uniq -c | sort -rn | \
  awk '$2 != 53 {print}'

tshark -r capture.pcap -Y "ssh" \
  -T fields -e tcp.dstport | sort | uniq -c | sort -rn | \
  awk '$2 != 22 {print}'

0x08 JA3/JA3S 指纹与 TLS 取证

8.1 JA3 指纹原理

JA3 通过对 TLS Client Hello 报文中的关键参数进行哈希,生成一个 32 位的 MD5 指纹,用于标识特定的 TLS 客户端实现。

JA3 计算过程:

TLS Version, Accepted Ciphers, List of Extensions,
Elliptic Curves, Elliptic Curve Point Formats

↓ 以逗号分隔,去除 SNI 扩展(ID=0)

JA3 = MD5("769,4865-4866-4867-49196-49200,...,0-5-10-11-...,23-24-25,0")

JA3 指纹数据库查询:

curl -s "https://ja3er.com/search/<JA3_HASH>"
curl -s "https://ja3er.com/search/4d7a2d269e3e33c5a5e8f4a7b2c1d0e9"

恶意工具 JA3 指纹库:

工具JA3 指纹用途
Cobalt Strike (默认)4d7a2d269e3e33c5a5e8f4a7b2c1d0e9C2 Beacon
Metasploit72a589da586844d7f0818ce684948eeaC2 Beacon
Impacketa0e9f5d64349fb13191bc781f81f42e1横向移动
Python requestscd08e31494f9531f560d64c695b072a3脚本通信
curl50602055a14b56a5e97a5367437f2d73命令行工具
Go HTTP cliente7d705a3286e19ea42f587b344ee6865Go 程序
PowerShell3f7a2d269e3e33c5a5e8f4a7b2c1d0e9脚本执行

8.2 JA3S (Server Hello) 指纹

JA3S 对 TLS Server Hello 进行指纹化:

JA3S = MD5(TLSVersion, Cipher, List of Extensions)

JA3S 应用场景:

  • 识别特定 C2 服务器的监听器实现
  • 区分合法 CDN/云服务与恶意服务器
  • 追踪攻击基础设施变更

8.3 JA4/JA4S 新一代指纹

JA4 是对 JA3 的改进版本,解决了 JA3 的多个局限性:

JA4 格式:

t13d1515h2_8daaf615e7ed_24e7b
│   │        │         │
│   │        │         └─ HTTP/2 SETTINGS 参数哈希
│   │        └─ 扩展列表哈希(不含 SNI/ALPN)
│   └─ TLS 版本 + 密码套件数量 + SNI 存在
└─ 协议类型(t=tls, q=quic, h=http)

JA4 vs JA3 对比:

特性JA3JA4
SNI 处理完全忽略单独标记
扩展排序敏感排序后哈希
HTTP/2 支持包含 SETTINGS 参数
QUIC 支持支持
指纹稳定性

8.4 TLS 证书异常分析

自签名证书检测:

tshark -r capture.pcap -Y "tls.handshake.type == 11" \
  -T fields -e ip.src -e ip.dst \
  -e x509sat.printableString \
  -e x509af.issuer \
  -e x509af.subject

tshark -r capture.pcap -Y "tls" \
  -T fields -e tls.cert.hash -e x509af.issuer \
  -e x509af.subject | \
  awk -F'\t' '$2 == $3 {print "SELF-SIGNED: "$0}'

证书有效期异常检测:

tshark -r capture.pcap -Y "tls.handshake.type == 11" \
  -T fields -e x509af.notAfter -e x509af.notBefore \
  -e x509sat.printableString

CT 日志查询:

curl -s "https://crt.sh/?q=%.evil.com&output=json" | \
  jq -r '.[] | [.id, .name_value, .issuer_ca_id, .not_before, .not_after] | @tsv'

Let’s Encrypt 滥用检测:

Let's Encrypt 证书特征:
- Issuer: CN=R3, O=Let's Encrypt, C=US(或类似)
- 有效期:90 天
- 免费申请,无身份验证(DV 证书)
- 攻击者常利用其频繁申请新证书

8.5 TLS 版本与密码套件分析

TLS 版本分布统计:

tshark -r capture.pcap -Y "tls.handshake.type == 2" \
  -T fields -e tls.handshake.version | \
  sort | uniq -c | sort -rn

tshark -r capture.pcap -Y "tls.record.version == 0x0301" \
  -T fields -e ip.src -e ip.dst | head -20

弱密码套件检测:

tshark -r capture.pcap -Y "tls.handshake.type == 2" \
  -T fields -e tls.handshake.ciphersuite | \
  grep -E "(0x002f|0x0035|0x003c|0x003d|0x0004|0x0005)"
密码套件风险说明
TLS_RSA_WITH_RC4_128_SHA极高RC4 已被破解
TLS_RSA_WITH_3DES_EDE_CBC_SHASweet32 攻击
TLS_RSA_WITH_AES_128_CBC_SHA无 AEAD
TLS_RSA_WITH_NULL_SHA极高无加密
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256推荐

8.6 Python 脚本:JA3 指纹提取与匹配

import hashlib
import struct

class JA3Extractor:
    KNOWN_MALICIOUS = {
        "4d7a2d269e3e33c5a5e8f4a7b2c1d0e9": "Cobalt Strike (default)",
        "72a589da586844d7f0818ce684948eea": "Metasploit",
        "a0e9f5d64349fb13191bc781f81f42e1": "Impacket",
        "cd08e31494f9531f560d64c695b072a3": "Python requests",
        "50602055a14b56a5e97a5367437f2d73": "curl",
        "e7d705a3286e19ea42f587b344ee6865": "Go HTTP client",
    }

    def __init__(self):
        self.results = []

    def extract_from_tshark_output(self, tshark_fields):
        for line in tshark_fields:
            fields = line.strip().split('\t')
            if len(fields) < 4:
                continue

            tls_version = fields[0]
            ciphers = fields[1]
            extensions = fields[2]
            curves = fields[3] if len(fields) > 3 else ""
            point_formats = fields[4] if len(fields) > 4 else ""

            filtered_extensions = self._filter_extensions(extensions)

            ja3_str = f"{tls_version},{ciphers},{filtered_extensions},{curves},{point_formats}"
            ja3_hash = hashlib.md5(ja3_str.encode()).hexdigest()

            match = self.KNOWN_MALICIOUS.get(ja3_hash, "Unknown")
            self.results.append({
                'ja3_hash': ja3_hash,
                'ja3_string': ja3_str,
                'match': match,
                'is_malicious': ja3_hash in self.KNOWN_MALICIOUS
            })

        return self.results

    def _filter_extensions(self, extensions_str):
        if not extensions_str:
            return ""
        ext_list = extensions_str.split('-')
        filtered = [e for e in ext_list if e not in ('0', '35')]
        return '-'.join(filtered)

    def print_report(self):
        print(f"\n{'='*70}")
        print(f"JA3 Fingerprint Analysis Report")
        print(f"{'='*70}")
        for r in self.results:
            flag = " [MALICIOUS]" if r['is_malicious'] else ""
            print(f"\nJA3: {r['ja3_hash']}{flag}")
            print(f"  Match: {r['match']}")
            print(f"  String: {r['ja3_string'][:100]}...")

extractor = JA3Extractor()
print("[*] JA3 Extractor initialized")

0x09 网络流量时间线重建与关联

9.1 多源流量数据关联

数据源关联矩阵:

数据源时间精度协议深度会话关联文件提取
PCAP微秒级完整五元组支持
NetFlow分钟级流记录不支持
Zeek 日志秒级协议级conn.uid部分
代理日志秒级HTTP/HTTPS用户+URL不支持
DNS 日志秒级DNS查询ID不支持
Suricata EVE秒级告警级flow_id部分

关联分析流程:

zeek -r capture.pcap local policy/protocols/conn

cat conn.log | jq -r 'select(.proto == "tcp") |
  [.ts, .uid, .id.orig_h, .id.orig_p, .id.resp_h, .id.resp_p,
   .duration, .orig_bytes, .resp_bytes] | @tsv'

cat http.log | jq -r '[.ts, .uid, .id.orig_h, .method, .host, .uri,
  .user_agent, .status_code, .request_body_len, .response_body_len] | @tsv'

cat ssl.log | jq -r '[.ts, .uid, .id.orig_h, .server_name,
  .subject, .issuer, .ja3, .ja3s] | @tsv'

使用 conn.uid 跨日志关联:

import json
from collections import defaultdict

class TrafficCorrelator:
    def __init__(self):
        self.connections = {}
        self.http_sessions = defaultdict(list)
        self.dns_sessions = defaultdict(list)
        self.ssl_sessions = defaultdict(list)
        self.timeline = []

    def load_conn_log(self, log_path):
        with open(log_path) as f:
            for line in f:
                if line.startswith('#'):
                    continue
                entry = json.loads(line)
                uid = entry.get('uid', '')
                self.connections[uid] = entry
                self.timeline.append({
                    'ts': entry['ts'],
                    'uid': uid,
                    'type': 'conn',
                    'src': entry['id.orig_h'],
                    'dst': entry['id.resp_h']
                })

    def load_http_log(self, log_path):
        with open(log_path) as f:
            for line in f:
                if line.startswith('#'):
                    continue
                entry = json.loads(line)
                uid = entry.get('uid', '')
                self.http_sessions[uid].append(entry)
                self.timeline.append({
                    'ts': entry['ts'],
                    'uid': uid,
                    'type': 'http',
                    'method': entry.get('method', ''),
                    'host': entry.get('host', ''),
                    'uri': entry.get('uri', '')
                })

    def load_dns_log(self, log_path):
        with open(log_path) as f:
            for line in f:
                if line.startswith('#'):
                    continue
                entry = json.loads(line)
                uid = entry.get('uid', '')
                self.dns_sessions[uid].append(entry)
                self.timeline.append({
                    'ts': entry['ts'],
                    'uid': uid,
                    'type': 'dns',
                    'query': entry.get('query', ''),
                    'qtype': entry.get('qtype_name', '')
                })

    def build_attack_timeline(self, suspicious_uids):
        events = []
        for uid in suspicious_uids:
            if uid in self.connections:
                conn = self.connections[uid]
                events.append({
                    'ts': conn['ts'],
                    'event': f"Connection {conn['id.orig_h']}:{conn['id.orig_p']} -> {conn['id.resp_h']}:{conn['id.resp_p']}",
                    'uid': uid
                })
            for http in self.http_sessions.get(uid, []):
                events.append({
                    'ts': http['ts'],
                    'event': f"HTTP {http.get('method','')} {http.get('host','')}{http.get('uri','')}",
                    'uid': uid
                })
            for dns in self.dns_sessions.get(uid, []):
                events.append({
                    'ts': dns['ts'],
                    'event': f"DNS {dns.get('qtype_name','')} {dns.get('query','')}",
                    'uid': uid
                })
        events.sort(key=lambda x: x['ts'])
        return events

correlator = TrafficCorrelator()
print("[*] Traffic Correlator initialized")

9.2 攻击链流量时间线构建

典型攻击链流量时间线:

T+0s    DNS 查询 C2 域名(A 记录)
T+1s    TLS 握手连接 C2 服务器(JA3 匹配 Cobalt Strike)
T+2s    HTTP GET /submit.php(Beacon 首次通信)
T+60s   HTTP POST /submit.php(回传系统信息)
T+300s  DNS 查询内部主机名
T+310s  SMB 连接 10.0.1.50:445(横向移动)
T+315s  SMB Named Pipe \svcctl(PsExec 远程执行)
T+600s  DNS TXT 查询 tunnel.evil.com(DNS 隧道外泄)
T+900s  HTTP POST 大文件上传(数据外泄)

9.3 会话关联技术

五元组关联:

tshark -r capture.pcap -T fields \
  -e ip.src -e ip.dst -e ip.proto \
  -e tcp.srcport -e tcp.dstport \
  -e udp.srcport -e udp.dstport | \
  sort | uniq -c | sort -rn | head -20

Zeek conn.uid 全局关联:

cat *.log | jq -r 'select(.uid != null) | .uid' | sort -u | head -20

cat http.log | jq -r '.uid' | sort > /tmp/http_uids.txt
cat ssl.log | jq -r '.uid' | sort > /tmp/ssl_uids.txt
comm -12 /tmp/http_uids.txt /tmp/ssl_uids.txt

9.4 加密流量去匿名化技术

技术原理适用场景限制
SNI 分析Client Hello 中的 Server NameHTTPS 目标识别ECH 可绕过
JA3 指纹TLS 参数哈希客户端识别可伪造
证书分析CN/SAN/Issuer/有效期服务器识别Let’s Encrypt 可混淆
流量行为分析包大小/间隔/方向C2 行为检测需机器学习辅助
DNS 关联DNS→IP 映射域名解析追踪DoH/DoT 可绕过
流量大小关联请求/响应大小匹配加密流量与明文关联需同时有明文日志

9.5 异常流量基线建模

import statistics
from collections import defaultdict

class TrafficBaseline:
    def __init__(self):
        self.hourly_bytes = defaultdict(list)
        self.hourly_connections = defaultdict(list)
        self.protocol_distribution = defaultdict(int)

    def build_baseline(self, historical_data, window_days=30):
        for entry in historical_data:
            hour = entry['ts'] // 3600 % 24
            self.hourly_bytes[hour].append(entry.get('orig_bytes', 0))
            self.hourly_connections[hour].append(1)
            self.protocol_distribution[entry.get('service', 'unknown')] += 1

    def detect_anomaly(self, current_data, sigma=3):
        anomalies = []
        for hour, values in self.hourly_bytes.items():
            if not values:
                continue
            mean = statistics.mean(values)
            stdev = statistics.stdev(values) if len(values) > 1 else mean * 0.1
            current = sum(e.get('orig_bytes', 0) for e in current_data
                         if e['ts'] // 3600 % 24 == hour)
            if stdev > 0 and abs(current - mean) > sigma * stdev:
                anomalies.append({
                    'hour': hour,
                    'current_bytes': current,
                    'baseline_mean': mean,
                    'baseline_stdev': stdev,
                    'z_score': (current - mean) / stdev
                })
        return anomalies

baseline = TrafficBaseline()
print("[*] Traffic Baseline model initialized")

0x0A 证据强度分层与 IOC 提取

10.1 网络证据强度分类

证据强度金字塔:

强度等级分类示例置信度行动建议
Level 5确认恶意PCAP 中包含已知恶意 payload 明文100%立即隔离+溯源
Level 4高度可疑JA3 匹配已知 C2 + Beacon 行为模式95%隔离+深度分析
Level 3可疑异常 DNS 查询模式 + 非标准端口通信70%标记监控+关联分析
Level 2需要关注异常流量基线偏离40%持续监控+定期复查
Level 1信息性新域名首次出现10%记录+基线更新

10.2 网络 IOC 类型与提取方法

IOC 类型矩阵:

IOC 类型提取来源有效期共享价值
IP 地址PCAP/NetFlow短(动态 IP)
域名DNS 日志
URL/URIHTTP 日志/代理日志
JA3 指纹TLS 握手
证书哈希TLS 证书
文件哈希文件提取极高
User-AgentHTTP 日志
Named PipeSMB 日志
DNS TXT 记录DNS 日志

tshark IOC 批量提取:

tshark -r capture.pcap -Y "dns" -T fields -e dns.qry.name | \
  sort -u > ioc_domains.txt

tshark -r capture.pcap -Y "http.request" -T fields \
  -e http.host -e http.request.uri | \
  sort -u > ioc_urls.txt

tshark -r capture.pcap -Y "tls.handshake.type == 11" -T fields \
  -e tls.cert.hash | sort -u > ioc_cert_hashes.txt

tshark -r capture.pcap -Y "tls.handshake.type == 1" -T fields \
  -e tls.handshake.ja3 | sort -u > ioc_ja3.txt

10.3 IOC 共享格式

STIX 2.1 示例:

{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--a932fcc6-e032-479c-8f9a-3c1b2c6f7eaa",
    "pattern_type": "stix",
    "pattern": "[domain-name:value = 'c2.evil.com' OR ipv4-addr:value = '198.51.100.1']",
    "valid_from": "2026-07-02T00:00:00Z",
    "labels": ["malicious-activity"],
    "confidence": 90
}

OpenIOC 示例:

<ioc>
  <definition>
    <Indicator operator="OR">
      <IndicatorItem condition="is">
        <Context document="Network" search="Network/DNS" type="mir"/>
        <Content>c2.evil.com</Content>
      </IndicatorItem>
      <IndicatorItem condition="is">
        <Context document="Network" search="Network/IP" type="mir"/>
        <Content>198.51.100.1</Content>
      </IndicatorItem>
    </Indicator>
  </definition>
</ioc>

10.4 误报率控制与信誉系统

多层验证策略:

第一层:IOC 匹配 → 产生告警
第二层:上下文验证 → 排除已知合法用途
第三层:行为关联 → 与其他数据源交叉验证
第四层:人工审核 → 最终确认/排除

信誉系统集成:

virustotal_url_check() {
    curl -s --header "x-apikey: $VT_API_KEY" \
      "https://www.virustotal.com/api/v3/domains/$1" | \
      jq '.data.attributes.last_analysis_stats'
}

for domain in $(cat ioc_domains.txt); do
    echo "Checking: $domain"
    virustotal_url_check "$domain"
done

0x0B 自动化流量狩猎

11.1 Sigma 规则集

title: DNS Tunnel via High Entropy Subdomain
id: e5f6a7b8-c9d0-1234-efab-567890abcdef
status: experimental
description: 检测 DNS 查询中包含高熵子域名的隧道行为
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: dns
detection:
    selection:
        qtype_name:
            - "TXT"
            - "NULL"
            - "CNAME"
        query|re: '[a-z0-9]{20,}\.'
    condition: selection
fields:
    - id.orig_h
    - id.resp_h
    - query
    - qtype_name
level: high
tags:
    - attack.command_and_control
    - attack.t1071.004
title: Suspicious JA3 Fingerprint Match
id: f6a7b8c9-d0e1-2345-fabc-678901bcdefa
status: experimental
description: 检测已知恶意工具的 JA3 指纹
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: ssl
detection:
    selection:
        ja3:
            - "4d7a2d269e3e33c5a5e8f4a7b2c1d0e9"
            - "72a589da586844d7f0818ce684948eea"
            - "a0e9f5d64349fb13191bc781f81f42e1"
    condition: selection
fields:
    - id.orig_h
    - id.resp_h
    - server_name
    - ja3
level: critical
tags:
    - attack.command_and_control
    - attack.t1573
title: ICMP Tunnel Detection
id: a7b8c9d0-e1f2-3456-abcd-789012cdefab
status: experimental
description: 检测 ICMP 隧道行为(大包/高频)
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: icmp
detection:
    selection_size:
        bytes|gt: 64
    selection_frequency:
        timeframe: 5m
    condition: selection_size | count() by id.orig_h > 50
fields:
    - id.orig_h
    - id.resp_h
    - bytes
level: high
tags:
    - attack.command_and_control
    - attack.t1071.004
title: LDAP Enumeration BloodHound Detection
id: b8c9d0e1-f2a3-4567-bcde-890123defabc
status: experimental
description: 检测 BloodHound/SharpHound 的 LDAP 枚举行为
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: ldap
detection:
    selection:
        search_filter|contains:
            - "samAccountType=805306368"
            - "samAccountType=805306369"
            - "servicePrincipalName="
            - "objectclass=*"
    timeframe: 5m
    condition: selection | count() by id.orig_h > 50
fields:
    - id.orig_h
    - id.resp_h
    - search_filter
level: high
tags:
    - attack.discovery
    - attack.t1087
title: SMB Lateral Movement via PsExec
id: c9d0e1f2-a3b4-5678-cdef-901234efabcd
status: experimental
description: 检测通过 SMB 进行的 PsExec 横向移动
author: Security Team
date: 2026/07/02
logsource:
    product: zeek
    service: smb_files
detection:
    selection:
        name|contains:
            - "svcctl"
            - "psexec"
        action: "SMB::FILE_OPEN"
    condition: selection
fields:
    - id.orig_h
    - id.resp_h
    - name
    - path
level: critical
tags:
    - attack.lateral_movement
    - attack.t1570

11.2 Zeek 脚本自定义检测

module C2Detection;

export {
    redef enum Notice::Type += {
        Suspicious_Beacon_Pattern,
        Known_Malicious_JA3,
        Unusual_DNS_Tunneling
    };
    const known_bad_ja3: set[string] = {
        "4d7a2d269e3e33c5a5e8f4a7b2c1d0e9",
        "72a589da586844d7f0818ce684948eea"
    } &redef;
}

event ssl_client_hello(c: connection, version: count, possible_ts: time,
    client_random: string, session_id: string, ciphers: vector of count)
    {
    local ja3 = ja3_calc(c);
    if (ja3 in known_bad_ja3)
        {
        NOTICE([$note=Known_Malicious_JA3,
                $conn=c,
                $msg=fmt("Known malicious JA3 detected: %s", ja3)]);
        }
    }

11.3 Suricata/Snort 规则编写

alert dns $HOME_NET any -> any any (
    msg:"DNS High Entropy Subdomain - Possible Tunnel";
    dns.query; pcre:"/[a-z0-9]{30,}\./i";
    threshold: type both, track by_src, count 50, seconds 300;
    sid:9000001; rev:1;
    metadata: attack_target Client_Endpoint, deployment Perimeter;
)

alert http $HOME_NET any -> $EXTERNAL_NET any (
    msg:"HTTP Possible Cobalt Strike Beacon URI";
    http.uri; content:"/submit.php";
    http.user_agent; content:"Mozilla/5.0";
    threshold: type both, track by_src, count 10, seconds 600;
    sid:9000002; rev:1;
    metadata: attack_target Client_Endpoint, deployment Perimeter;
)

alert tcp $HOME_NET any -> $HOME_NET 445 (
    msg:"SMB Admin Share Access";
    flow:to_server,established;
    content:"|00|"; depth:1;
    content:"ADMIN$"; nocase;
    sid:9000003; rev:1;
    metadata: attack_target Server_Endpoint, deployment Internal;
)

alert icmp any any -> any any (
    msg:"ICMP Large Payload - Possible Tunnel";
    dsize:>128;
    threshold: type both, track by_src, count 100, seconds 60;
    sid:9000004; rev:1;
    metadata: attack_target Client_Endpoint, deployment Perimeter;
)

alert tls $HOME_NET any -> $EXTERNAL_NET any (
    msg:"Self-Signed Certificate on Unusual Port";
    tls.cert_issuer; content:"CN=";
    tls.cert_subject; content:"CN=";
    flow:to_server,established;
    sid:9000005; rev:1;
    metadata: attack_target Client_Endpoint, deployment Perimeter;
)

11.4 YARA 规则(网络流量匹配)

rule CobaltStrike_Beacon_Metadata
{
    meta:
        description = "Detect Cobalt Strike beacon metadata pattern"
        author = "Security Team"
        date = "2026-07-02"
    strings:
        $metadata_pattern = {00 01 00 01 00 02}
        $ua_pattern = "Mozilla/5.0 (compatible; MSIE"
        $uri_submit = "/submit.php"
        $uri_pixel = "/pixel.gif"
    condition:
        any of them
}

rule DNS_Tunnel_Iodine_Pattern
{
    meta:
        description = "Detect iodine DNS tunnel traffic pattern"
        author = "Security Team"
        date = "2026-07-02"
    strings:
        $iodine_header = {69 6f 64 69 6e 65}
        $high_entropy = /[a-z0-9]{40,}/
        $null_query = {00 10 01}
    condition:
        any of them
}

rule Suspicious_UserAgent_Collection
{
    meta:
        description = "Detect known malicious user agents"
        author = "Security Team"
        date = "2026-07-02"
    strings:
        $ua1 = "Mozilla/4.0 (compatible; MSIE 6.0)"
        $ua2 = "Mozilla/4.0 (compatible; MSIE 7.0)"
        $ua3 = "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0"
        $ua4 = "python-requests/2."
        $ua5 = "Go-http-client/1.1"
    condition:
        any of them
}

11.5 Arkime 查询与狩猎

Arkime 常用查询:

# 查找特定 JA3 指纹的会话
ja3 == 4d7a2d269e3e33c5a5e8f4a7b2c1d0e9

# 查找 DNS 隧道
protocols == dns && dns.opcode == 0 && dns.storm == 0 &&
  packets > 100 && dbytes > 50000

# 查找 SMB 横向移动
protocols == smb && port == 445 &&
  (ip.src == 10.0.0.50 || ip.dst == 10.0.0.50)

# 查找异常 TLS 证书
cert.alt == *evil* || cert.issuer.cn == *"Let's Encrypt"* &&
  cert.valid.from > 2026-06-01

11.6 Python 脚本:流量自动化分析框架

import json
import subprocess
import hashlib
from collections import defaultdict
from datetime import datetime

class AutomatedTrafficHunter:
    def __init__(self, pcap_path):
        self.pcap_path = pcap_path
        self.findings = []
        self.ioc_list = {
            'domains': set(),
            'ips': set(),
            'ja3': set(),
            'cert_hashes': set(),
            'urls': set()
        }

    def run_tshark(self, display_filter, fields):
        cmd = ['tshark', '-r', self.pcap_path, '-Y', display_filter,
               '-T', 'fields']
        for f in fields:
            cmd.extend(['-e', f])
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout.strip().split('\n')

    def hunt_dns_tunneling(self):
        lines = self.run_tshark('dns',
            ['frame.time', 'ip.src', 'dns.qry.name', 'dns.qry.type'])
        for line in lines:
            parts = line.split('\t')
            if len(parts) < 4:
                continue
            query = parts[2] if len(parts) > 2 else ''
            subdomain_parts = query.split('.')
            if len(subdomain_parts) > 3:
                subdomain = '.'.join(subdomain_parts[:-2])
                if len(subdomain) > 30:
                    self.findings.append({
                        'type': 'DNS_TUNNEL_SUSPECTED',
                        'severity': 'HIGH',
                        'query': query,
                        'src': parts[1]
                    })
                    self.ioc_list['domains'].add(query)

    def hunt_c2_beacons(self):
        lines = self.run_tshark('http.request',
            ['frame.time', 'ip.src', 'ip.dst', 'http.host', 'http.request.uri'])
        host_requests = defaultdict(list)
        for line in lines:
            parts = line.split('\t')
            if len(parts) < 5:
                continue
            host = parts[3]
            host_requests[host].append({
                'ts': parts[0],
                'src': parts[1],
                'uri': parts[4]
            })

        for host, reqs in host_requests.items():
            if len(reqs) > 20:
                self.findings.append({
                    'type': 'C2_BEACON_CANDIDATE',
                    'severity': 'HIGH',
                    'host': host,
                    'request_count': len(reqs)
                })
                self.ioc_list['domains'].add(host)

    def hunt_suspicious_tls(self):
        lines = self.run_tshark('tls.handshake.type == 1',
            ['ip.src', 'ip.dst', 'tls.handshake.ja3',
             'tls.handshake.extensions_server_name'])
        known_bad = {
            '4d7a2d269e3e33c5a5e8f4a7b2c1d0e9': 'Cobalt Strike',
            '72a589da586844d7f0818ce684948eea': 'Metasploit'
        }
        for line in lines:
            parts = line.split('\t')
            if len(parts) < 3:
                continue
            ja3 = parts[2] if len(parts) > 2 else ''
            if ja3 in known_bad:
                self.findings.append({
                    'type': 'MALICIOUS_JA3',
                    'severity': 'CRITICAL',
                    'ja3': ja3,
                    'tool': known_bad[ja3],
                    'src': parts[0],
                    'dst': parts[1]
                })
                self.ioc_list['ja3'].add(ja3)

    def hunt_smb_lateral_movement(self):
        lines = self.run_tshark('smb2',
            ['frame.time', 'ip.src', 'ip.dst', 'smb2.filename'])
        for line in lines:
            parts = line.split('\t')
            if len(parts) < 4:
                continue
            filename = parts[3] if len(parts) > 3 else ''
            if any(p in filename.lower() for p in ['svcctl', 'atsvc', 'msagent']):
                self.findings.append({
                    'type': 'SMB_LATERAL_MOVEMENT',
                    'severity': 'CRITICAL',
                    'src': parts[1],
                    'dst': parts[2],
                    'pipe': filename
                })

    def generate_report(self):
        report = {
            'timestamp': datetime.now().isoformat(),
            'pcap': self.pcap_path,
            'total_findings': len(self.findings),
            'findings_by_severity': defaultdict(int),
            'findings': self.findings,
            'iocs': {k: list(v) for k, v in self.ioc_list.items()}
        }
        for f in self.findings:
            report['findings_by_severity'][f['severity']] += 1
        return report

    def execute_full_hunt(self):
        self.hunt_dns_tunneling()
        self.hunt_c2_beacons()
        self.hunt_suspicious_tls()
        self.hunt_smb_lateral_movement()
        return self.generate_report()

hunter = AutomatedTrafficHunter("capture.pcap")
print("[*] Automated Traffic Hunter initialized")

11.7 与 SIEM/SOAR 集成方案

ELK Stack 集成:

{
    "pipeline": {
        "description": "Network traffic enrichment pipeline",
        "processors": [
            {
                "grok": {
                    "field": "message",
                    "patterns": ["%{TIMESTAMP_ISO8601:timestamp} %{IP:src_ip} %{IP:dst_ip} %{NUMBER:src_port} %{NUMBER:dst_port} %{WORD:protocol}"]
                }
            },
            {
                "geoip": {
                    "field": "dst_ip",
                    "ignore_missing": true
                }
            }
        ]
    }
}

SOAR Playbook 流程:

触发条件:Sigma 规则匹配
  → Step 1: 提取 IOC(IP/域名/哈希)
  → Step 2: VirusTotal/ThreatFox 查询
  → Step 3: 关联 SIEM 历史告警
  → Step 4: 查询资产管理系统(受影响主机)
  → Step 5: 自动生成工单
  → Step 6: 通知 SOC 分析师
  → Step 7: 如确认恶意 → 自动隔离(EDR/NAC)

0x0C 公开案例分析

12.1 SolarWinds SUNBURST C2 流量分析

攻击链概述:

SUNBURST(Solorigate)是 APT29(Cozy Bear)于 2020 年实施的供应链攻击,通过篡改 SolarWinds Orion 平台的软件更新植入后门。

攻击时间线:

2020-02  → 攻击者入侵 SolarWinds 构建系统
2020-03  → 植入后门代码到 Orion 平台
2020-03  → 受感染更新分发给 ~18,000 客户
2020-04  → 攻击者选择性激活约 9 个高价值目标的后门
2020-12  → FireEye/Mandiant 公开披露

C2 通信流量特征:

特征描述
域名avsvmcloud.com(子域名动态变化)
协议HTTPS (TCP 443)
通信模式周期性 Beacon(间隔约 1 小时)
数据编码请求数据编码在子域名中
响应处理响应数据编码在 DNS TXT 记录中
用户代理SolarWinds 合法 UA

C2 域名结构:

{encoded_data}.appsync-api.eu-west-1.avsvmcloud.com  → C2 命令请求
{encoded_data}.appsync-api.us-east-2.avsvmcloud.com  → 数据回传
{step_number}.appsync-api.eu-west-1.avsvmcloud.com   → 阶段控制

检测方法:

tshark -r capture.pcap -Y "dns.qry.name contains avsvmcloud.com" \
  -T fields -e frame.time -e ip.src -e dns.qry.name

tshark -r capture.pcap -Y "dns.qry.name contains appsync-api" \
  -T fields -e dns.qry.name -e dns.qry.type | \
  sort | uniq -c | sort -rn

关键 IOC:

域名: avsvmcloud.com
SHA256: 32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77 (SUNBURST)
IP: 13.59.205.66, 54.193.111.190
URI 模式: /appsync-api/{region}/avsvmcloud.com

12.2 APT29 网络流量特征

APT29 常用 TTPs 与网络特征:

TTP工具网络特征检测方法
初始访问鱼叉邮件SMTP 流量 + 恶意附件邮件网关检测
执行PowerShellWinRM/HTTP 流量脚本日志分析
持久化计划任务SMB/RPC 流量事件日志关联
凭据窃取MimikatzLSASS 访问(本地)EDR 检测
横向移动PsExec/WMISMB Named Pipe流量基线偏离
C2自定义工具HTTPS BeaconJA3 + 行为分析
数据外泄云存储HTTPS 上传流量量异常

APT29 典型网络流量模式:

阶段 1 - 初始访问:
  受害者 → 邮件服务器 (SMTP/IMAP)
  受害者 → 恶意 URL (HTTPS)

阶段 2 - C2 建立:
  受害者 → C2 服务器 (HTTPS, JA3 匹配)
  Beacon 间隔: 5-60 分钟

阶段 3 - 横向移动:
  受害者 → 内部主机 (SMB 445)
  Named Pipe: \svcctl, \msagent_*

阶段 4 - 数据外泄:
  受害者 → 云存储 (HTTPS, 大量上传)
  或 → 攻击者基础设施 (DNS 隧道/HTTPS)

APT29 检测 IOCs:

JA3 指纹: 72a589da586844d7f0818ce684948eea (Metasploit)
域名模式: *.ddns.net, *.no-ip.com (DDNS 滥用)
证书特征: 自签名证书, CN=*.microsoft.com (仿冒)
SMB 特征: \svcctl Named Pipe + 批量连接

12.3 案例关联分析总结

维度SUNBURSTAPT29 常规
C2 协议HTTPS + DNSHTTPS 为主
隐蔽性极高(供应链)中等
横向移动有限广泛(SMB/WMI)
数据外泄DNS 编码HTTPS 上传
检测难度极高
关键检测点DNS 子域名异常JA3 + SMB 行为

0x0D 参考资料

  1. Zeek Network Security Monitor Documentation - https://docs.zeek.org/en/master/

    • 网络协议分析、日志格式、脚本框架的权威参考
  2. Suricata Rule Writing Guide - https://suricata.readthedocs.io/en/latest/rules/intro.html

    • IDS 规则编写语法与最佳实践
  3. Sigma Rules - Network Traffic - https://github.com/SigmaHQ/sigma/tree/master/rules/network

    • 网络流量相关的 Sigma 检测规则集
  4. JA3/JA3S Fingerprinting - https://github.com/salesforce/ja3

    • TLS 指纹识别技术的原始论文与实现
  5. Arkime (Moloch) Full Packet Capture - https://arkime.com/

    • 全流量捕获与分析平台的官方文档
  6. MITRE ATT&CK - Command and Control - https://attack.mitre.org/tactics/TA0011/

    • C2 战术下所有技术的详细描述与检测方法
  7. SANS Network Forensics - https://www.sans.org/cyber-security-summit-archives/track/network-forensics/

    • 网络取证技术的系统性培训材料
  8. FireEye/SolarWinds SUNBURST Analysis - https://www.mandiant.com/resources/blog/sunburst-backdoor-uses-dns-steganography

    • SUNBURST 后门使用 DNS 隐写术的详细技术分析
  9. BloodHound AD Attack Path Analysis - https://bloodhound.readthedocs.io/

    • BloodHound 工具文档与 AD 攻击路径分析
  10. Malicious Traffic Detection with JA3 - https://engineering.salesforce.com/greasing-the-wheels-of-ssl-tls-fingerprinting-with-ja3s-490f1f3d1e33

    • Salesforce 工程团队关于 JA3/JA3S 的技术博客
  11. ICMP Tunnel Detection Techniques - https://www.sans.org/blog/detecting-icmp-tunnels/

    • ICMP 隧道检测技术的系统性介绍
  12. TLS 1.3 and Network Security Monitoring - https://tls13.ulfheim.net/

    • TLS 1.3 协议详解及其对网络安全监控的影响