8点击蓝字
关注我们
声明
本文作者:PeiQi
本文字数:1999字
阅读时长:约5分钟
附件/链接:点击查看原文下载
本文属于【狼组安全社区】原创奖励计划,未经许可禁止转载
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,狼组安全团队以及文章作者不为此承担任何责任。
狼组安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经狼组安全团队允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
❝
2024 年 1 月 30 日,MIM SPELL 由于代码中出现借贷变量计算精度漏洞,导致损失 650万美元
相关地址
-
攻击者地址:0x87F585809Ce79aE39A5fa0C7C96d0d159eb678C9 -
攻击合约:0xe1091d17473b049cccd65c54f71677da85b77a45 -
被攻击合约:0x7259e152103756e1616A77Ae982353c3751A6a90 -
攻击交易:0x26a83db7e28838dd9fee6fb7314ae58dcc6aee9a20bf224c386ff5e80f7e4cf2
攻击过程
1.攻击者通过闪电贷获取初始资金2.通过漏洞提取合约内所有的 $MIM Token 并归还闪电贷3.最后将获利部分换成 $ETH
攻击分析
攻击者首先从闪电贷中借了 300,000 $MIM 代币通过 totalBorrow 查询 合约中的总借款资金 (total.elastic) 和总借款份额 (total.base) 合约中 repayForAll 函数允许任何人偿还债务,并将 total.elastic 的值缩小攻击者的目的是将总借款资金变成零去攻击四舍五入造成的漏洞,所以这里攻击者需要尽可能的将总借款资金清空,由于 repayForAll 函数中有 require 限制了总借款资金必须大于 1000 eth,所以不能一次性清空,攻击者先清除了一部分剩下部分通过 repay 函数将其他用户的借款资金偿还,其目的同样是将 total.elastic 尽可能变小在剩下最后一个用户时,攻击者将 total.elastic 和 totla.base 控制在 3 和 100,然后多次还款 1 后将 total.elastic 清空,此时 total.elastic 和 totla.base 分别为 0 和 97攻击者将前置工作完成后,开始了漏洞攻击这里发现通过不断的调用 borrow 和 repay 函数将总借款份额不断的增大,但增大的速率非常不正常,跟进代码可以看到漏洞点
function toBase(
Rebase memory total,
uint256 elastic,
bool roundUp
) internal pure returns (uint256 base) {
if (total.elastic == 0) {
base = elastic;
} else {
base = (elastic * total.base) / total.elastic;
if (roundUp && (base * total.elastic) / total.base < elastic) {
base++;
}
}
}
当 total.elastic 为 0 时,攻击者调用函数借款时 base 与 elastic 相等,此时 elastic 与 base 的值根据代码计算为 1 , 97 + 1 = 98 , 此时攻击者第二次调用 borrow,elastic 与 base 的值根据代码计算为 1 + 1 =2 , 98 + 1 * 98 / 1 = 196紧接着攻击者调用了函数 repay, 使 elastic 与 base 的值根据代码计算为 2 – 1 * 2/196 = 1, 196 – 1 = 195 ,此时 elastic 的计算就是攻击者利用的漏洞点我们在toELastic 和 toBase 函数中可以发现非常重要的一个位置,其计算过程中有一个向上取整的算法,这样就到导致了攻击者可以通过这个特性将 totla.elastic 的值始终保持为 1 并重复上一个借款行为将 totla.base 无限扩大,这里用一张图可以更好理解计算过程通过漏洞多次进行上述操作 将 base 变成非常庞大的数字,并在最后一次调用中额外 repay 一次将 total.elastic 再次变为 0攻击者完成这一切后任意抵押都可以通过 borrow 函数的 solvent 修饰符限制条件拥有借出大量 $MIM 的权限
// _totalBorrow.base 非常庞大
borrowPart.mul(_totalBorrow.elastic).mul(_exchangeRate) / _totalBorrow.base;
最后攻击者通过 borrow 借出合约中的所有 $MIM 所有代币,归还闪电贷完成攻击
作者
PeiQi
今天又是摸鱼的一天!
扫描关注公众号回复加群
和师傅们一起讨论研究~
长
按
关
注
WgpSec狼组安全团队
微信号:wgpsec
Twitter:@wgpsec
原文始发于微信公众号(WgpSec狼组安全团队):MIM SPELL – 借贷变量计算精度漏洞