DDoS攻击的溯源难点在于攻击流量几乎都伪造了源IP,直接抓包看到的源地址绝大多数是“替死鬼”而非真实攻击机。真正有分析价值的是攻击来源IP段,因为大规模DDoS通常由僵尸网络发起,而僵尸主机在地理位置、运营商归属和AS号上往往呈现聚集性。分析IP段不是去追查某台具体设备,而是识别出哪些网段被持续用于发起攻击,从而在边界设备上做针对性封禁或限速。

拿到一份攻击流量样本后,第一件事不是看单个IP,而是做聚合统计。把pcap或netflow数据里的源IP按/24段聚合,统计每个段出现的包数、字节数和连接数。攻击流量中,某些/24段会出现异常高的发包频率,而正常访问流量在段级别分布相对均匀。这里有一个关键点:不要只按包数排序,要结合包长和协议类型。UDP反射攻击的源IP段可能包数极高但都是固定长度,SYN Flood的源IP段则表现为大量半开连接。

分析IP段的归属信息需要用到whois和BGP数据。对聚合出的可疑IP段逐一查询AS号和所属运营商,你会发现很多攻击源集中在少数几个AS内,尤其是那些对滥用投诉处理缓慢、主机托管业务宽松的网络。记录下这些AS号比记录单个IP有效得多,因为僵尸网络会不断更换具体IP,但短期内很难整体迁移出某个AS。如果某个AS内超过30%的攻击流量来自相同几个/24段,基本可以判定该段存在大量被控主机。

时间维度上的分析同样重要。把攻击流量按小时切分,观察可疑IP段的活动规律。真实僵尸网络受控于C2指令,攻击时段往往与目标所在地的白天或业务高峰重合。如果某个IP段只在攻击发生时出现,攻击停止后完全消失,说明该段内的主机平时不访问你的业务,封禁这些段不会影响正常用户。反之,如果某个IP段在攻击前后都有正常访问记录,只是攻击期间流量激增,就不能整体封禁,需要更精细的限速策略。

还有一种情况是攻击者利用IP伪造,源IP段看起来分散且随机。这时要换一个分析角度:看TTL值和IP标识字段。同一批僵尸主机发出的伪造包,即使源IP随机,TTL初始值往往相同,因为操作系统类型一致。把TTL值相同且源IP分散的流量归为一组,再分析这些伪造IP的段分布,有时能发现攻击工具在生成随机IP时使用了特定的随机算法,导致某些段被重复选中。这种规律一旦找到,就能提取出用于匹配的特征。

对于反射放大攻击,分析来源IP段的方法要反过来。反射攻击的流量来自合法的反射服务器,比如DNS、NTP、Memcached服务器,这些服务器本身不是攻击者,但被攻击者利用。分析这些反射源的IP段,可以识别出哪些网段存在大量可被利用的开放服务。把这些段加入监控名单,当某个段突然对你的IP发送大量响应包时,就能提前触发告警。很多反射服务器集中在云服务商的IP段里,因为云主机默认开放了相关服务且带宽充足。

在实际操作中,建议用以下流程处理攻击来源IP段。第一步,从流量采集系统导出攻击时段的数据,过滤掉正常业务流量。第二步,用脚本按/24和/16两个粒度聚合,分别统计包数和字节数。第三步,对排名前50的段做whois查询,记录AS号、运营商和注册国家。第四步,结合攻击类型判断哪些段是真实攻击源、哪些是反射源、哪些是伪造源。第五步,针对真实攻击源段在防火墙或WAF上做封禁,针对反射源段做协议级限速,针对伪造源段提取特征做动态过滤。

下面给一段用于聚合统计的Python代码,可以直接处理netflow导出的CSV文件,按/24段统计包数并输出前20个段。

import csv
from collections import defaultdict
from ipaddress import ip_address, ip_network

def ip_to_24(ip_str):
    ip = ip_address(ip_str)
    return str(ip_network(f"{ip}/24", strict=False))

seg_stats = defaultdict(lambda: {"packets": 0, "bytes": 0})

with open("attack_flow.csv", "r") as f:
    reader = csv.DictReader(f)
    for row in reader:
        src_ip = row["src_ip"]
        seg = ip_to_24(src_ip)
        seg_stats[seg]["packets"] += int(row["packets"])
        seg_stats[seg]["bytes"] += int(row["bytes"])

sorted_segs = sorted(seg_stats.items(), key=lambda x: x[1]["packets"], reverse=True)

for seg, stats in sorted_segs[:20]:
    print(f"{seg}  packets={stats['packets']}  bytes={stats['bytes']}")

这个脚本的核心逻辑是把每个源IP归入对应的/24段,然后累加包数和字节数。实际使用时,CSV文件需要包含src_ip、packets、bytes三列。如果数据量大,建议先把数据导入数据库再用SQL做GROUP BY,性能会好很多。

封禁IP段时要注意粒度选择。直接封/8段过于粗暴,可能误伤大量正常用户。封/24段相对安全,但僵尸网络如果分布在多个/24段,需要封禁的条目会很多。折中方案是封/16段,前提是该段内的正常访问流量占比极低。判断方法是查看攻击前30天的访问日志,统计该段内正常用户的访问量,如果正常访问量不到总访问量的0.1%,封禁该段的风险可以接受。

还有一个容易被忽视的分析维度是源端口。UDP Flood和反射攻击的源端口有固定规律,比如DNS反射固定是53端口,NTP反射是123端口,Memcached反射是11211端口。把这些源端口和IP段结合起来分析,可以快速区分攻击类型。如果某个IP段同时出现在多个攻击事件中,且每次使用的源端口不同,说明该段内的主机被植入了多种攻击工具,属于重点封禁对象。

对于长期运营的业务,建议建立攻击源IP段数据库。每次攻击后把分析出的可疑段存入数据库,记录攻击时间、攻击类型、包数峰值和AS信息。当新的攻击发生时,先与历史数据库比对,如果某个段反复出现,直接提升封禁优先级。这个数据库还能用于生成黑名单,同步给上游运营商或CDN节点,在流量进入你的网络之前就进行丢弃。

分析攻击来源IP段还有一个实际用途:向运营商投诉。把攻击流量按AS号聚合后,找出承载攻击流量最大的几个AS,整理出攻击时段、流量峰值、涉及的IP段和样本数据,提交给对应运营商的滥用投诉邮箱。虽然响应速度参差不齐,但对于长期持续的DDoS攻击,运营商层面的干预往往比本地封禁更有效,尤其是当攻击流量大到堵塞入口带宽时,本地封禁已经没有意义。

最后要强调的是,IP段分析不是一次性的工作。攻击者会不断更换僵尸网络、调整攻击工具,甚至利用新的反射协议。只有持续采集流量数据、定期更新分析模型、保持对异常段的敏感度,才能在DDoS防御中占据主动。把分析流程工具化、自动化,让每次攻击都成为丰富黑名单库和优化防御策略的机会,这才是IP段分析方法的真正价值所在。