数十亿美元代码中的潜在漏洞

  • Dedaub
  • 发布于 2022-04-20 14:51
  • 阅读 10

本文分析了xSushi类似奖励合约中存在的两个潜在漏洞,第一个漏洞与ERC777代币的重入攻击有关,攻击者可以通过在转账前重新进入合约来廉价获取份额。第二个漏洞涉及在有其他用户存款时,首次存款者可以通过操纵交易顺序,使得其他用户的存款份额被舍入为零,从而窃取后续存入的资金。文章还对以太坊上的已部署合约进行了检查,以评估当前是否存在受威胁的资金。

YANNIS SMARAGDAKIS

超十亿美元代码中的潜在 Bug

你可能很安全,但请注意……

Daniel Von Fange 上周联系了我:

嘿,我刚刚意识到,常用的 xSushi 奖励分配合约如果使用的存款代币是允许重入的 ERC777 风格,那么它很容易被完全盗窃。

这条消息引发了对大约 15 行代码的仔细检查,这些代码处理着数十亿美元的资金。

我们发现了不是一个,而是两个潜在的 bug。两者都有相当具体的条件才能成为漏洞。我们尽了最大努力确定当前的部署没有风险。(曾经有一段时间,攻击者可以窃取 6000 万美元。)但是,这并不意味着没有风险:可能有一些代币,如果你打算质押,有人现在就可以攻击你,更不用说未来部署可能发生的事情了。

要点:

  • 对类似 xSushi 的奖励合约的初始质押要格外小心
  • 永远不要使用 ERC777 基础代币部署此类合约。

总的来说:

  • 在与 ERC777 代币交互时,要注意重入威胁。

代码

这是一个有问题的代码的实例,一个常见的质押代币合约代码段。这样的代码最初在 xSushi 质押合约中使用,此后被广泛克隆。

contract VulnerableXToken {
    // ..

    // 支付一些代币并赚取一些份额。
    function enter(uint256 _amount) public {
        uint256 totalToken = token.balanceOf(address(this));
        uint256 totalShares = totalSupply();
        if (totalShares == 0 || totalToken == 0) {
            _mint(msg.sender, _amount);
        } else {
            uint256 what = _amount.mul(totalShares).div(totalToken);
            _mint(msg.sender, what);
        }
        token.transferFrom(msg.sender, address(this), _amount);
    }

    // 索回你的代币。
    function leave(uint256 _share) public {
        uint256 totalShares = totalSupply();
        uint256 what = _share.mul(token.balanceOf(address(this))).div(totalShares);
        _burn(msg.sender, _share);
        token.transfer(msg.sender, what);
    }

    // ..
}

enter 函数只是接受对底层代币(上面的 token)的投资,并通过铸造质押代币(VulnerableXToken)来发行份额。质押代币会累积奖励,并在 leave 时,投资者可以索回他们应得的底层代币比例。

Bug #1

乍一看,这段代码似乎是重入安全的。外部调用 (transferFrom) 发生在所有状态更新 (_mint) 之后。所以,似乎不会出错。

早在 2 月 24 日,著名的以太坊安全工程师 t11s发推 警告过 ERC777 代币。

ERC777 的一个杀手级功能 是它的接收Hook,允许合约在接收代币时做出反应。但经常被忽略的是在资金的 发送者 上调用的相应Hook,这些Hook 必须在更新状态之前调用

实施要求:

更新状态 之前,代币合约 必须 调用 tokensToSend Hook

更新状态 之后,代币合约 必须 调用 tokensReceived Hook

这意味着 任何 ERC777 代币都是一个重入死亡陷阱!代币 本身 违反了“外部调用前的效果”规则:它在提交转移效果之前调用发送者。任何调用代币的调用者可能都在维护 effects-before-calls 规则,但如果代币本身不这样做,那可能无关紧要。调用者应该对代币的效果不可知(即,从不读取余额),或者应该使用重入锁。

Daniel 意识到关于类似 xSushi 代码的是,ERC777 代币的 transferFrom 中的 PRE-transfer Hook将允许攻击者在任何资金转移到质押合约之前重入(字面上:重 enter,在上面的代码中),利用在调用之前所做的任何状态更改。在我们的例子中,在重入时,VulnerableXToken 余额已更改(通过内部 _mint 调用),但底层代币的余额没有:有更多的份额但相同的资金,所以,当重新进入时,份额似乎更便宜!

