Tornado Cash 治理系统遭到攻击,攻击者利用 CREATE、CREATE2 和 selfdestruct 等操作码,部署包含自毁函数的恶意合约,在提案通过后删除原合约并在相同地址部署恶意合约,从而控制了治理合约,最终导致大量资金被盗。
图片来源 — https://www.onchainupdates.com/tornado-cash-governance-hacked-the-hack-that-shook-dao-governance/
5月13日,Tornado Cash 的治理系统遭到攻击。
让我们了解一下这是如何发生的,以及漏洞是什么。这篇文章不会涉及统计数据,更多的是关于攻击的技术路线。
简介:攻击者主要使用 CREATE、CREATE2 和 selfdestruct 来利用治理系统。他们提出了一个与之前通过的提案相同的合约,但这个提案有一个 selfdestruct 函数,没有引起注意。在被接受后,黑客删除提案合约,并在同一地址部署一个恶意合约。由于这个地址已经被治理系统接受,他们获得了对治理合约的完全控制权。
首先,治理系统的工作方式是,成员提交提案,其他成员投票赞成或反对该提案。要参与治理,你需要锁定特定的代币(在这种情况下是 TORN 代币)。
在投票或创建提案后,代币将被完全锁定,直到提案执行或被拒绝。提案必须作为经过验证的智能合约提交,如果获得 DAO 的批准,代码将通过 delegatecall 在治理合约中执行。
来源 — https://tornado-cash.medium.com/tornado-cash-governance-proposal-a55c5c7d0703
到目前为止,一切看起来都很好,除非我们知道攻击者使用的主要漏洞是 selfdestruct()
以及 CREATE2 操作码。
让我们把这分解成几个步骤。
https://etherscan.io/tx/0xf93536162943bd36df11de6ed11233589bb5f139ff4e9e425cb5256e4349a9b4
emergencyStop
,该函数应该执行 selfdestruct
函数并删除合约。我们可以用“特洛伊木马”这个词来形容它。攻击者部署提案合约。来源 — https://youtu.be/whjRc4H-rAc
selfdestruct
,然后在同一地址部署一个新的恶意合约。攻击者删除提案合约。来源 — https://youtu.be/whjRc4H-rAc
攻击者在同一地址部署一个新的恶意合约并劫持合约,来源 — https://youtu.be/whjRc4H-rAc
但问题是怎么会这样?这次攻击的主要失败点是什么?
让我们理解上面提到的步骤 2。他们怎么能在同一个地址部署一个具有不同代码的新合约?
为了回答这个问题,我们应该了解的最基本的概念是在使用 CREATE 和 CREATE2 操作码时智能合约的地址生成过程。
CREATE 当我们使用 CREATE 操作码来部署合约时,为该合约生成的地址取决于创建者的地址和创建者的 nonce。
这是如何使用发送者的地址和 nonce 生成地址的:
address of contract = last 20 bytes of sha3(rlp(sender,nonce))
你知道吗? 智能合约地址也有一个 nonce。但它与 EOA nonce 不同,因为它仅在合约部署另一个合约时增加,而不是每次合约调用我们称之为“内部交易”的其他合约函数时增加。在 EIP 161 之后,新部署的合约中的 nonce 从 1 而不是 0 开始。在继续前进时请记住这一点。
CREATE2 在 CREATE2 中,不需要 nonce。地址生成取决于 4 个参数。
我们甚至可以在部署之前计算地址。这里 是一个你可以查看的小型实践。
用于生成地址的 solidity 代码如下所示。
address of contract =
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xFF),
address(this),
salt,
keccak256(creation code)
)
)
)
)
);
我们现在可以说,为了像以前一样在同一地址上部署合约,我们需要满足这两个条件。
现在让我们看看黑客如何在这种情况下结合 selfdestruct
、CREATE 和 CREATE2 的潜力。我将再次写下这些步骤,但这次以一种更容易理解的方式。
到目前为止,流程如下所示:
这些框是合约
虚线框是被销毁(删除)的合约
这里是关于 CREATE 和 CREATE2 的关键部分。
CREATE 取决于发送者的地址和 nonce,每次合约部署另一个合约时,nonce 都会增加 1。
CREATE2 取决于发送者的地址、salt 和创建代码。这意味着 nonce 不需要相同,但合约创建代码应该相同。
很明显,为了在与提案合约的地址相同的地址上部署恶意合约,我们不能使用 CREATE2,因为代码已经更改,因此创建代码也已更改。
这意味着我们需要使用默认的部署方法,即 CREATE。
但是在这里我们遇到了另一个问题,即在部署提案合约后,Sender 合约的 nonce 将增加 1,并且在部署恶意合约时,将生成不同的合约地址。
这就是为什么黑客也销毁了 Sender 合约的原因,selfdestruct 也会将地址 nonce 重置为 0。这样,在使用 CREATE2 部署 Sender 合约后,nonce 将再次为 1,并且地址已经相同。这导致恶意合约部署在之前部署的已接受提案合约的同一地址上。
通过这种方式,攻击者获得了完全控制权。通过这次接管,他们解锁了锁定的 TORN 代币,并且为攻击者控制的每个地址分配了 10,000 个治理代币,总计 120 万张选票。
有了这么多选票,攻击者完全控制了 Tornado Cash 治理系统,因为只有大约 70,000 张合法选票。他们拿走了价值约一百万美元的资产。还使用了 Tornado Cash 本身来取出 ETH。
我希望这很容易理解,如果你对任何事情有任何疑问,可以在这里与我们联系。
- 原文链接: medium.com/coinmonks/tor...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!