价值3400万美元的项目灾难,竟然是因为一个单词?
4月23号,原本是一个平静的周六,一个3400万美元的消息震动了整个NFT圈子。
我们的办公室小哥原本还在忙着为疫情囤菜,不得不放下手里的抢菜软件,第一时间学习了技术分析。
简单来说,就是Akutar这个项目的基础代码出现了问题,导致总共3400万美元的ETH被永久锁定。
这场NFT界史无前例的灾难,迅速吸引了各方关注,很多媒体也cover了这次事件。
事件始末
Akutar是一个由著名棒球运动员Micha Johnson发起的项目,发行一系列梦想成为宇航员的戴着头盔的黑人小男孩。这个项目采用了和Azuki一样的荷兰式拍卖,从官网精致的画风到用心的项目描述,发布之初就收到了大部分人的认可。
其实早在这次事件之前,@RedBeadnDAO成员meows.eth就在推特上提示了Akutar合同之中的潜在风险。
同时@hasan在github上发布了一个POC,并且推文说到,“大家可能觉得我是想抹黑这个项目,但是这个合同中确实存在一个令人担忧的漏洞,并会有被人利用的可能”。
(用户Hasen创建的POC页面)
Hasen试图积极与Akutar团队建立联系,但双方只是讨论了一些恶意攻击的问题,并没有完全解决合同中存在的危险。
甚至呢,Hasen还被说成了FUD(FUD通常指对价格产生负面影响的新闻观点或声明,通常是没有依据的)
于是,在4月23日AkuDreams 3.5以太坊的荷兰式拍卖如期上线,此时人们还没有意识到灾难正在来临。
拍卖过程非常成功,但是在最终提款的步骤时出现了问题,11539.5个以太币被卡在合约里面无法被取出。
由于区块链智能合约具有不可篡改的特性,这个问题是无法修复的。这就导致了这价值3400万美元的11539.5个以太币永永远远被锁死在合约里面。
Akutar团队也第一时间承认了错误,并进行了弥补。但是这笔资金不可能拿出来了,这让人既震惊又难过。
作为这场灾难的结果,对“无根据的FUD”的恐惧已经成为现实。我们应该反省一下,为什么像这样用心的、且被大家所认可的项目往往带来如此糟糕的体验。
代码分析
事情出来第一时间,大家就审查了Akutar的合同代码,这里借用@meows.eth的“审查摘要”说明一下主要漏洞。
总结一下就是:
漏洞一:processRefunds() 会卡住;
漏洞二:出价计数没有随着铸币量正确增加漏洞;
漏洞三:取款需要出价计数正确累加,这最终导致资金永远卡住。
我们先看看项目基本情况,这是ETHERSCAN上的页面,大家眼睁睁看着11539.5个以太币无能为力,有没有觉得狠狠得心疼?
合约地址:0xF42c318dbfBaab0EEE040279C6a2588Fa01a961d
我们把合约代码复制到REMIX,折叠一些不重要的,拉到最后。
这3个校验的目的是在合约层面限制项目方的提款权限,通过三层校检使项目的可信度更高。
为什么我说这个检验的初心是非常好的,他要求所有没中标的用户退款完成之后,才进行提款功能,refundProgress >= totalBids ,从逻辑上是没问题的,提高了项目的可信程度,保证了用户的权益。
但为什么又会出现代币锁死而无法提取的情况呢?
原因就在于第2个校验refundProgress在实现时存在错误,无法达到预期的目标。
这里,refundProgress指处理的退款数量,即退款账户的数量,退款处理函数 processRefunds代码如下:
我们看到refundProgress的比较对象是bidIndex,这里的bidIndex指的是投标账户的总数,在bid函数中,每当有一个账户投标,bitIndex就会加1,且不会重复,代码如下:
以上这些看起来都没有问题,然而...
真正的问题出现在下面这个语句里:
在claimProjectFunds函数中,使用的是refundProgress >= totalBids,进行退款校验比较。
这里的totalBids不是投标账户的总数,而是所有用户总投标的NFT总数,如果1个账户只能投标1个NFT,该比较在数量上不会有问题。
但是显然这是不可能的,实际上在bid函数中,1个用户可以投标多个NFT。只要用一个用户投标1个以上的NFT,那totalBids > bitIndex。
所以在所有人完成退款之后,实际情况是:refundProgress == bitIndex < totalBids
实际拍卖结果refundProgress的数量是3669,而totalBids是5495
但大家还记得之前的提款要求吗?是refundProgress >= totalBids
我想说到这里完全不懂代码的朋友也发现问题了,这第二项代码检验refundProgress是不可能通过的,导致claimProjectFunds函数也不可能执行。
提款这个行为自然永远不可能成功,这3400万美元也就永远地锁在了里面。
这个totalBids,原本应该是bitIndex ,就是这一个单词的错误,引起了一个3400万美元的灾难。
沉痛反思
这是一个比较少见的,在宣发层面非常成功,但是代码拉跨的项目。
Akutar作为一个优质项目,其实团队还是非常负责的,后续处理也非常积极,没有摆烂。OP上稀有的Akutar甚至一度价格超过18e,大有起死回生的意思。
但实在太可惜了,项目方本可以规避这次风险:
一、在项目初期寻找专业的代码审计进行风险规避;
二、不要将安全研究人员的担忧视为没有根据的FUD。
所有从事区块链开发的人其实都明白,如果在这个行业太过谦逊,只会让自己失去机会。所以不管技术有没有到位,直接上手项目才是最好的选择。
而这就是问题的症结所在。
这也是为什么我们看到一些备受瞩目的项目一遍又一遍犯下那些“不可思议”的灾难性错误。
这是血淋淋的典型案例。所有开发者和区块链从业人员都应该深入研究这个漏洞的二阶后果,在之后的项目开发时更加完善自身的合约代码。
让投资者可以在更完善的审计和安全环境下,专注于项目本身的价值。
转载请在文章开头和结尾显眼处标注:作者、出处和链接。不按规范转载侵权必究。
未经授权严禁转载,授权事宜请联系作者本人,侵权必究。
本文禁止转载,侵权必究。
授权事宜请至数英微信公众号(ID: digitaling) 后台授权,侵权必究。
评论
评论
推荐评论
暂无评论哦,快来评论一下吧!
全部评论(0条)