来源:SharkTeam
2024年1月30日,MIM_SPELL遭受闪电贷攻击,因为精度计算漏洞,项目方损失650万美元。
SharkTeam对此事件第一时间进行了技术分析,并总结了安全防范手段,希望后续项目可以引以为戒,共筑区块链行业的安全防线。
一、攻击交易分析
攻击者地址:
0x87F585809Ce79aE39A5fa0C7C96d0d159eb678C9
攻击合约:
0xe1091d17473b049cccd65c54f71677da85b77a45
0x13AF445F81B0DEcA5dCb2Be6A4C691F545c95912
0xe59b54a9e37ab69f6e9312a9b3f72539ee184e5a
被攻击合约:
0x7259e152103756e1616A77Ae982353c3751A6a90
攻击交易:
0x26a83db7e28838dd9fee6fb7314ae58dcc6aee9a20bf224c386ff5e80f7e4cf2
0xdb4616b89ad82062787a4e924d520639791302476484b9a6eca5126f79b6d877
攻击流程:
1. 攻击者(0x87F58580)通过闪电贷借取300000枚MIM代币。
2. 随后向被攻击合约(0x7259e1520)发送了240000枚的MIM代币,用于下一步偿还用户的借款。
3. 攻击者(0x87F58580)随后调用repayForAll函数偿还其他用户的借款,后续又依次调用repay函数偿还其他用户借款,目的是将elastic变量减小为0.
4. elastic变量减小为0后,攻击者(0x87F58580)创建新的攻击合约(0xe59b54a9)并不断的进行borrow和repay函数的调用,直到将elastic =0,base = 120080183810681886665215049728时结束。
5. 随后攻击者(0x87F58580)调用borrow函数和DegenBox合约的withdraw函数借出了5000047枚MIM代币。
6. 攻击者(0x87F58580)归还闪电贷函数,并将4400000枚MIM代币兑换为1807枚ETH,本交易获利约450W。
二、漏洞分析
攻击的本质是在进行借贷变量计算时精度出现了问题,使得关键变量elastic和base值被操纵后比例失衡,导致计算抵押物和借贷数量时出现问题,最终超额借出MIM代币。
被攻击合约(0x7259e1520)中borrow函数和repay函数在对elastic和base两个变量进行计算时,都采用了向上取整的方式。
攻击者(0x87F58580)首先通过偿还其他用户借款的方式,将elastic变量和base变量分别设置为了0和97。
随后不断的调用borrow函数和repay函数并且参数amount都为1,在第一次调用borrow函数时,由于elastic=0,会执行上述if逻辑并回到add函数中。这样会导致elastic = 1,base = 98。
攻击者(0x87F58580)再调用borrow函数并传入1,由于elastic=1,会执行else逻辑,计算出的返回值为98,这样在回到add函数中时,elastic=2,base变量为196.
但此时攻击者(0x87F58580)调用repay函数并传入1,由于elastic=2,会执行else逻辑,计算出的elastic变量本来为 1*2/98 =0,但由于下面存在向上取整的步骤,导致计算出的返回值1,这样在回到sub函数中时,elastic变量又变回1,而base变量为195。
可以看到在经历一次borrow-repay循环后,elastic变量不变而base变量近乎翻倍,利用这一漏洞,黑客频繁进行borrow-repay函数循环,最后再调用一次repay,最终使得elastic=0 base = 120080183810681886665215049728。
当elastic和Base变量之间的比例严重失衡后,攻击者(0x87F58580)添加了一点抵押物后即可通过solvent修饰符中的限制条件,从而借出大量MIM代币。
三、安全建议
针对本次攻击事件,我们在开发过程中应遵循以下注意事项:
1. 开发精度计算相关逻辑时,慎重考虑精度和取整情况。
2. 项目上线前,需要通过专业的第三方审计团队进行智能合约审计。