畸形 TCP 报文攻击,是指攻击者故意构造违反 RFC 规范或违背 TCP 状态机的报文,利用目标协议栈在解析、校验、重组、状态处理环节的实现缺陷或行为差异,达到使目标崩溃、资源耗尽、连接错乱,或绕过检测、探测目标的目的。
它和前面聊过的 PSH+ACK 洪泛属于不同维度:洪泛是"用结构合法的报文堆量",畸形报文是"用结构非法的报文找缝"。前者拼的是带宽和包速率,后者拼的是实现对异常输入的鲁棒性。
分类
| 维度 | 典型手法 | 攻击点 |
|---|---|---|
| 标志位畸形 | NULL(全 0)、XMAS(FIN+PSH+URG)、仅 FIN、SYN+FIN、全标志位置位 | 状态机处理、端口探测、防火墙策略探测 |
| 首部字段畸形 | 数据偏移小于 5、保留位非零、校验和错误、窗口与数据矛盾、紧急指针越界 | 解析越界、内存破坏 |
| 选项畸形 | 非法选项长度、MSS 异常、窗口缩放因子越界、SACK 块重叠或超范围 | 选项解析溢出、内核崩溃 |
| 分片与长度畸形 | 重叠分片、超小分片、偏移异常、IP 长度与 TCP 首部矛盾 | 重组缓冲区溢出、绕过检测 |
| 状态机异常 | 无会话的 ACK/RST/FIN 注入、序号越窗、零窗口滥用 | 连接表耗尽、连接重置 |
几个经典手法
NULL / FIN / XMAS 扫描是最常见的标志位畸形。按 RFC 793,不属于任何连接的报文若标志位异常,关闭端口应回 RST、开放端口应无响应。攻击者借此区分端口状态。XMAS 置 FIN+PSH+URG,NULL 一位都不置,原理相同。这类扫描对 Windows 无效,因为其协议栈不遵循这一行为——而这个"无效"本身就是操作系统指纹。
SYN+FIN 同置是典型的自相矛盾报文:既要建连又要拆连。现代协议栈按 RFC 9293 要求直接丢弃,但它对老设备和中间安全设备仍是有效的探测手段。
Land 攻击(1997)把源地址、目的地址、源端口、目的端口全设成同一个值,使旧栈陷入自我循环。现代系统已免疫,但作为历史案例仍有教学价值。
Teardrop 类分片攻击利用分片偏移重叠或计算错误,使重组时写入超出缓冲区的数据,导致内核崩溃。这是 IP 层的问题,但常与 TCP 流量结合使用。
超小分片与重叠分片是更隐蔽的用法——目的不是打瘫目标,而是让 IDS 与终端对报文的理解产生分歧。IDS 可能只检查首片,或采用与目标不同的重组策略,攻击载荷就被"拼"到检测设备看不到的位置。1998 年 Ptacek 与 Newsham 的论文《Insertion, Evasion, and Denial of Service》系统性地阐述了这类规避理论,至今仍是入侵检测领域的必读文献。
SACK Panic(CVE-2019-11477)说明畸形报文并非历史问题。攻击者构造异常的 SACK 选项触发 Linux 内核整数溢出,直接导致内核恐慌。这类漏洞在 2019 年才被发现和修复。
Sockstress(2008)则是另一种思路:不构造畸形包,而是滥用合法机制——以零窗口和大量并发连接耗尽目标的连接跟踪资源。它属于协议状态滥用,严格说不是畸形报文,但常被归入同一大类的讨论。
为什么这类攻击有效
根本原因在于规范留白与实现分歧。TCP 规范对很多异常输入未做强制规定,各实现自由裁量,OpenBSD 严格丢包、Linux 相对宽松、Windows 又不遵循某些行为。攻击者利用的就是这些差异。
更麻烦的是检测设备与终端解析不一致。防火墙、IDS、主机对同一个畸形包可能有三种理解,攻击者只要构造出让三者理解不同的报文,就能让检测设备放行而终端照样执行。这是协议异常类攻击最难防的部分。
还有一层现实因素:网络中间设备(防火墙、IPS、负载均衡)往往比主机协议栈更脆弱,因为它们需要做深度解析,攻击面反而更大。
检测
畸形报文的检测靠状态检测和协议一致性校验,不是靠特征匹配。
Wireshark 常用过滤表达式:tcp.flags == 0x000 抓 NULL 扫描;tcp.flags == 0x029 抓 XMAS;tcp.flags.syn == 1 && tcp.flags.fin == 1 抓 SYN+FIN;tcp.hdr_len < 20 抓首部长度非法。
主机侧看内核计数器,netstat -s 中 invalid header、bad checksum、out-of-window 等计数的异常增长是重要信号。IDS 侧用 Suricata 或 Snort 的协议异常规则,并启用目标基(target-based)重组策略,让检测端与终端的重组逻辑保持一致,从根上消除解析分歧。
防御
有状态过滤是核心。 没有匹配会话的 ACK、FIN、RST 一律丢弃:
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
sysctl -w net.netfilter.nf_conntrack_tcp_loose=0
第一行丢弃连接跟踪判定为无效的报文,第二行让 conntrack 不再从孤立 ACK 包"捡起"会话,两者配合能阻断很大一部分伪造与畸形流量。
内核加固方面,开启 tcp_syncookies 抵御半开连接耗尽,开启 net.ipv4.tcp_rfc1337=1 防止针对 TIME_WAIT 状态的连接刺杀,出口启用 rp_filter 抑制源地址伪造。
按 RFC 5961 的思路处理窗口外报文:对窗口外的 RST 不直接响应而是发 ACK 挑战,对窗口外的 SYN 回 ACK 而非 RST,可显著提高盲注入攻击的难度。主流内核已默认实现,老系统需确认。
及时打补丁是治本手段,尤其是嵌入式设备、工控设备和网络中间设备——它们的协议栈往往常年不更新,是畸形报文攻击的主要受害对象。
减少暴露面:关闭不必要端口以降低扫描价值;在网络边界丢弃长度异常和非法标志的报文;不依赖单一检测层,把主机日志、流量日志和 IDS 告警做关联分析。