SharkTeam:ERC2771&Multicall任意地址欺骗漏洞原理分析
字数 1691 2025-08-10 08:28:18
ERC2771与Multicall任意地址欺骗漏洞分析及防范指南
漏洞概述
2023年12月8日,OpenZeppelin发布安全警报,指出在项目集成中使用ERC-2771标准与类Multicall方式时,存在任意地址欺骗攻击的风险。该漏洞允许攻击者通过精心构造的calldata参数,欺骗合约的_msgSender()函数,模仿任意地址进行调用。
攻击案例分析
攻击交易详情
- 攻击者地址: 0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A
- 攻击交易哈希: 0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
攻击流程
- 攻击者先用5枚WETH兑换了约3,455,399,346枚TIME代币
- 构建恶意calldata参数并调用
[Forwarder].execute函数 - 恶意calldata触发TIME合约的
multicall函数 - 利用剩余calldata触发执行TIME合约的
burn函数,销毁池中的TIME代币
技术原理分析
涉及的关键技术
1. ERC2771标准
- 提供虚拟
msg.sender能力,允许用户委托第三方[Forwarder]执行交易 - 提交交易时,
msg.sender地址会被添加到calldata中 - 合约继承
ERC2771Context后,_msgSender()会检查calldata数据,截取最后20字节作为预期的msg.sender
2. Multicall功能
- 将单个函数调用转变为在同一个合约中按顺序调用多个函数的方法
- 接受用户编码调用的数组并对其自身合约执行
- 遍历调用数组,对每个操作执行
delegatecall() - 主要目的是节省gas费用
3. 精心构造的calldata
攻击者通过以下方式构造恶意数据:
- 调用
[Forwarder].execute函数并传入特定参数 - 通过对当前calldata的偏移操作获得新的data值
- 新data的前4个字节是
burn(uint256)函数的选择器 - 在
multicall(bytes[])函数中通过delegatecall调用burn(uint256)函数 - 将目标地址(如Uniswap v2上的TIME-ETH流动性池地址)添加在calldata末尾
漏洞根本原因
- ERC-2771的[Forwarder]并非专为multicall设计
- 攻击者将
_msgSender()函数中的相关参数添加到multicall的外部调用中 - 在multicall函数中,某些函数会附加
_msgSender()中的参数 - 导致攻击者可以欺骗
_msgSender(),模仿任意地址调用 - 最终通过授权销毁池子里的代币
安全建议与修复方案
OpenZeppelin官方修复方案
- 新版本Multicall带有
ERC2771context数据的context后缀长度标识 - 来自可信任[Forwarder]的任何call都将被正确识别并适应每个子函数call
- 仍然允许通过合约进行multicall
ThirdWeb的修复方案
- 禁止任何合约调用multicall
- 防止[Forwarder]使用multicall功能
- 相比OpenZeppelin的方案更为严格
最佳实践建议
- 及时升级:使用OpenZeppelin或ThirdWeb修复后的最新版本
- 权限控制:严格限制multicall函数的访问权限
- 输入验证:对所有传入的calldata进行严格验证
- 事件监控:监控合约中的异常调用模式
- 安全审计:在集成ERC2771和Multicall功能前进行专业安全审计
总结
ERC2771与Multicall的组合漏洞展示了智能合约开发中"功能组合"可能带来的安全隐患。开发者在集成多个功能模块时,需要特别注意它们之间的交互可能产生的副作用。通过理解此漏洞的原理和修复方案,开发者可以更好地保护自己的合约免受类似攻击。