第三代互联网受到智能合约漏洞的围攻!代币被烧,投资者损失19万美金
任意地址伪造攻击分析
任意地址欺骗攻击
你好,亲爱的数字资产投资者!今天,为了让你不仅能够了解最新的数字资产风云,还能保持一丝微笑,我们为你带来了一则充满幽默和专业的文章。
在这个寒冷的2023年12月5日,Web3基础开发平台thirdweb意外地发现了一处安全问题。究竟发生了什么呢?是电力短缺导致了智能合约的冷失效么?哦不,根据第一手资料显示,使用thirdweb的预构建智能合约部署的ERC20、ERC721和ERC1155代币都陷入了困境。你能想象吗?这些智能合约怎么性情大变,变得如此躁动不安。下面这个链接是详细的故事,赶紧点进去看看吧:地址链接
慢雾安全团队第一时间介入分析,他们的研究显示,截至2023年12月7日,ETH主网上的Time代币,就因为该漏洞受到了攻击。这些经验丰富的攻击者,居然捞到了19万美金的利润。妈呀,他们可真是铁了心地攻击这些漏洞代币呀!而且消息传来,还有一些潜伏在暗处的代币合约也处于被攻击的危险之中。看到这个情况,慢雾安全团队披挂上阵,决定拿出自己的技术来为我们分析。接下来就让我们一起来看看他们的分析结果吧!
前置知识
在我们展开解析之前,简单介绍一下几个相关的概念。首先是“ERC-2771”,这可是尖端的元交易标准啊!它让你可以将交易的执行委托给第三方“Forwarder”,听起来像不像中继器或者转发器呢?原来的合约通常通过“msg.sender”获取调用者的地址,但是如果使用了ERC-2771,如果“msg.sender”居然是个转发器,它就会截断传入的“calldata”,然后神奇地获取最后20个字节作为交易的直接调用者地址。简直是魔术一般的操作啊!你看下面这个图片,幽默地揭示了其中的奥妙:
- ZachXBT:有人从Tornado Cash中提取了11200 多个以太坊,或为Uranium黑客!
- 关于铭文的数据上链和对比特币生态的意义
- 铭文:是一个 Bug 还是 Feature?——我来给你分析个清楚
另外,还有一个关键概念“Multicall”,这是一个智能合约库,并且其作用就是可以让你一次性执行多个合约函数调用,大大减少了交易成本。这个库通常用于优化DApp的性能和用户体验,特别是在需要进行多个读取操作时。这个智能合约库真是个帮手啊!不过话说回来,如果这个库被设置在缺陷代币合约中,就可能出现问题啦!就像下面的图片一样,会通过循环调用DelegateCall函数来执行引用了该库的合约中的其他函数:
有了“ERC-2771”和“Multicall”这两把锋利的武器,接下来我们来看看这次攻击的根本原因吧!
根本原因
这次漏洞的致命根源可谓是一拍脑袋惹出的祸啊!代币合约同时使用了“ERC-2771”和“Multicall”这两个家伙,结果可想而知,攻击者通过Forwarder合约的execute函数调用代币合约的multicall函数,执行合约中的其他函数,比如燃烧代币。这听起来可能没啥问题,但问题就是当Forwarder合约使用了ERC-2771的isTrustedForwarder函数判断后,它居然误认为调用者是其他用户的地址,最终导致了其他用户的代币被燃烧的悲剧。这个误判简直是智能合约的“近视眼”啊!你难以想象这个小小的漏洞居然给攻击者留下了前进的空间。
攻击步骤分析
好吧,接下来我为大家分析一下攻击的步骤。这里我以攻击交易“0xecdd11…f6b6”为例进行分析:
第一步,攻击者使用5个 WETH 在Uniswap V2池子中兑换成了令人眼花缭乱的 345,539,9346 枚Time代币。这样炫酷的数字让我们不禁陶醉其中啊!看看这个图片,是不是蛮惊艳的呢?
接着,攻击者调用了Forwarder合约的execute函数,通过构造恶意的data去调用代币合约的multicall函数。在这里,代币合约会根据攻击者传入的恶意data去delegateCall执行代币合约的burn函数,一口气烧掉池子地址中的62,227,259,510 枚Time代币!看下面这个图片,让你看到真实的攻击行为!
最后,由于上一步将池子中的大量Time代币烧掉,导致Time代币的价格瞬间飙升。聪明的攻击者最后一步是迅速反向Swap第一步获取的Time代币,掏空了池子中整整94 枚WETH。让我们一起惊叹这个反转的刺激场景吧!看一下下面这个图片,就能让你更加了解攻击方式了:
攻击原理剖析
接下来,我会给你一个更加深入的攻击原理解析。在Forward合约的execute函数中,验证req.from的签名后,会用call与req.to(代币地址)交互。你想不到吧,攻击者竟然在req.data中插入了恶意calldata!这种操作不禁让我们想起了仙女扑克中的绝活,是不是让你很好奇呢?
当你看到这段calldata的描述时,你会发现原来的calldata中并没有出现req.from这个参数。这是因为EVM底层处理call调用时,会根据其中的偏移量截取所需的值。这就是攻击者的一个巧妙之处,他们设置了偏移量38,长度为1的数值。结果截取出来的data值恰好是42966c680000000000000000000000000000000000000000c9112ec16d958e8da8180000760dc1e043d99394a10605b2fa08f123d60faf84。你想象一下,在这个操作过程中,EVM底层是如何实现的呢?你可以点这个链接了解更多细节哦:地址链接。下面这个图片演示了对call的描述:
因为0x42966c68是burn函数的函数签名,所以攻击者根据构造的data值进行了delegatecall调用代币合约的burn函数。下面这个图片揭示了其中的奥妙:
其中,_msgSender()函数被ERC-2771库重写,真是花招百出呀!既然是通过delegatecall进行调用的,isTrustedForwarder传入的msg.sender实际上是Forward合约的地址。这样一来,通过了判断之后,最终导致_msgSender()的返回值为传入calldata的最后20个字节,即池子的地址0x760dc1e043d99394a10605b2fa08f123d60faf84。让我们一起来为攻击者这次的伎俩鼓掌吧!瞧瞧下面这幅图,告诉你这整个过程的关键所在:
结论及建议
最后,让我们总结一下这次攻击的根本原因吧!问题出在合约同时引用了Multicall和ERC2771Context。攻击者通过插入恶意calldata的方式利用Multicall的delegatecall功能,通过“受信任转发器”的判断,顺利操纵了子调用中_msgSender()的解析,从而大肆操控任意用户的代币。这就是连环套招的精髓!
慢雾安全团队在这里郑重提醒各位项目方,在编写代币合约时切勿同时使用Multicall和ERC2771Context。如果你必须引用这两个合约,请务必检查calldata长度是否符合预期,或者采用OpenZeppelin官方最新版本的Multicall和ERC2771Context合约。如果你想寻求更多的信息和帮助,请点击参考链接。
最后,陪伴到这里我们来做个互动吧!在评论区里留下你对这次攻击的看法,或者你觉得上面提到的幽默词句中哪一个最给力,我们一起来探讨啊!
We will continue to update 算娘; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles





