事件背景
根据NUMEN链上监控显示,Feb-09-2023 11:10:22 PM +UTC,Optimistic和Arbitrum链上dForce遭到闪电贷攻击,共损失2364枚ETH、103万枚USDC和72万枚USX,价值约540万美元。
攻击者地址:0xe0d551017c0111ac11108641771897aa33b2817c
攻击者合约:0xee29b6aee6e4783db176946e4e8f1e5fdcd446a7
攻击交易:0x5db5c2400ab56db697b3cc9aa02a05deab658e1438ce2f8692ca009cc45171dd
攻击分析
攻击者首先通过9次闪电贷攻击获得初始资金6.8万枚ETH。随后通过Vyper_contract.AddLiquidity添加流动性得到6.5万枚wstETHCRV。
将1900枚wstETHCRV质押获取1900枚wstETHCRV-gauge,并获得208万枚USX。
随后在Vyper_contract.remove_liquidity移除流动性操作中调用raw_call(msg.sender)攻击合约,并通过攻击合约回调vMUSX.liquidateBorrow进行两次清算。
之后正常调用Vyper_contract.remove_liquidity移除获利流动性资金,并将资金兑换为ETH,归还闪电贷后获利离场。
漏洞核心
关键问题是在Vyper_contract合约的remove_liquidity函数和get_virtual_price函数(Vyper_contract合约源代码,可查阅:https://arbiscan.io/address/0x6eb2dc694eb516b16dc9fbc678c60052bbdd7d80#code)。我们首先来看remove_liquidity函数:
移除流动性时,会先将ETH发送给调用者,之后将调用者LP Token销毁掉。
攻击者利用了这里存在的两个问题:
攻击者在回调vMUSX.liquidateBorrow时使用了Vyper_contract.get_virtual_price方法获取价格。
接下来,分析get_virtual_price函数:
由于移除流动性时,没有先对LP Token进行销毁,攻击者回调清算时正好使用了get_virtual_price用作价格。由于计算价格时LP Token总额并未减小,也就是token_supply增大,导致最终价格变小。攻击者利用未更新的LP总量进行价格计算,最终清算获取大量资金。
攻击复现
EXP https://github.com/numencyber/SmartContractHack_PoC.git
测试结果如下:
在最后的闪电贷回调执行完,打一下获利金额的日志。
用调用栈数据一致。
总结
NUMEN实验室提醒项目方,代币价格需要进行严格把控,多种喂价汇总在一块时,需要考虑价格计算的合理程度及喂价是否存在被控制的风险,并且对于合约代码逻辑遵循先判断,后写入变量,再进行外部调用的编码规范(Checks-Effects-Interactions)会使项目更加安全稳定,合约上线前进行多家安全审计,保障合约风险尽可能被消除在链下。NUMEN专注于为Web3生态安全保驾护航。
原文始发于微信公众号(Numen Cyber Labs):损失约540万美元!dForce项目攻击事件分析及PoC