闪电贷攻击偷袭

封面:Photo by Abdullah Ahmad on Unsplash

北京时间 2024 年 1 月 30 日,据 Beosin 旗下 EagleEye 安全风险监控、预警与阻断平台监测显示,DeFi 协议 MIM_Spell 遭黑客闪电贷攻击,导致了超 600 万美元的损失。目前攻击者将被盗资金兑换为 ETH,并转移到两个攻击者地址上,Beosin KYT 将对资金进行持续监控,同时我们对本次漏洞进行了分析。

漏洞分析

该事件发生的主要原因是攻击者利用了项目方合约使用了向上取整的算法,并且控制了参数为 1,将向上取整的误差控制的最大,从而导致账本失衡。

合约存在两个函数,分别是 borrow 和 repay,一个是向合约借钱,一个是还钱给合约。

Borrow 函数将指定借款数额,并且通过比例转换计算出债务值,更新到调用者的总债务值。如下图,这里合约的 add 算法采用了向上取整。 

Borrow 函数将指定还款债务值,并且通过比例转换计算出还款数额,将还款数额转移到本合约。如下图,这里合约的 sub 算法依然采用了向上取整。 

了解了借款和还款的过程,我们来看看黑客是如何利用该漏洞的。

黑客先将合约的借款数额与债务值控制为了 0 与 97(如何控制将在下一节介绍)。

接下来不停调用 borrow 和 repay 函数,并且借款和还款数值都为 1,最后将借款数额与债务值控制为了 0 和 120080183810681886665215049728,导致比例严重失衡。

根据上述代码规则 (elastic=0,base=97),当攻击者调用一次 borrow 并传入 1 时,两个账本将变为 elastic=1、base=98(elastic 为 0 时,将按数值同步增加),再次调用一次 borrow 并传入 1 时,将变成 elastic=2、base=196(elastic 不为 0 时,将按比例同步增加)。

接下来攻击者调用 repay 函数传入 1,将调用 sub 函数,此时计算出来的 elastic 应该等于 1*1/196=>0,但是算法向上取整,导致计算出来 elastic=1,结果将变成 elastic=1、base=195。可以看到,此时 elastic 不变,base 却翻倍。

攻击者通过多次上述方式,将 elastic=0、base=120080183810681886665215049728。最终通过一笔 borrow 将合约 500 多万 MIM 借贷出来。

攻击流程

明白了函数问题点,我们来看看攻击者是如何实施攻击的(其中一笔交易为例)。
1. 攻击者首先借贷了 30 万枚 MIM。 

2. 随后,攻击者在回调函数中查询借款数额与债务值,可以看到,此时为 24 万和 23 万。

3. 接下来攻击者调用 repayForAll 函数,归还了 24 万 MIM 代币,将 elastic 控制得极小

4. 接下来,攻击者通过 repay 函数归还了其他用户的负债,最终将借款数额与债务值控制为了 0 与 97。 

5. 攻击者新创建合约,并通过上诉 borrow 与 repay 的方式,将借款数额与债务值控制为了 0 和 120080183810681886665215049728。 

6. 最终通过一笔 borrow 将 500 万 MIM 借贷出来,并归还闪电贷。 

资金追踪

截止发稿,被盗的超 600 万美元的资金,全部被攻击者兑换为了 ETH,并且一直分散存在黑客地址未移动,Beosin KYT 反洗钱平台将对资金进行持续监控。

免责声明:作为区块链信息平台,本站所发布文章仅代表作者及嘉宾个人观点,与 Web3Caff 立场无关。文章内的信息仅供参考,均不构成任何投资建议及要约,并请您遵守所在国家或地区的相关法律法规。