发现Compound的第二个严重漏洞
本文转自 发现Compound的第二个严重漏洞 | 登链社区 | 深入浅出区块链技术 (learnblockchain.cn)
这个漏洞原作者在2022年02月23日已经发布过,由于内容比较敏感,发布后没多久就将违章的主要内容都删除了。然而,这个漏洞还是被利用了,March-15-2022 06:28:40 PM +8 UTC,Hundred Finance遭受攻击,黑客获利2363 ETH(价值超4000万美金)。Hundred Finance代码源自Compound,文中有在rinkeby上模拟攻击的交易,可以自行核对时间。
前置条件
- 开通了多个代币的市场
- 代币市场中有ERC777
- 攻击者在多个市场中存入资产,获得份额凭证。
- 攻击者向ERC777的代币市场发起借款,并在借款转账时,触发事先准备好的回调,在回调中退出这个发生了借款的市场。
- 攻击者赎回所有可以赎回的份额,由于借贷市场已经退出,因此不会在赎回时扣除用户的借款,因此可以正常退出,从而盗走借款。
文章图片
【发现Compound的第二个严重漏洞】
- 在borrowFresh()函数中,在完成借款的各项检查和准备后,会给用户转账,并更新用户的借款账本。
- 给用户转账doTransferOut()在更新用户账本之前,这使得用户可以有机会通过转账触发回调。
- 攻击者在回调中可以调用comptroller的exitMarket()函数退出借款的市场,由于此时用户的借款账本还没有更新,因此exitMarket()中检查用户是否可以退出该市场的逻辑会验证通过,攻击者可以成功退出市场。
- 攻击者退出借款市场后,再进行其他资产赎回时,由于发生借款的市场已经被退出,因此不会在赎回时计算这笔借款,从而可以成功赎回资产。
- 通过上述方法,攻击者可以成功的将借款偷走。
https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol#L786
退出市场,检查用户是否可以退出
https://github.com/compound-finance/compound-protocol/blob/master/contracts/ComptrollerG7.sol#L175
以下是在rinkeby上模拟攻击的相关交易 https://rinkeby.etherscan.io/tx/0x944f46be4591dbed7d855e99b5707557fd074303ff9c1935b2bc35c5e61d2eda
可以看出,攻击合约按照前面描述的流程,完成攻击后,合约内的资产多了800USDT。
漏洞特性 根据上面的分析可知,只要代币市场中有ERC777存在,就具备了攻击的条件!
另外,有很多项目是fork自Compound的,如果在fork项目时,将转eth的代码改用当前应用较广泛的TransferHelper.safeTransferETH(),则会导致这种攻击的发生。因为TransferHelper.safeTransferETH()通常的实现没有限制gas。
总结
- 使用重入锁并不能解决所有问题,可以考虑使用checks-effects-interactions模式,另外,转账最好放在一个完整逻辑的最开始或者最结尾,避免状态不一致。
- 这个取名safeTransferETH()的函数,并不会给大家带来安全,相反留下了被攻击的可能。因此,应该慎用TransferHelper.safeTransferETH()方法,另外,也建议在safeTransferETH()的实现里面,将gas限制为5000,这样既可以解决往代理合约转账的问题,也会让攻击难以发生。
推荐阅读
- 张高兴的|张高兴的 Entity Framework Core 即学即用((一)创建第一个 EF Core 应用)
- Spring源码完美导入IDEA的过程
- java自定义序列化的具体使用
- 详解java关于对象的比较
- 面试必问的安卓虚拟机,你真的掌握了么(——安卓虚拟机基础知识回顾)
- 为什么使用低代码的 60% 都是专业开发者()
- 区块链的架构模型
- #|送给小公主的一首诗——闪光屏幕书写(Python实现)
- #|基于改进二进制粒子群算法的配电网重构
- 编程|基于Matlab的遗传算法在图像分割问题中的应用