Vyper 被黑的时间线和反思’ 以下是 Vyper 被黑的时间线和反思的结果:

Vyper黑客事件时间线和反思结果如下:

信任,但要核查

image

由于合约的不可变性, 项目会隐性依赖多年前编写的代码, 我们在修复 bug 时,就更需要注意它的潜在影响。

在区块链领域,有一句非常经典的口头禅:“信任,但要核查”。这句话的意思是,在处理区块链项目的过程中,我们不能仅仅依赖于信任,而是要对项目进行全面的核查和审查。这是因为,由于合约的不可变性,项目往往会依赖多年前编写的代码。在修复 bug 的过程中,我们必须格外注意可能带来的潜在影响。

在一个项目中,我们遇到了这样的情况。接下来,我将通过时间线的方式向大家讲述这个故事。

时间线

在本文中,我会用“我们”来指代所有为这次事件努力的人。我觉得,虽然我最初对发现漏洞作出了一些贡献,但在整个过程中,有无数人提供了更多的帮助。

  • 13:10 UTC,pETH/ETH 流失了 1100 万美元。
  • 13:19 UTC,Michal 在 ETHSecurity 上发布了关于 pETH 价格突然暴跌的消息。
  • Igor 首先注意到了这里的不对劲,并引发了我们的深入调查。

但是机器人是如何在remove_liquidity()调用中重入add_liquidity()的呢?

  • 14:01 UTC,我们成立了一个应急小组来解决这个问题。
  • 14:07 UTC,我们使用我们最喜欢的反编译器,对 JPEGd 合约进行了反编译,并注意到重入保护存储槽有些不同。
// DisLianGuaitch table entry for add_liquidity(uint256[2],uint256)
label_0057:
    if (storage[0x00]) { revert(memory[0x00:0x00]); }
    storage[0x00] = 0x01;

// DisLianGuaitch table entry for remove_liquidity(uint256,uint256[2])
label_1AF3:
    if (storage[0x02]) { revert(memory[0x00:0x00]); }
    storage[0x02] = 0x01;
  • 14:27 UTC,我们通过一个简单的本地测试合约确认了这个问题。
@external
@nonreentrant("lock")
def test(addr: address) -> bool:
    return True

@external
@nonreentrant("lock")
def test2(addr: address) -> bool:
    return False

这次出现的问题可不仅仅是另一个重入 bug。

我们意识到这个 bug 将会产生怎样的影响。为了封锁消息,我们删除了有关该漏洞的公开消息。

  • 14:37 UTC,Wavey 帮助确认了存在漏洞的提交和受影响的版本。我和 Charles 通过手动检查 Vyper 编译器输出也证实了这一点。
image

这就像是一场与黑客的竞赛。

幸运的是,人们将其与只读重入混淆。“Alchemix”和“Metronome DAO” 也因为只读重入 bug 遭到了黑客攻击。

Michael 发现了运行着 0.2.15 版本的 alETH 和 msETH 池也存在潜在漏洞。

  • 14:50 UTC,msETH/ETH 被耗尽。
  • 15:34 UTC,alETH/ETH 被耗尽。
  • 15:43 UTC,我们发现用 Vyper 版本 0.3.0 编译的 CRV/ETH 存在漏洞。我们必须尽可能长时间保密受影响的合约,这一点至关重要。
  • 16:11 UTC,我们开始研究白帽漏洞。
  • 不幸的是,太多的组织在同时进行独立研究,谣言四起。到了 16:44 UTC,我们决定针对受影响的版本发布公开声明。

但是,到了 18:32 UTC,我们有了一个可用于潜在白帽拯救的概念证明漏洞。和Chainlight一起研究漏洞的bLianGuaik于 19:06 UTC 分享了他的研究成果。

五分钟后,19:11 UTC,有人盗走了资金。

这次攻击的结构与我们的概念证明有很大不同,不太可能是我们团队泄密。无论如何,这一切都令人非常沮丧。

然而,尽管如此,还有很多工作要做。

  • 21:26 UTC,Addison 提出了一个雄心勃勃的计划,拯救 CRVETH 池中的剩余资产。

如果你将 30k crv 发送到 crv/eth 池,你可以更新管理费(admin fee),然后设置 crv/eth 费率约为每个 crv 0.15 eth,基本上可以全部提取走池中的数百 K crv。

  • 21:52 UTC,bLianGuaik 提出了一个可行的概念证明,可以拯救 3100 ETH。
  • 十分钟后,22:02 UTC,我们再次被击败。出乎意料的是,CRV 管理费用机器人已被取走资金,并且池子已经耗尽。

责备

责备是一个非常强烈的词。指责没有什么用处。我觉得思考一下有哪些方面可以做得更好才是有用的。

竞赛

白帽们的努力在不到半小时的时间内就被击败了。有时候,每一秒都非常重要。

也许我们可以有更好的准备和资源来执行这些攻击。然而,这似乎是一把双刃剑。把如何执行黑客攻击的信息汇总起来真的是个好主意吗?我们应该信任谁?

另一方面,我觉得整个过程非常高效。从最初的怀疑到确认受到攻击的人只用了 2 小时 4 分钟。

信息泄露

我既是审计员又是白帽黑客。

审计行业有着特有的发布文化。我们因为在技术思想和漏洞理解方面领先而受到回报。然而,证明自己的领先和深刻的方法之一就是发布“独家新闻”,也就是有关黑客行为的消息。研究人员付出了巨大的努力,而获得的回报却是宣传。

另一方面,有一个令人信服的观点认为,早期公开披露受影响版本的信息对于白帽拯救工作将产生重大影响。

如果再多半小时,我们也许可以拯救 1800 万美元。

审计师们并不会为他们的报告所造成的影响付出代价。相反,他们会获得点赞、转发和报道。这似乎是一个问题。

下一步

我对于“我们需要形式化验证来解决这个问题”的观点并不完全认同。这个错误可以通过单元测试捕获。形式化验证对于许多错误类型非常有用,但对于相对简单、未优化的编译器来说,我并不认为它同样有效。

需要注意的是,这个错误在 2021 年 11 月就已经修复了。

我认为这个 Vyper 漏洞不是 Vyper 团队的技术或语言本身的问题,更多是流程问题。这个错误在很久以前的版本已被修复,但在修复的时候并没有意识到它的潜在影响。

不幸的是,公共物品很容易被忽视。由于合约的不可变性,项目往往会隐性依赖多年前编写的代码。协议开发人员和安全专家应该了解整个执行堆栈的最新安全开发情况。

以上就是这次事件的全部内容。希望通过这次事件,我们能够从中吸取经验教训,更好地提高项目的安全性。