当然,底层代币不一定需要是 ERC777,因为对于任何实现与描述的类似回调机制的代币,这种漏洞利用都是可能的。

总结一下:

  • 如果类似 xSushi 的奖励合约的底层代币(上面的 token)回调一个Hook(例如,是一个 ERC777,它在发送者上调用 tokensToSend
  • 并且底层代币在调整余额之前执行此回调,
  • 那么可以重新进入并以更低的价格获得份额,直到完全耗尽其他人的资金。

Bug #2

当我在 Dedaub 内部频道分享代码时,Konstantinos(我们的一位高级工程师)立即评论道:

“我看到了这个 bug —— 我们以前在审计中没有遇到过这个吗?”

确实遇到过……

……但他没有看到 Daniel 的 bug!!!

这是一个完全不同的 bug,基于当另一个用户存款时,除法 _amount.mul(totalShares).div(totalToken) 向下舍入为零。这样,存款人将获得零份额,但旧的份额持有人将保留新存入的资金。

一个简单的攻击场景,只有两个存款人(攻击者和受害者)将如下进行:

  • 攻击者是第一个调用 enter 并存入 amount1token 的人,获得相等数量的份额。
  • 下一个存款人进来并尝试存入 amount2token。攻击者抢先他们,并直接转移到合约任何数量的 token 大于 (amount2–1)*amount1
  • 攻击者没有获得任何份额,但他们从一开始就拥有所有份额!这样,amount2*totalShares/totalToken 向下舍入为零,使下一个存款人一无所获,而攻击者可以通过调用 leave 撤回所有存入的 token,因为他们拥有所有份额。

要了解这个 bug 可能会产生多大的影响,请考虑第一次转移到 xDVF 质押代币:

这是转移了 1250 万个 DeversiFi 代币,目前每个价值 5 美元。攻击者本可以抢先转移并窃取所有价值 6000 万美元的代币!

检查实时漏洞

为了确定目前是否有资金受到威胁,我们使用了 Dedaub Watchdog 数据库来查询以太坊上所有当前部署的合约,以及它们的当前余额。

  • 在公开发布的源代码中,有 239 个部署在以太坊上的合约具有类似 xSushi 的 enter / leave 代码。
  • 其中 13 个目前有质押资金。价值最高的是 xShib(9.6 亿美元),xSushi(2.33 亿美元)和 xDVF(7200 万美元)。
  • 其中没有一个以 ERC777 作为底层代币。
  • 在初始存款期间面临抢先攻击风险的最大价值是 xDVF 中的 6000 万美元,如前所述。
  • 我们还检查了 Polygon,只发现了 4 个类似 xSushi 的合约,没有一个有质押资金。

虽然以上数字应该相当完整,但值得注意的是,可能仍然存在我们遗漏的威胁。相同的代码可以部署在以太坊以外的网络中;易受攻击的合约可能没有发布源代码,因此我们的搜索可能遗漏了它们;对于在转移时未发出预期事件的代币,我们的余额查询可能不完整;而且我们的 Polygon 扫描并不详尽——只考虑了大约最后 20 万个合约。

当然,当前部署的 200 多个或未来的任何类似 xSushi 的合约中的任何初始质押都容易受到抢先攻击。

结论

我们查看的代码非常简单,只有在非常微妙的情况下才会出现问题,并非所有问题都在其控制之下(例如,ERC777 重入可以说不是 xSushi 代码的问题)。它可能会不断被克隆,或者在其他设置中独立出现。(在后一种情况下,请告诉我们!)

无论哪种方式,我们都重申我们的意识信息:

  • 对类似 xSushi 的奖励合约的初始质押要格外小心
  • 永远不要使用 ERC777 基础代币部署此类合约。

总的来说:

  • 在与 ERC777 代币交互时,要注意重入威胁。

这些是社区应该了解的攻击媒介,以免我们看到其中一种被利用并造成重大损失。

  • 原文链接: dedaub.com/blog/erc777-t...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Dedaub
Dedaub
Security audits, static analysis, realtime threat monitoring