使用Scapy向NPS发送RADIUS数据包时遇Message-Authenticator无效问题求助
首先,这个问题我之前排查过类似场景,核心原因是Message-Authenticator的计算依赖完整的RADIUS数据包上下文,你直接拼接IP/UDP层的操作可能无意中篡改了关键字段,或者遗漏了原请求的源端点验证信息。以下是几个必须检查的关键环节:
1. 强制固定RADIUS的Length字段
当你把捕获的RADIUS数据包导入Scapy作为负载时,Scapy默认会自动重新计算RADIUS层的length字段——而Message-Authenticator是基于包含Length字段的整个RADIUS数据包计算的,一旦Length值和原包不一致,HMAC校验结果必然失效。
解决方法:从Wireshark里提取原包的Length值,在构造数据包时强制固定:
# 假设你导入的RADIUS包是radius_pkt radius_pkt.length = 123 # 替换成原捕获包的实际Length数值 final_pkt = IP(dst="X.X.X.X")/UDP(dport=1812, sport=原WLC的UDP源端口)/radius_pkt
2. 必须指定UDP源端口为原WLC的端口
原WLC发送RADIUS请求时使用的UDP源端口是固定的,NPS的RADIUS客户端配置通常会绑定这个端口作为验证条件。更关键的是,部分NPS实现会将UDP源端口纳入Message-Authenticator的验证逻辑(虽非RFC标准,但厂商自定义实现很常见)。
一定要在UDP层显式指定sport为原捕获包的源端口,不能让Scapy随机分配。
3. 禁用Scapy自动修改RADIUS核心字段
Scapy的RADIUS层会自动处理authenticator或message_authenticator字段,发送时可能重新计算覆盖原值,直接导致校验失败。你需要手动固定这些字段并禁用自动处理:
# 从原包提取Authenticator和Message-Authenticator的字节值 radius_pkt.authenticator = b'\xXX\xXX...' # 替换成原包的Authenticator字节串 # 定位Message-Authenticator属性并固定其值 for attr in radius_pkt.attributes: if attr.type == 80: # Message-Authenticator的属性类型是80 attr.value = b'\xXX\xXX...' # 替换成原包的Message-Authenticator值 # 清除Scapy的自动计算缓存 del radius_pkt.rawlayer
4. 确保源IP匹配NPS的RADIUS客户端配置
NPS只会接收已配置的RADIUS客户端IP发送的请求,如果你用Scapy发送时的源IP不是WLC的IP(即NPS里登记的客户端IP),NPS会直接判定为非法请求,进而抛出Message-Authenticator无效的提示(这是NPS的通用错误话术,不一定完全对应字段本身的问题)。
解决方法:要么在Scapy里设置IP(src="WLC的IP")(需要机器具备伪造源IP的权限和网络支持),要么临时在NPS里添加你的机器IP作为测试客户端。
总结操作步骤
- 从Wireshark中提取原包的RADIUS Length、Authenticator、Message-Authenticator值,以及UDP源端口、WLC源IP。
- 在Scapy中构造数据包时,强制固定所有上述字段,禁用自动计算逻辑。
- 确保发送的源IP是NPS认可的RADIUS客户端IP。
内容的提问来源于stack exchange,提问作者Matusai

