abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · opnsense-tunables-loader
技术文章:https://abraxaslabs.tech/research/opnsense-tunables-loader
类别: 配置行注入 可达性: 远程
OPNsense 核心 26.7.6(a842fe48)- opnsense.org
系统:高级:可调参数(Tunables)仍会将名称/值插值写入 /boot/loader.conf。这是 GHSA-fq94 遗留的同类问题。Tunables.xml 中的 tunable / value 是裸 TextField(允许换行)。system_login_configure() 写入 {$param}="{$value}"。重新配置可调参数还会重启 login。实时 sysctl(8) 会经过 shell_safe 以及 OID 过滤器,因此该环节不是 shell 注入。遗留问题是在下次启动时多出额外的 loader 指令。所需权限为 page-system-advanced-sysctl,而非 page-all。
此 GitHub 仓库在协调披露前保持私有。
| ID | 暂无 CVE |
| 类别 | 配置行注入 |
| 可达性 | 远程(已认证的 WebGUI / API) |
| CWE | CWE-93 |
| CVSS | 高危:8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 产品 | OPNsense core |
| 受影响版本 | 26.7.6(a842fe48c21288d11a422cb944678e8eb308becf)系统:高级:可调参数 |
| 认证 | 具有 page-system-advanced-sysctl 的 WebGUI 会话或 API 密钥 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | compose exec gadget(hunt 槽位 18850) |
我固定了标签 26.7.6 的 peel 提交 a842fe48。实验环境是一个 PHP gadget,复现固定版本中 system_login_configure() 的插值行为。Compose 项目为 opnsense-tunables-loader。Hunt 槽位 18850 属于 18800-18860 gadget 系列;此 compose 文件使用 docker compose exec php,而非对外发布的 HTTP 绑定。
| 方法 | 汇聚点 | 权限 |
|---|---|---|
可调参数值包含 CR/LF(hw.usb.no_boot_wait 加上 "\n# witness") | 在 /boot/loader.conf 中固定 system_login_configure() 的额外行 | 完整性(实验已验证): 在已闭合的赋值之后单独一行出现额外的 # OPNSENSE-TUNABLES-LOADER-WITNESS。实验:newline-extra-line=yes。 |
干净值 1 | 同一写入器 | 阴性(实验已验证): 仅单行赋值,无见证标记。实验:clean-value-single-line=yes。 |
| 下次启动时出现相同的额外 loader 行 | loader 的 init_path / module_path / *_load / vfs.root.mountfrom / 控制台 | 完整性(推断): 下次启动的 loader 会采纳攻击者的键。本 gadget 中未重启。 |
垃圾 loader 行 / 错误的 vfs.root.mountfrom | /boot/loader.conf | 可用性(推断): 启动失败或根挂载错误。 |
POST /api/core/tunables/searchItem | 可调参数 API | 侦察(推断): 列出可调参数,包括当前值/默认值/类型。此 ACL 本就允许该操作。 |
对有效 OID 执行实时 sysctl -w | set_sysctl + OID 过滤器 | 该页面的预期功能。额外 loader 行是遗留问题。 |
实验已验证 vs 推断: 换行额外 loader 行与干净值单行均为实验成功。下次启动时 loader 应用为推断。这是 gadget,而非完整的 OPNsense FreeBSD 虚拟机。
前提条件: 已登录用户或该用户的本地 API 密钥,具有 page-system-advanced-sysctl 且不含 page-all。POST /api/core/tunables/*。会话 POST 需 CSRF。重新配置会重启 login;rc.reload_all 和启动过程也会调用 system_login_configure。
| 攻击面 | 实验环境 |
|---|---|
| 实时 sysctl shell 注入 | shell_safe 加 OID 过滤 |
| 干净值 | 单条赋值行 |
| 未认证 | 401 |
无 page-system-advanced-sysctl 权限的用户 | 403 |
user-config-readonly | save() 抛出异常 |
page-all 可调参数管理员设置真实 OID | 预期行为 |
| GHSA-fq94 已修补的 GUI 文本字段 | 不同的汇聚点;此字段未被点名 |
无未认证。无实时 sysctl shell。无 Diagnostics: Command。
cd lab
./run.sh
Compose 项目 opnsense-tunables-loader。见证 OPNSENSE-TUNABLES-LOADER-WITNESS。最后一行:
SUCCESS opnsense-tunables-loader newline-extra-line=yes clean-value-single-line=yes OPNSENSE-TUNABLES-LOADER-WITNESS
根启动器:python3 opnsense-tunables-loader-Abraxas-Labs.py。
从 tunables 名称和值中剥离 CR/LF 和 ",与 GHSA-fq94 属于同一类问题。将名称类型设为 OID 掩码,而不是裸 TextField。使用无法闭合赋值的辅助函数进行引号处理。除非是已知的 loader 键,否则不要将 tunable 写入 /boot/loader.conf。
a842fe48c21288d11a422cb944678e8eb308becfsystem.inc system_login_configure loader.conf 插值Tunables.xml 裸 TextField 名称/值