Telegram Channel
前阵子 Bybit 价值 1.4B 的资产被盗,堪称史上最大金额的盗窃案。黑客所使用的盗窃技术其实并不复杂,某种意义上更说明整个区块链业界的安全观念仍然非常欠缺。

区块链的本质就是保存不可修改的数据块,Ethereum 的 EVM 就是运行在这些 append-only 的数据存储层之上的计算机。其中可以被运行的程序称为合约(Contract)。因为合约一旦被部署上链后,它的调用地址、代码就无法修改,只有数据可以被修改。为了让合约能够在不变更地址的前提下实现升级,人们想出了一个办法就是 proxy-Implementation 模式。也就是部署两个独立的合约,逻辑代码通过 implemenation 合约部署,然后再部署一个保存用户数据的 proxy 合约,proxy 合约作为面向用户的入口层,一旦部署就永久使用,以保证调用地址的稳定。proxy 合约中有一个 master 变量,可以理解为是一个指针,指向 implementation 合约的地址,实际的逻辑代码都是通过调用 implementation 合约来完成的。

从函数调用的角度来考虑,这相当于是 proxy 函数调用了 implementation 函数的代码,但是修改的却是 proxy 函数的数据。这种特殊的调用在 EVM 中称为 delegateCall,即在调用者的上下文中执行被调用者的代码逻辑。这一设计通过对数据和逻辑的拆分,让每个面向用户的 proxy 合约保持了地址和数据的一致性,而实现逻辑的 implementation 合约可以像插件一样随时更替。

然而,这次出事的就是这个 proxy-implementation 的设计。黑客部署了一个恶意的合约,这个合约有一个伪装成转账接口的方法,虽然看上去像是转账 transfer(address,uint256) ,但是其实际功能是替换 proxy 合约中的 master 属性,也就是替换其所指向的 implementation 合约地址。然后黑客生成了一个对这个恶意合约的调用 transfer("0xbDd077f651EBe7f7b3cE16fe5F2b025BE2969516", "0"),这个交易看上去像是一个无害的零额转账,但是因为设置了 operation=1 即启动了 delegateCall,实际上是执行了恶意合约的修改 proxy 合约中 master 属性的逻辑。很可惜,因为 Safe 的网站前端代码被黑客替换,Bybit 的三位管理员都没能注意到这次调用中的 operation=1 这个高度危险的设置,可能误以为是一次零额转账而签署了交易,黑客从而成功将 proxy 合约所指向的 implementation 修改为指向到自己的恶意合约,完全替换了 proxy 合约的逻辑,最终完成了对 1.4B 资产的盗窃。

Update: Safe 已经承认了,是因 Safe 的前端文件被黑客替换,导致了这一事件。 #blockchain

ref:

* 我曾写过一篇 web3 的简易入门,可以搜索 Upgradable 一节
* 关于 safe-wallet 被黑的分析
 
 
Telegram Channel