0x01:前言
援引官方消息,北京时间12月19日,Fantom链上复合收益平台GrimFinance遭遇了闪电贷攻击。知道创宇区块链安全实验室第一时间对本次事件深入跟踪并进行分析。
0x02:事件详情
交易细节如下图所示:
浏览上图的交易过程可知,攻击合约利用闪电贷借取代币WFTM和BTC,将借取的代币与自己铸造的代币质押到SpiritSwap里增加流动性获取lp代币,而问题就出现在攻击者通过depositFor()实现质押的过程中。
通过Tenderly调试该笔交易,攻击者多次递归调用depositFor函数,利用该函数获取大量代币:
美国纽约联邦法官驳回以太坊开发者Virgil Griffith的动议:此前,美国纽约南区美国检察官办公室和联邦调查局宣布,已逮捕并指控以太坊开发者Virgil Griffith违反美国制裁法。罪名是联邦政府指控他于4月非法前往朝鲜,并在“平壤区块链和加密货币会议”上作了陈述。对此,Griffith在其动议中声称,他在“平壤区块链和加密货币会议”上发表的讲话受到言论自由权保护。并且,针对他的四页起诉书“简短而含糊”,并且缺乏概述其犯罪行为的具体细节。法官驳回此动议,认为已提供对Griffith的指控的充分告知。(Cointelegraph)[2021/1/29 14:17:46]
Grin矿机已投入使用,当前全网算力22378 Gps:隐私币项目Grin的前核心开发者Gary近日在论坛表示,借到了一台Grin的Asic矿机并进行了运行测试。在不到24小时的时间里挖出了3个区块。
Gary对矿机的外观进行了描述,类似于其他Asic矿机,Grin矿机尺寸大概是44cm x20cm x35cm,箱重约20公斤。Gary将矿机连接到一个grin节点来尝试进行挖矿,在不到24小时后,他挖出了3个区块(819660、820461、820801),出块奖励共计180枚Grin。不过Gary表示,因为在家中挖矿为了控制噪音,并未把散热风扇调整到最大,因此矿机挖矿效率或可以更高。(BlockBeats)[2020/8/11]
0x03:漏洞分析
depositFor()函数位于的第1115行:
外媒:18个月之内 很少有人使用、开采或购买隐私币Grin:据Coindesk文章分析称,尽管在2019年初大张旗鼓地推出,但古灵币(隐私币Grin)并未显示出生命迹象。?在问世之初,专业投资者投入了大量资金(据估计有1亿美元)来开采这种加密货币,有些人甚至将其称为“比特币2.0”。?但是链上数据表明,投资者对这个年轻的加密货币感到失望。Grin的哈希能力和采矿难度在2019年8月开始崩溃,在连续9个月下降之后,这种趋势没有逆转的迹象。[2020/5/18]
function?depositFor(address?token,?uint?_amount,address?user?)?public?{
?uint256?_pool?=?balance();
?IERC20(token).safeTransferFrom(msg.sender,?address(this),?_amount);
动态 | Grin开发者David Burkett更新莱特币MimbleWimble 12月份开发进展:由莱特币基金会资助的GRIN开发者David Burkett发文更新莱特币MimbleWimble 12月份的开发进展。其表示,经过数月的规划,MimbleWimble扩展区块的开发已正式开始。此外,本月的工作主要集中在重组将在Grin ++和LTC之间共享的core logic上,这涉及所有logging、序列化、加密、错误处理和通用数据结构等。
另外,明年1月份的优先事项为:1.确定构建方法;2.定义所有LTC模型,包括确定headers & kernels(包括签名)的确切字段和序列化格式;3.将数据库实现移至libmw-core,完成清理并匹配新标准,并添加完整的测试。此外,还将在下个月为Grin开发一种更快的同步机制,LTC将直接从中受益。[2019/12/30]
?earn();
动态 | 鱼池顺利挖出Grin的第一个区块 目前交易所价格虚高:神鱼微博表示,鱼池顺利挖出Grin的第一个区块 ,目前交易所价格虚高,买一 1Btc/个。[2019/1/16]
?uint256?_after?=?balance();
?_amount?=?_after.sub(_pool);?//?Additional?check?for?deflationary?tokens
?uint256?shares?=?0;
?if?(totalSupply()?==?0)?{
??shares?=?_amount;
?}?else?{
??shares?=?(_amount.mul(totalSupply())).div(_pool);
?}
?_mint(user,?shares);
}
该函数的safeTransferFrom()方法从IERC20(token)调用,调用完该方法后,余额balance也会随之变动,最后通过_mint()方法向用户添加质押凭证代币。其中调用的变量token可控,导致攻击者可以自己实现safeTransferFrom()方法,将该方法重入到depositFor()发起攻击。
以实施了5次重入攻击为例,开始_pool的值为0,在重入depositFor方法的前四次里,攻击者一直传入自己铸造的代币,_pool的值会一直保持为0,但在第五次,也就是最后一次传入100个受认可的代币时,_after的值会变成100,而_afer-_pool的差值_amount也就是100,最后由于重入了5次,导致合约会向攻击者铸造100*5的质押凭证代币。
其后果就是攻击者向该合约质押自己铸造不受认可的代币,同样会增加质押总量,最后利用多出来的质押凭证实现套利。
0x04:修复方案
1.由于depositFor()方法里的token可控才是导致这次攻击事件的原因,因此只需要在传递参数的时候让token不可控就行:
function?depositFor(?uint?_amount,address?user?)?public
2.由于套利的原因是depositFor()方法里存在修改代币数量的函数,因此还可以将修改代币的方法单独实现,这样即使token变量可控,也无法成功套利:
function?depositFor(address?token,?uint?_amount,address?user?)?public?{
?IERC20(token).safeTransferFrom(msg.sender,?address(this),?_amount);
}
3.锁定交易token:
function?setLPToken(address?lp)?public?onlyOwner?{
lpToken?=?lp;
}
function?depositFor(uint?_amount,address?user?)?public?{
uint256?_pool?=?balance();
IERC20(lpToken).safeTransferFrom(msg.sender,?address(this),?_amount);
earn();
......
}
0x05:总结
经过完整分析,知道创宇区块链安全实验室明确了该次攻击事件的源头并非网传的闪电贷攻击,攻击者利用GrimBoostVault合约的depositFor方法参数可控,实施了重入攻击,将自己的铸造的无价值代币兑换成了质押凭证,最后通过withdrawAll方法实现套利,而闪电贷?攻击者只是利用闪电贷扩大了套利值。
对于合约代码而言安全性是十分重要的,每一个未经验证的传入参数都可能导致巨大的经济损失,开发者在编写重要操作方法时,须记住零信任原则,谨慎对待每一个传入参数。
来源:金色财经
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。