“友好协商”后退赃90%,Arbitrum上Sentiment项目黑客事件分析
原文:《》
2023年4月5日,据Beosin-Eagle Eye态势感知平台消息,Arbitrum链的Sentiment项目遭受黑客攻击,黑客获利约1百万美元,不过在项目方的“感化”下,黑客已退还大部分资金。
据了解,Sentiment是一个Defi借贷项目。借贷逻辑是Sentiment为用户开设账户,用户通过此账户将资产质押到其他项目获取收益,并且在质押之后也可以进行借贷。本次攻击如何发生,请听我们详细分解。
事件相关信息
攻击交易
0xa9ff2b587e2741575daf893864710a5cbb44bb64ccdc487a100fa20741e0f74d
攻击者地址
0xdd0cdb4c3b887bc533957bc32463977e432e49c3
攻击合约
0x9f626f5941fafe0a5b839907d77fbbd5d0dea9d0
被攻击合约
0x62c5aa8277e49b3ead43dc67453ec91dc6826403
攻击流程
跟着Beosin一起来看看黑客是如何对Sentiment项目“下手”的。
1.攻击者首先从Tornado.Cash提取1ETH到其以太坊账户,然后通过跨链桥将0.7ETH转入到其Arbitrum账户做好gas准备。然后部署了他的攻击合约。
2.接着攻击者发起攻击交易,首先攻击合约通过闪电贷获得606个WBTC,10050个WETH和18,000,000个 USDC。然后,攻击合约在Sentiment项目中按照项目方的正常业务逻辑创建账户,并只在账户中质押了50个WETH,再通过Sentiment项目的AccountManager合约将这50个WETH添加到Balancer项目的Balancer: Vault合约中。为价格操控之后的借款提供质押记录。
3.可以看到,上面的质押是通过Sentiment开设的账户进行的,之后攻击合约以合约身份向Balancer提供大量流动性,一共花费了606个WBTC,10000个WETH和18,000,000个 USDC。
4.紧接着攻击者调用Balancer: Vault.exitPool()函数取回流动性,这个过程中Balancer: Vault会向攻击者转账从而调用攻击者预先构造好的fallback函数。
5.在fallback函数中,攻击者调用了Sentiment项目的borrow进行借贷。按照借贷的逻辑,借款需要检查借款人的质押,而Sentiment确实通过RiskEngine.isAccountHealthy()进行了检查。
6.这里的检查是通过WeightedBalancerLPOracle.getPrice()函数获取抵押物价格,而该函数依赖Balancer: Vault.getPoolTokens()返回的数据。由于这时攻击者退出流动性的操作还没有完成,这里返回的数据是包含了攻击者流动性的旧数据。
7.这个旧数据导致了预言机的价格计算错误,WeightedBalancerLPOracle.getPrice()返回价格由正常的220132731298820699变成了3550073070005057760,提升了约16倍,使得攻击者抵押的50WETH价值升高,从而能取出更多资产。
8.攻击者通过多个borrow和exec,最终获取了0.5个WBTC、30个WETH、538,399USDC和360,000USDT。然后通过跨链回到了攻击者的以太坊地址,并全部换成了517个ETH,价值约1百万美元。
漏洞分析
根据Beosin安全团队的分析,本次攻击主要利用了重入导致的价值计算错误。这一漏洞的主要原因是Sentiment项目未考虑到Balancer: Vault._joinOrExit()函数在流动性移除时,先转移资产再更新池子余额。导致在转移ETH资产时,会触发攻击合约的fallback调用,此时攻击合约借款,Sentiment采用未更新的Balancer的数据计算价格,导致比质押更多的资产被借出。
Sentiment的价格计算函数:
Balancer项目的流动性添加与移除函数:
资金追踪
Beosin Trace追踪发现,被盗资金为517个ETH,经项目方与黑客协商,其中51ETH为赏金已被黑客转移到Tornado.Cash,其余资金已归还项目方。
总结
针对本次事件,Beosin安全团队建议:
1.在合约开发时,采用检查-影响-交互模式。并且在多个合约相互依赖时需要更加注意合约之间的影响带来的安全问题。
2.项目与其他项目有数据依赖时,需要谨慎考虑项目之间的结合是否会导致新的安全问题出现。尽量通过原始数据作为自己逻辑的参考,减少对其他项目运算结果的依赖。