2023年12月8日,OpenZeppelin官方发布了一则重要的安全警报,指出在项目集成中使用ERC-2771标准和Multicall方式时存在任意地址欺骗攻击的风险。SharkTeam进行了技术分析并总结了安全防范手段,希望其他项目能够借此教训,共同加强区块链行业的安全防线。
攻击交易分析如下:
攻击者地址:0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A
攻击交易:0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
攻击流程:
1.攻击者使用5枚WETH兑换了约3,455,399,346枚TIME。
2.随后,攻击者构建了恶意的calldata参数并调用了[Forwarder].execute函数。
3.在调用[Forwarder].execute函数时,恶意的calldata触发了TIME合约的multicall函数。接着,使用剩余的calldata触发执行TIME合约的burn函数,销毁池中的TIME代币。
漏洞分析如下:
此次攻击事件涉及ERC2771、Multicall和经过精心构造的calldata。从TIME代币合约中可以找到相关的继承关系:
1.ERC2771提供了拥有虚拟的msg.sender能力,允许用户委托第三方[Forwarder]执行交易,以降低gas成本。提交交易时,msg.sender地址会被添加到calldata中。
2.TIME代币合约继承了ERC2771Context。当[Forwarder]调用合约时,_msgSender()会检查calldata数据,并将其右移,截断最后的20个字节作为预期的msg.sender。
3.Multicall是一种将单个函数调用转变为在同一个合约中按顺序调用多个函数的方法。它接受一个用户编码调用的数组并对其自身合约执行。这个函数遍历调用数组,并对每一个操作执行delegatecall()。它的主要目的是节省gas。
4.攻击者通过调用[Forwarder].execute函数,传入相关参数,构造恶意的calldata。
通过进一步格式化data值,我们得到以下结论:
攻击者通过对当前calldata的偏移操作获得新的data值,并将该值传递给multicall(bytes[])函数。新data的前4个字节是burn(uint256)函数的选择器,amount参数为62227259510000000000000000000。
在multicall(bytes[])函数中,通过delegatecall调用burn(uint256)函数。在0x20这一行,0x760dc1e043d99394a10605b2fa08f123d60faf84地址是在构造calldata时一开始添加在末尾的。该地址对应Uniswapv2上的TIME-ETH流动性池。
刚才提到的msg.sender为何变成TIME-ETH流动性池地址?原因是一开始msg.sender是[Forwarder]合约地址。为了判断是否是可信的[Forwarder],如果是可信的[Forwarder],则将msg.sender设置为calldata的最后20个字节。