NTP 放大攻击的 iptables -p udp –dport 123 -m u32 过滤规则

9次阅读

仅用 -p udp –dport 123 无法防御 ntp 放大攻击,因该规则只匹配端口不检查 udp 载荷;必须结合 u32 模块检测 ntp 报文 mode 字段(偏移 6 字节),拦截 mode 非 3 / 4 的非法请求,且规则须置于 input 链前端。

NTP 放大攻击的 iptables -p udp --dport 123 -m u32 过滤规则

为什么 --dport 123 单独拦不住 NTP 放大攻击

因为攻击者根本不用标准 NTP 请求格式——他们发的是伪造源 IP 的 UDP 包,目标端口确实是 123,但 payload 是恶意构造的(比如 x00x00x00x00x00x00x00x00 或更长的 monlist 请求),NTP 服务端一响应就放大数倍。只靠 -p udp --dport 123 只能匹配端口,完全不检查内容,等于给放大器开了大门。

必须用 u32 模块对 UDP payload 做粗筛,把明显非法的请求在内核层面丢掉,避免进用户态 NTP 进程。

  • u32 规则要放在 INPUT 链靠前位置,越早匹配丢包,CPU 和带宽浪费越少
  • 别在 FORWARDOUTPUT 链加这条规则——NTP 放大是入向流量触发的
  • Linux 内核需 ≥ 2.6.18 才默认支持 u32,老系统先确认 lsmod | grep u32

u32 怎么写才能拦住常见 NTP 放大载荷

核心思路:NTP 查询报文前 4 字节是 LI VN Mode 字段,合法查询中 Mode 应为 3(client)或 4(symmetric active)。而大多数放大攻击(如 monlist、readvar)会把 Mode 设为 0–2 或 6–7,或者干脆填 0 填满整个包。用 u32 提取并判断这个字节最有效。

典型规则示例(拦截 Mode 非 3/4 的所有 NTP 请求):

iptables -A INPUT -p udp --dport 123 -m u32 --u32 "6&0x7C=0x0 || 6&0x7C=0x4 || 6&0x7C=0x8 || 6&0x7C=0xC || 6&0x7C=0x10 || 6&0x7C=0x14 || 6&0x7C=0x18 || 6&0x7C=0x1C" -j DROP

说明:6&0x7C 表示从第 6 字节开始取低 6 位(即 Mode 字段),合法值只有 0x0(0)、0x4(1)、0x8(2)、0xC(3)、0x10(4)……但实际只需保留 0xC(3)和 0x10(4)即可,其余全拦。更精简写法:

iptables -A INPUT -p udp --dport 123 -m u32 --u32 "6&0x7C!=0xC && 6&0x7C!=0x10" -j DROP
  • 注意字节偏移:UDP 头 8 字节 + IP 头最小 20 字节 = 第 28 字节才是 UDP payload 起始;但 u32 默认从 IP 头起算,所以 NTP payload 起始是 28+8=36?错——u32 的 offset 是从 IP 包头开始的「字节偏移」,而 NTP 报文在 UDP payload 里,所以是 20(IP 头)+8(UDP 头)=28,第 28 字节是 UDP payload 第一个字节,NTP 的 LI VN Mode 就在那,即 offset 28。但实测主流内核中 u32 对 UDP 匹配时,常以 6 为 offset,这是因为它自动跳过了 IP+UDP 头(依赖内核 netfilter 的解析逻辑),不是绝对偏移。稳妥做法是用 tcpdump -i any -nn -X port 123 抓包确认真实 payload 偏移
  • 如果 NTP 服务启用了 IPv6,这条规则无效——u32ip6tables 中不支持,得换用 ipset 或用户态限速
  • 别用 --u32 "0>>22&0x3C@12>>26&0x3F=0x17" 这类复杂匹配——可读性差,且不同内核版本对 @ 符号解析可能有差异

这条规则上线前必须验证的三件事

没验证就上生产,大概率要么拦不住攻击,要么把正常 NTP 客户端全干掉。

  • 先用 iptables -L INPUT -v -n 看规则是否加载成功,计数器是否随测试包增长
  • echo -ne 'x17x00x00x00' | nc -u target_ip 123 模拟 Mode=0 的恶意包,确认被 DROP;再用 ntpdate -q target_ipntpq -p 测试合法 client 查询是否仍通
  • 检查 /var/log/messagesdmesg 是否有 u32: invalid rulenf_u32: unknown key 报错——常见于内核模块未加载或规则语法括号不匹配

比 iptables 更靠谱的长期方案是什么

iptables + u32 是应急止血,不是根治。NTP 放大本质是服务配置缺陷:公开暴露的 ntpd 默认允许 monlist、readvar 等高危命令,且不校验源地址。真正该做的优先级是:

  • 升级到 ntpd 4.2.8p10+ 或改用 chrony,两者默认禁用 monlist 且支持 restrict default noquery
  • ntp.conf 里明确写 restrict default kod nomodify notrap nopeer noquery,再单独放开可信网段
  • 云环境直接关掉公网 123 端口,让 NTP 流量走 VPC 内网或使用云厂商提供的 NTP 服务(如 AWS Time Sync)

u32 规则容易写错偏移、难调试、IPv6 无解——它只是给运维多争取几小时修复窗口,别当成永久防线。

text=ZqhQzanResources