我们对Homebrew的审计 - The Trail of Bits博客
William Woodruff
2024年7月30日
研究实践
这是一篇与Homebrew维护者联合发布的文章;请在此处阅读他们的公告!
去年夏天,我们对Homebrew进行了一次审计。审计范围包括Homebrew/brew本身(brew CLI的所在地),以及三个负责Homebrew操作中各种安全相关方面的相邻仓库:
- Homebrew/actions:一个包含Homebrew CI/CD中使用的自定义GitHub Actions的仓库;
- Homebrew/formulae.brew.sh:负责Homebrew可安装包JSON索引的代码库;
- Homebrew/homebrew-test-bot:Homebrew的核心CI/CD编排和生命周期管理例程。
我们在Homebrew中发现了一些问题,虽然不关键,但可能允许攻击者在意外点加载可执行代码,并破坏Homebrew使用沙箱所意图的完整性保证。同样,我们在Homebrew的CI/CD中也发现了问题,可能允许攻击者秘密修改公式的二进制(“bottle”)构建,并可能从触发CI/CD工作流转向控制CI/CD工作流的执行并窃取其秘密。
这次审计由Open Tech Fund赞助,作为其保护互联网基础设施关键部分更大使命的一部分。您可以在我们的出版物仓库中阅读完整报告。
Homebrew
Homebrew是自称为“macOS(或Linux)缺失的包管理器”。它作为macOS上软件开发者的实际标准包管理器,每年服务数亿次包安装。这些安装包括“关键”包,如Golang、Node.js和OpenSSL,使得Homebrew的安全性(及其构建的完整性)对整个下游软件生态系统的安全至关重要。Homebrew的核心(不要与homebrew-core混淆)是一个Ruby单体,负责向用户提供brew CLI以及可导入的Ruby API。
自2009年成立以来,Homebrew经历了多次架构转变,旨在提高向用户交付包的可靠性和可用性:实现了二进制构建(bottles),使其成为默认安装机制(取代本地源构建),并随后仅在CI/CD上构建,以限制开发者机器被入侵的风险。尽管采取了这种日益静态的方法,Homebrew的核心代码库本质上是动态的,并且在许多地方反映了Homebrew历史上通过用户控制的Ruby代码动态加载DSL指定公式的需求。
范围
Homebrew既是一个用户可安装的包管理器(brew CLI),也是一个打包生态系统,具有广泛且定制的CI/CD配置,用于审查、构建和向最终用户分发bottles。我们的审计聚焦于这两方面的内容,旨在回答以下(但不限于)问题:
- 本地参与者能否诱导公式DSL的意外执行,例如在没有显式调用
brew install
的情况下? - 本地参与者能否诱导tap公式的意外评估,例如仅通过
brew tap
且没有后续用户操作? - 本地参与者能否在brew内诱导命名空间混淆或冲突,导致
brew install foo
安装意外公式? - 本地安装的公式能否秘密破坏或绕过Homebrew的构建隔离机制?
- 无特权或低特权CI/CD参与者(如第三方贡献者)能否在Homebrew的CI/CD中提升到更高特权?
- 无特权或低特权CI/CD参与者能否秘密污染或破坏bottle构建?
- 无特权或低特权CI/CD参与者能否在Homebrew的CI/CD中建立持久性?
重点发现
brew
在审查brew CLI代码库期间,我们发现了许多发现,虽然不关键,但可能破坏Homebrew的每公式完整性和隔离属性。我们还发现了可能允许从意外源(如远程URL)加载公式(即可执行代码)的发现。
一些有趣的发现包括:
- TOB-BREW-2:其中公式可以通过字符串注入影响其沙箱的构建,导致沙箱逃逸。
- TOB-BREW-5:其中Homebrew使用易碰撞的哈希函数(MD5)用于合成命名空间(FormulaNamespace),可能允许攻击者诱导公式间的运行时混淆。
- TOB-BREW-8:其中公式可以秘密地在构建中包含网络资源,而无需通过resource节显式列出它们。
- TOB-BREW-11:其中公式可能使用套接字枢轴在macOS上逃逸其构建沙箱。
- TOB-BREW-12:其中公式可以机会性地通过用户先前激活的sudo令牌执行权限提升。
- TOB-BREW-13:其中可以诱导
brew install
从非本地URL安装公式,适用于所用curl版本支持的任何协议,如SFTP或SCP。
我们对Homebrew/brew的整体评估反映在我们的报告中:虽然经过广泛测试,但Homebrew的大型API和CLI表面以及非正式的本地行为合约为机会主义攻击者提供了多种非沙箱本地代码执行的途径。这些途径不一定违反Homebrew的核心安全假设(假设公式可信),但可能被恶意公式或通过意外的公式加载源(如未充分清理的输入)破坏。
Homebrew的CI/CD
我们对Homebrew的CI/CD工作流和actions的审查发现了可能破坏Homebrew CI/CD运行完整性并允许较低特权用户提升到更高特权位置甚至在其自托管的GitHub Actions runners上获得持久性的发现。
一些有趣的发现包括:
- TOB-BREW-18:其中多个CI/CD工作流使用
pull_request_target
触发器允许第三方拉取请求在Homebrew上游仓库的上下文中运行代码,可能启用凭据披露或篡改Homebrew的bottle构建。 - TOB-BREW-23:其中多个CI/CD工作流无意中允许通过未清理的
workflow_dispatch
输入进行shell注入,可能允许较低特权用户(即可以分派工作流但无法修改它们的用户)进行垂直移动。
除了CI/CD特定发现外,许多brew发现在CI/CD设置中也很突出:
- TOB-BREW-6:描述了归档提取期间缺乏沙箱/隔离,可能被较低特权CI参与者用于通过诱导提取在CI生命周期中自动加载和执行公式或其他可执行代码来枢轴到更高特权上下文。
- 上述描述的TOB-BREW-13:可能被较低特权CI参与者用于通过诱导通过
brew install
安装不在CI预配置(假定可信)上下文中的公式的任意代码执行来枢轴到更高特权上下文。
我们的报告得出结论,Homebrew的CI/CD虽然成熟且有效减少了Homebrew包生命周期中的人工接触点,但很复杂,并依赖于GitHub Actions工作流中常见的易误用模式(如危险的工作流触发器和通过模板扩展混合配置、代码和数据)。这些模式不一定使完全外部参与者能够获得持久性或枢轴,但可能被较低特权内部人员(如恶意维护者)利用来破坏Homebrew CI/CD所做的完整性和隔离假设。
要点
审计像Homebrew这样的包管理生态系统带来了独特的挑战。本地包管理工具设计上安装和执行任意第三方代码,因此通常在预期和意外代码执行之间具有非正式和松散定义的边界。这在像Homebrew这样的打包生态系统中尤其如此,其中包的“载体”格式(公式)本身就是可执行代码(在Homebrew的情况下是Ruby脚本)。
在整个审计过程中,我们与Homebrew维护者和Homebrew PLC密切合作,并感谢他们分享广泛的知识和专业知识。我们还要特别感谢Homebrew的安全经理Patrick Linnane,他代表Homebrew进行了分类和协调工作。
如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News
页面内容
Homebrew
范围
重点发现
要点
近期文章
Trail of Bits的Buttercup在AIxCC挑战赛中获得第二名
Buttercup现已开源!
AIxCC决赛:记录表
攻击者的提示注入工程:利用GitHub Copilot
作为新员工发现NVIDIA Triton中的内存损坏
© 2025 Trail of Bits。
使用Hugo和Mainroad主题生成。