




原文标题:《 2 亿美金损失,Euler Finance 黑客攻击溯源 》
原文作者:0xNorman
本篇文章主要对 2023.3.13 日发生的 Euler Finance 被攻击事件进行分析和溯源。希望对项目方,投资者,安全工程师以及整个区块链行业起到警示和反思的作用。
造成 Euler Finance 被攻击的关键因素在于健康分数(healthScore)这一变量上。这是用来衡量用户资产健康水平的一个变量。在一般的 transferFrom()函数方程里,这个变量会被用作限制以防坏账。但是在eIP-14引入的 donateToReserves() 函数里,并没有这样的限制。这意味着用户可以随意给 Euler 捐款,并且使自己的账户产生坏账。
此外,Euler 的清算过程包括清算折扣 (liquidation discount)。当清算人对一个资不抵债的账户进行清算时,会根据该账户的健康评分进行折扣。健康分数越低,折扣就越大。
如果资不抵债情况严重,那么清算者就可能在不支付任何债务的情况下得到抵押品。
溯源在Etoken.donateToReserves()缺少健康分数审核,导致用户可以造成资不抵债的情况。
在liquidate()里用健康评分来作清算折扣的设计使得任何人都可以对资不抵债的账户清算,并且在不偿还债务的情况下得到抵押品并转换成现金。
攻击者的交易细节可以在Etherscan上查看,以下是还原。
第一步:制造一个资不抵债的账户
将 2 千万 DAI 存为 eDAI
用 2 千万 eDAI 作为抵押,借出 2 亿 eDAI
偿还 1 千万 DAI(用来提高健康分数并且再次借款)
再借出 2 亿 eDAI
捐赠 1 亿 eDAI,这样资产和债务就分别是 3.2 亿 eDAI 以及 3.9 亿 dDAI.
攻击者在这里先是创造一个拥有巨大抵押和欠债的账户,抵押是 4.2 亿 eDAI(存入了 2 千万,借了两次 2 亿),欠债是 3.9 亿 dDAI(借了 4 亿,还了 1 千万)。
然后攻击者捐了 1 亿 eDAI 出去,导致了 7 千万的坏账(3.2 亿 eDAI-3.9 亿 dDAI),目前账户是资不抵债的状态。
第二步:清算该账户
调用 Liquidation.liquidate() 函数
RiskManager.computeLiquidity() 被调用来计算清算折扣
由于破产账户深陷债务,有效清算折扣为 20%。
通过承担 2.54 亿的 dDAI 债务,清算者得到 3.17 亿的 eDAI(2.54/3.17==0.8)。
清算者提取了 3890 万 eDAI(能提取的最大金额),并未偿还债务。
通过清算,破产账户的抵押和负债就转移到了清算者账户里,但是负债打了折扣,而抵押却没有。如此一来七千万的坏账就变成了六千万的利润。当然,是以 Euler finance 的损失为代价的。
攻击者用其他类型的代币发起了几次相同的攻击,最终使得 Euler finance 损失惨重。
这次的攻击主要是因为捐赠函数在设计上没有考虑到健康分数,让攻击者有机可乘制造了坏账账户,还给负债打了友情价。可谓是一笔打赏打垮了 Euler finance 系统。
从去中心化协议设计角度来说,在引入新的代码和商业逻辑时就应该考虑到与之前的代码的契合度,否则仅是看似无害的捐款也能变成高危漏洞。
从安全的角度来说,新引入的代码被 Sherlock 平台最顶尖的几位安全工程师审计过。但审计不代表没有漏洞,即使是最厉害的专家也不例外。因此,笔者建议项目方在开发和升级项目的时候与安全审计公司一直保持合作,同时监控合约有无异常行为。如果能设置常态的漏洞赏金则更好。多一双眼睛,就多一份安全。
Make this world a better place by one commit each time
原文链接