OPNsense 26.7.6 - 高危 - 远程 - 网络访问绕过 - captive lastseen roam
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · opnsense-captive-lastseen-roam
类别: 网络访问绕过 可达性: 远程
OPNsense 核心 26.7.6 (a842fe48) - opnsense.org
强制门户漫游仍会为某个 MAC 上最新的 hostwatch IPv4 以及所有 IPv6 继承会话。GHSA-864r(26.7.3)阻止了“添加每个 IPv4”。遗留的 IPv4 来自 list_hosts.py 的 ORDER BY last_seen DESC。随后主 IP 从不过滤的 current_ips[0] 中分配。免费 ARP attacker_IP is-at victim_MAC 会更新 last_seen。在 26.7.3 之后,该 IPv4 不再是众多之一;如果它比受害者自身的 ARP 更新,它就是过滤器保留的那个 IPv4。IPv6 NDP 从未被限制。漫游和 hostwatch 默认开启。
此 GitHub 包在协调披露之前保持私有。
| ID | 暂无 CVE |
| 类别 | 网络访问绕过 |
| 可达性 | 远程(L2 相邻,强制门户区域) |
| CWE | CWE-345 / CWE-863 |
| CVSS | 高危:7.4 CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N |
| 产品 | OPNsense core |
| 受影响 | 26.7.6 (a842fe48c21288d11a422cb944678e8eb308becf) 强制门户漫游 |
| 认证 | 强制门户区域上未经认证的 L2 相邻主机;漫游开启 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
我固定了标签 26.7.6 剥离 a842fe48。实验环境是一个 Python 小工具,复现了固定版本的 _filter_addresses / list_hosts.py / arp.py 代码行,在 127.0.0.1:18820 上等待回环。
| 方法 | 汇聚点 | 权限 |
|---|---|---|
| 针对漫游=1 的 MAC,最新的 hostwatch IPv4 | 固定 _filter_addresses / list_hosts.py 的 ORDER BY last_seen DESC;主 IP 来自不过滤的 current_ips[0] | 完整性(实验证明): 攻击者 192.0.2.99 被保留,受害者 192.0.2.10 被丢弃,主 IP=192.0.2.99。实验:attacker-ipv4-kept=192.0.2.99 victim-ipv4-dropped=yes roaming=1。 |
| 同一 MAC,漫游=0 | _filter_addresses 返回 [addresses[0]] | 否定(实验证明): 第一个 IPv4 192.0.2.10 被保留。 |
| 同一 MAC 上的 IPv6,漫游=1 | _filter_addresses 保留每个非 v4 地址 | 完整性(实验证明): 所有 IPv6 均被保留(2001:db8::10 和 2001:db8::99)。 |
| 伪造的 GARP / NDP,hostwatch 将其存储在受害者 MAC 下 | 在 __captiveportal_zone_N 上实时调用 PF.add_to_table / IPFW.add_accounting | 完整性(推断): 攻击者源 IP 匹配门户放行表。会话用户名和配额仍属于受害者。此小工具中未运行线路上的实时 GARP 和实时区域表放行。 |
| 同一表添加 | 每个会话的 ipfw 计费规则编号 | 完整性(推断): 攻击者字节数计入受害者会话。 |
| 受害者 IPv4 不再排在首位 | _remove_client / pf 删除不在 list_session_ips 中的地址 | 可用性(推断): 受害者 IPv4 可能从区域表中掉出,而攻击者 IPv4 保留。 |
实验证明与推断: last_seen IPv4 保留/丢弃、漫游=0 首个 IP、以及 IPv6 全部保留均为实验成功。线路上的伪造 GARP、实时 pf/ipfw 放行、以及计费污染为推断。这是小工具,不是完整的 OPNsense FreeBSD 虚拟机。
前提条件: 强制门户区域上 L2 相邻的未认证主机。漫游开启(默认)。Hostwatch 开启(默认)。该区域上已有一个已授权会话。
| 攻击面 | 实验 |
|---|---|
| GHSA-864r 添加每个 IPv4 | 已在 26.7.3 关闭;此遗留问题是 last_seen IPv4 加上所有 IPv6 |
| 漫游=0 | 第一个 IPv4 被保留;攻击者 IPv4 未被选中 |
XFF / X-Real-Ip 伪造不同的登录 IP | 区域代理会追加;不是干净的 pf CIDR |
对调用者 IP 的未认证 logon | 已记录的 getClientIp() 门户登录 |
| 对默认 8+10 CSPRNG 的凭证暴力破解 | 不是此遗留问题 |
| 模板 zip-slip | realpath 加上管理员上传 |
| 门户启动页 XSS 到 WebGUI 源 | 不同端口 / chroot |
| WAN 未认证 | 区域上 L2 相邻 |
| WebGUI / root / 凭证铸造 | 保持关闭 |
无未认证 WebGUI。无 root。无 WAN 跳过门户。
cd lab
./run.sh
回环等待 127.0.0.1:18820。Compose 项目 opnsense-captive-lastseen-roam。镜像标签来自该 compose。见证 OPNSENSE-CAPTIVE-LASTSEEN-ROAM-WITNESS。最后一行:
SUCCESS opnsense-captive-lastseen-roam attacker-ipv4-kept=192.0.2.99 victim-ipv4-dropped=yes roaming=1 OPNSENSE-CAPTIVE-LASTSEEN-ROAM-WITNESS
根启动器:python3 opnsense-captive-lastseen-roam-Abraxas-Labs.py。
选择会话已授权的 IPv4,而不是该 MAC 最新的 hostwatch 行。以同样方式限制 IPv6,或要求内核仍持有的 NDP。当过滤器已选择不同地址时,不要从不过滤的 current_ips[0] 分配主 IP。将仅更新 last_seen 的 GARP 视为不可信观察,这正是 GHSA-864r 的不变量。
a842fe48c21288d11a422cb944678e8eb308becfcp-background-process.py _filter_addresses 和主 IP 重写list_hosts.py ORDER BY last_seen DESClib/arp.py get_all_addresses_by_mac