分析 ERC2771 与 Multicall 集成引发的任意地址欺骗攻击
2023 年 12 月 4 日星期一晚上 9 点 UTC,OpenZeppelin 收到了来自 thirdweb 团队的安全披露。这是关于两个标准:ERC-2771 和 Multicall 的集成引起的问题。
OpenZeppelin 团队迅速验证了该问题, 并非是 OpenZeppelin Contracts 库的实现所特有的问题。
尽管如此,为了保护生态系统免受此漏洞的影响,OpenZeppelin 事件响应团队带头努力识别潜在的受影响合约。在识别阶段之后,OpenZeppelin 团队与更广泛的生态系统合作伙伴联系,扩大识别工作并进行缓解措施。
这是一个由问题集成模式引起的广泛问题。对生态系统有广泛影响,特别是对 thirdweb 用户和 thirdweb 的 fork。受影响的 thirdweb 合约在此处列出 ,但我们的库或其他实现中可能还存在与此集成问题的合约。
我们的团队已经通过协调系统化的联系策略,帮助了几个资产规模可观的流动池(包括这个在内)。尽管如此,借助 Dedaub 和 Ironblocks 团队的监控和分析,我们观察到一些攻击正在发生:
金额:84.59 ETH
金额:17,394 USDC
https://polygonscan.com/tx/0x1b0e27f10542996ab2046bc5fb47297bcb1915df5ca79d7f81ccacc83e5fe5e4
金额:1.06 ETH
金额:0.73 ETH
金额:0.36 ETH
金额:0.29 ETH https://explorer.phalcon.xyz/tx/eth/0x913f68babb2851903df7efe6bbc7c83dbbd1c2a858df0d47a1328750f90305fb
任何实现了Multicall
和 ERC-2771 的合约都容易受到地址欺骗攻击。在 OpenZeppelin 合约库的上下文中,这可以通过Multicall
和ERC2771Context
来实现。攻击者可以在转发请求中包装恶意 calldata,并利用Multicall
的delegatecall
功能来操纵子调用中的_msgSender()
解析。
ERC-2771 是用于元交易的标准。它标准化了应该如何解析由受信任的转发器中继的调用的调用者地址。在这样的调用中,msg.sender
是转发器的地址,而实际的调用者只有转发器本身知道(并使用签名进行验证)。因此,ERC-2771 详细说明了关于原始调用者的信息是如何由转发器传递给被调用合约的。
正如在 OpenZeppelin Contracts 的ERC2771Context
实现中所看到的,ERC-2771 标准重新实现了msgSender()
和msgData()
,以便正确处理来自受信任转发器的调用。当检测到这样的调用时,实际调用者的地址将从 calldata 的最后 20 个字节中提取。
💡 这是对攻击的简单表示。攻击者可以在单个multicall(bytes[])
中秘密的包含多个欺骗性调用。
从 OpenZeppelin Contracts 集成ERC2771Context
和Multicall
的合约可以通过 OpenZeppelin Defender 的 Code Inspector 进行检测 。OpenZeppelin Defender 安全平台要求在标记合约为易受攻击之前,必须满足以下每个条件:
合约导入任何标题或文件名以Context
为结尾的合约。假定任何变体都遵循 ERC-2771 模式。
合约导入任何标题或文件名以Multicall
为前缀的合约。
如果合约具备以下所有特征,则受到影响:
具有让用户提供数据进行delegatecall
调用自身的能力(例如Multicall
)
一些上下文细节(例如调用者的地址)是从受信任合约传递的数据中提取的。特别是ERC2771Context
或类似的 ERC-2771 实现(包括GSNRecipient
)。
推荐的缓解措施取决于具体合约细节。在采取行动之前,评估漏洞是否已蔓延到具有访问其他关键功能的函数:
检查使用_msgSender()
进行访问控制管理的函数。一些具体的例子是使用_msgSender()
的onlyOwner
或onlyRole
函数。
寻找常见的转账函数,如safeTransferFrom()
或transfer()
。
一些自定义的ERC2771Context
实现允许设置受信任的转发器。这样可以防止执行任何无 gas 交易,从而限制任何可能的利用。这可能不是一个令人满意的长期解决方案,但它是一个临时缓解措施,直到找到更好的解决方案。
可以执行此步骤的用户可以跳过措施 2。
暂停你的合约会影响你的用户,但可以降低漏洞的风险。然而,根据你的实现,漏洞可能允许攻击者取消暂停你的合约。尽管这种缓解措施不完整,但它给潜在攻击者增加了一些障碍,为完成下一步提供了一些时间。
尽管漏洞可能仍然存在于你的合约中,但确保指导受影响的用户使用 Revoke.cash 等工具。这是一个重要的步骤,因为在许多情况下,它可以显著降低攻击的盈利能力。
如果你的合约无法升级,请转到措施 4。
这个潜在的修复需要在两者同时存在的地方只保留Multicall
或ERC2771Context
合约中的一个。根据用户与你的合约的交互方式,一个可能对你系统的可用性产生更大影响,这可能有助于确定保留哪个合约以最小化对最终用户的影响。
如果你使用包含某些批处理机制的转发器,你可能希望删除Multicall
,而选择基于 ERC-2771 的批处理解决方案。这将影响用户需要签署的内容(EIP-712 类型数据 + 中继交易)。
你可以使用 OpenZeppelin Upgrades 插件来检查你的升级操作的兼容性,或者与 OpenZeppelin Defender 协调你的升级 。升级完成后,漏洞应该被修补。如果你已完成此步骤,可以忽略措施 4 。
无法升级的易受攻击的合约无法恢复到完全正常和安全的状态,除非你能够执行第 1 步。但是,仅执行第 1 步将使你的合约无法支持元交易。如果你需要重新启用此功能以使系统正常运行,你可能需要计划迁移。
我们建议项目确定受信任的转发器可能被授予的任何角色。这是因为即使完成了第 1 步,攻击者仍然可以使用转发器。OpenZeppelin Defender Access Control 模块可以帮助确定感兴趣的合约中的访问控制角色。
请注意,迁移是一个复杂的过程,会对你的用户和你交互的其他协议产生影响。但是,这样做可能是成功缓解漏洞的必要条件。因此,我们建议你寻求受信任的顾问来规划迁移。
升级的替代方案是对合约状态进行快照。这取决于数据在你的合约中的存储方式,尽管对于 ERC-20 和 ERC-721 合约有可用的解决方案。其他不太标准的合约可能需要自定义逻辑以实现对快照机制的支持。然后,可以在部署系统的新修补版本时复制此状态的副本。
区块链公开跟踪所有更改。因此,一旦你确定了“安全”的区块号(在执行任何攻击之前),你应该能够在几天、几周甚至几个月内构建快照。你需要时间来计划如何将此快照用作新部署的基础。
请记住,你的合约持有的任何资产(作为抵押品)可能无法转让。此外,如果你的合约是第三方协议中用作抵押品/流动性的资产(例如,在 AMM 中交易的 ERC-20),你必须考虑该迁移对流动性提供者的影响。
为了履行我们对安全生态系统的承诺,,我们为 OpenZeppelin Contracts 的 4.x 和 5.x 版本发布了新的更新,允许Multicall
与ERC2771Context
一起使用。
虽然在没有适当措施的情况下,这些模式之间的集成仍然存在问题,但 OpenZeppelin Contracts 库的更新允许以安全和向后兼容的方式进行集成。 新版本的Multicall
带有ERC2771context
数据的上下文后缀长度,用于标识预期的 ERC-2771 后缀长度。这样,来自受信任转发器的任何调用都将被识别并适应到每个子调用中。
使用 Multicall
现在建议考虑到对接收到的 msg.data
的任何期望都可以通过将调用包装在 Multicall
中来绕过,澄清其潜在危险。
本翻译由 DeCert.me 协助支持, 在 DeCert 构建可信履历,为自己码一个未来。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!