Chasing the OPNsense RCE: The Story Behind My First CVEs
AI 深度解读
背景
OPNsense 是一款基于 FreeBSD 的开源防火墙与路由平台,广泛应用于企业网络和家庭网络的边界防护。其核心定位是将商业级防火墙功能以免费形式提供给所有用户,因此在开源安全领域拥有大量用户群体。
在 Hacking Cult 公司,渗透测试人员会定期获得专门用于安全研究和专业发展的时间。由于团队高度依赖开源软件,他们决定利用这段时间对开源生态进行渗透测试,以帮助提升整体安全性。通过社区投票,OPNsense 被选为研究目标。
核心内容
研究方法论
研究在虚拟机中部署 OPNsense 实例后展开,作者的核心目标是绘制应用程序的攻击面,并追踪路由逻辑以及支撑 Web 界面的 Phalcon 框架(基于 PHP 的 MVC 框架)。
手动污点分析是主要方法论支柱。作者大量使用 ripgrep 配合自定义正则表达式,在庞大的 PHP 代码库中搜索潜在的危险函数(sink),包括文件系统操作、shell 执行和未消毒的输出等。通过这种方式,手动追踪执行流程,判断用户输入是否未经适当验证就到达了这些危险函数。
由于 Phalcon 框架的动态路由和参数绑定机制,简单的 grep 搜索往往无法揭示全貌,作者需要将 ripgrep 的发现与实际 XML 配置文件进行交叉引用,这些配置文件将前端控制器映射到后端 API 端点。
此外,作者还使用 Burp Suite 进行动态代理,拦截和分析前端与 Phalcon 后端之间的 API 调用,并对证书描述、别名名称和网格参数等输入字段进行激进的黑盒测试,使用 XSS polyglot 载荷。这种单一载荷能同时突破多个上下文(如 HTML 属性、JavaScript 字符串和标准 HTML 标签),极大提升了测试效率。
四项中等漏洞
在发现关键 RCE 之前,作者还识别出四项中等严重程度的漏洞,它们共同揭示了在同一代码库中重复出现的同类错误——信任输入而不进行消毒。
XPath 注入(MVC Safe-Delete)
OPNsense 中所有基于 MVC 模块的"删除"按钮最终都会调用同一个通用的安全删除例程,该例程被数十个端点共享。作者发现 URL 中的删除令牌通过简单的字符串插值直接被放入 XPath 查询中,这一漏洞并非影响单个端点,而是同时影响21 个端点。
一个简单的载荷如 ')or(' 就能将原本针对特定节点的查询转换为匹配 config.xml 中所有文本节点的查询。当匹配成功时,API 会抛出 HTTP 500 错误消息,其中包含匹配节点的模块、描述和 UUID。拥有多项权限中某一项的用户可以利用安全删除端点作为读取预言机,访问他们本不应看到的模块。虽然不会发生数据更改或删除操作,但配置信息仍会通过错误消息泄露。
三个存储型 XSS
剩余三个发现均为存储型 XSS,其共同模式是转义发生在错误的位置。
-
防火墙规则和 NAT 网格:类别名称和别名描述被放入
title="..."属性中,但后端仅使用htmlspecialchars()配合ENT_NOQUOTES参数,这会阻止<、>和&,但不会阻止双引号"。攻击者可以闭合属性并注入onanimationstart等事件处理器到现有<span>标签上,实现零用户交互的 JavaScript 执行。 -
NTP GPS 页面:该页面尝试了更强的防护,但仅对初始化命令的 base64 编码形式进行转义。当值在
<textarea>中被解码回页面时,转义已经作用于一个不再存在的字符串上,因此一个简单闭合标签的载荷就能在页面渲染时立即执行。 -
管理页面的 SSL 证书下拉框:直接从
config.xml读取证书描述并打印到<option>标签中,完全没有转义。一个简单的<script>alert(1337);</script>载荷即可生效。
这三个不同错误、三条不同代码路径,却指向同一个教训:尽可能靠近 sink 进行验证和转义,因为每多一步中间环节,防护就有可能悄然失效。
关键 RCE 漏洞(CVE-2026-57155)
漏洞代码理解
OPNsense 内置了 GeoIP 别名导入器。用户可以将其指向一个国家-IP 数据库 URL,它会定期以 root 权限下载并解压该数据库,以便构建类似"X 国所有 IP"的防火墙别名。该导入器位于 src/opnsense/scripts/filter/lib/alias/geoip.py 中,会盲目写入下载数据库指定的任何文件名。
两个处理解压的函数 process_zip() 和 `process_gzip
