Multichain协议的用户遭到攻击,攻击者利用Multichain智能合约中的漏洞窃取了数百万美元的代币。文章深入分析了漏洞的技术细节,利用Tenderly调试器重放智能合约交易,揭示了攻击者如何通过构造恶意合约、绕过WETH合约的permit函数以及利用用户预先授权的无限额度来窃取资金。文章还总结了漏洞产生的多个因素,并提出了安全建议。
几天前,Multichain 的用户遭到多个攻击者团伙的攻击,他们都利用了 Multichain(以前的 AnySwap)智能合约中的同一个漏洞。 攻击者能够窃取价值数百万美元的代币。
加密协议公开宣布缺陷,用户遭到黑客无情攻击 \ 针对 Multichain 用户的黑客攻击正在恶化,因为一位网络安全研究人员称该事件为“最糟糕的方式... \ www.vice.com
在密切关注这次(非常有趣!)黑客攻击的细节的同时,我们希望在本文中重点关注此漏洞的技术方面。
为了分析这个漏洞,我们将主要使用 tenderly 的调试器,这是一个我最近才了解到的工具,似乎是以太坊研究人员工具箱的一个很好的补充。
Tenderly 调试器允许其用户重放智能合约交易的执行过程,包括所有参数、内部函数调用和当时的区块链状态,并逐步进入开源智能合约代码的每一行。
让我们直接开始分析一笔金额最高的漏洞利用交易,该交易导致 308 ETH(约 95 万美元)被盗。
攻击交易在 etherscan 中
让我们将此交易哈希提供给 Tenderly 调试器,看看它能告诉我们什么。
攻击交易在 Tenderly 中
调试器将我们引导到 Multichain 代码中的函数,攻击者可能滥用了该函数。 这是 anyswapRouterv4.sol 合约中的 anySwapOutUnderlyingWithPermit() 函数。
但是为了理解这种滥用,我们需要首先了解它的正常功能。
根据 网站,Multichain(以前的 AnySwap,因此得名)路由器的任务是:
Multichain 路由器允许用户在任意两个链之间自由交换。 它可以降低费用,并使在链之间移动变得更容易。
为此,路由器使用其 “anyToken” 包装实际的 token。 例如,DAI token 被包装为 anyDAI,或者反之,DAI 是 anyDAI 的底层资产。 包装后的 token 用于 Multichain 内部会计,当用户将 DAI 从以太坊 “转移” 到 BSC 时,实际上 anyDAI 会添加到 Multichain anyDAI BSC 合约中,并在 anyDAI 以太坊合约上销毁(减少)。
前面提到的被利用的函数 anySwapOutUnderlyingWithPermit 使用 ERC20 permit() 函数 交换底层 token。 permit() 函数允许其用户提供已签名的交易,以批准合约花费其资金,而无需实际将其发送到区块链,这有助于最大限度地降低用户的 gas 成本。 签名交易用 (v,r,s) 术语表示。
易受攻击的函数(来源 github)
在介绍之后,我们现在可以了解 anySwapOutUnderlyingWithPermit() 的功能:
该函数的其余部分处理其包装版本的会计处理并在链之间发送。
值得注意的是,根据我们在 Dune Analytics 上创建的查询,此易受攻击的函数从未实际使用过,它的首次使用是 1 月 18 日的漏洞利用。 这意味着此函数实际上是一块死木,只会增加合约的攻击面。
anySwapOutUnderlyingWithPermit() 在 1 月 18 日攻击者使用它之前从未被使用过(来源:Dune Analytics)
现在让我们看看攻击者传递给易受攻击的函数的参数
攻击交易在 Tenderly 中的函数调用参数
from 是受害者的地址, token 是攻击者部署的合约, to 目标地址也是如此。
我们可以看到攻击者没有传递有效的签名,因为 v,r,s 都是零。
攻击者试图通过无效签名获得其合约的 308 ETH。 它是如何工作的?
underlying() 输出是 WETH 合约地址 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2(Tenderly)
2. IERC20(_underlying).permit(from, address(this), amount, deadline, v, r, s); 最初 , 预期的结果是调用底层 token(“WETH”)的 ERC20 合约 permit() 以批准路由器(this)从用户(from)地址提取 amount 的能力,因为用户为此提供了用 (v,r,s) 表示的签名交易 但是,WETH 合约没有 permit() 函数! WETH 合约有一个 “fallback function”,当调用一个函数但未找到时会调用该函数。 WETH 的 fallback function 是 deposit(),在这种情况下不会执行任何实际操作,但允许其调用函数的执行继续,因为它不会失败。
WETH 合约没有 Permit(),回退到 deposit()(Tenderly)
3. TransferHelper.safeTransferFrom(_underlying, from, token, amount); 最初,我们预计如果我们到了这一行,则意味着上面的签名已验证,现在我们可以使用它授予的批准来实际将金额从用户转移到路由器 但是,如上所述,签名未经过验证。 理论上,这不应该是一个问题,因为尽管攻击者的输入不应该通过签名验证,但它没有批准路由器访问代表受害者转移资金。 但是,Multichain 的 dapp 要求其所有用户提供实际上是无限的批准金额。 这种不安全的方法在 dapp 中非常常见,可以节省用户的 gas 费用。 我们过去曾警告说,如果存在恶意或易受攻击的 dapp,这种行为(我们将其命名为 baDAPProve)可能很危险,而现在这种潜在的威胁已经变为现实。通过滥用这种过度的批准,该函数将 WETH amount 从受害者帐户转移到攻击者控制的合约。
现在攻击者获得了受害者的资金,他们只需要确保该函数不会失败,并且此转移不会被回滚,这就是代码的其余部分所做的。
正如事故和漏洞经常发生的那样,这里讨论的漏洞有多个促成因素,可能即使正确处理其中任何一个,都可以帮助 Multichain 的用户免受攻击:
此外,Multichain 没有对此合约应用任何升级机制,因此 用户唯一的防线是单独撤销他们之前的批准。
Twitter 嵌入
Twitter 小部件 Iframe
我们希望通过分享这项研究和经验教训,我们都能享受更安全的 Web3 环境。
- 原文链接: medium.com/zengo/without...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!