價(jià)值3400萬美元的項(xiàng)目災(zāi)難,竟然是因?yàn)橐粋€(gè)單詞?
4月23號,原本是一個(gè)平靜的周六,一個(gè)3400萬美元的消息震動了整個(gè)NFT圈子。
我們的辦公室小哥原本還在忙著為疫情囤菜,不得不放下手里的搶菜軟件,第一時(shí)間學(xué)習(xí)了技術(shù)分析。
簡單來說,就是Akutar這個(gè)項(xiàng)目的基礎(chǔ)代碼出現(xiàn)了問題,導(dǎo)致總共3400萬美元的ETH被永久鎖定。
這場NFT界史無前例的災(zāi)難,迅速吸引了各方關(guān)注,很多媒體也cover了這次事件。
事件始末
Akutar是一個(gè)由著名棒球運(yùn)動員Micha Johnson發(fā)起的項(xiàng)目,發(fā)行一系列夢想成為宇航員的戴著頭盔的黑人小男孩。這個(gè)項(xiàng)目采用了和Azuki一樣的荷蘭式拍賣,從官網(wǎng)精致的畫風(fēng)到用心的項(xiàng)目描述,發(fā)布之初就收到了大部分人的認(rèn)可。
其實(shí)早在這次事件之前,@RedBeadnDAO成員meows.eth就在推特上提示了Akutar合同之中的潛在風(fēng)險(xiǎn)。
同時(shí)@hasan在github上發(fā)布了一個(gè)POC,并且推文說到,“大家可能覺得我是想抹黑這個(gè)項(xiàng)目,但是這個(gè)合同中確實(shí)存在一個(gè)令人擔(dān)憂的漏洞,并會有被人利用的可能”。
(用戶Hasen創(chuàng)建的POC頁面)
Hasen試圖積極與Akutar團(tuán)隊(duì)建立聯(lián)系,但雙方只是討論了一些惡意攻擊的問題,并沒有完全解決合同中存在的危險(xiǎn)。
甚至呢,Hasen還被說成了FUD(FUD通常指對價(jià)格產(chǎn)生負(fù)面影響的新聞觀點(diǎn)或聲明,通常是沒有依據(jù)的)
于是,在4月23日AkuDreams 3.5以太坊的荷蘭式拍賣如期上線,此時(shí)人們還沒有意識到災(zāi)難正在來臨。
拍賣過程非常成功,但是在最終提款的步驟時(shí)出現(xiàn)了問題,11539.5個(gè)以太幣被卡在合約里面無法被取出。
由于區(qū)塊鏈智能合約具有不可篡改的特性,這個(gè)問題是無法修復(fù)的。這就導(dǎo)致了這價(jià)值3400萬美元的11539.5個(gè)以太幣永永遠(yuǎn)遠(yuǎn)被鎖死在合約里面。
Akutar團(tuán)隊(duì)也第一時(shí)間承認(rèn)了錯誤,并進(jìn)行了彌補(bǔ)。但是這筆資金不可能拿出來了,這讓人既震驚又難過。
作為這場災(zāi)難的結(jié)果,對“無根據(jù)的FUD”的恐懼已經(jīng)成為現(xiàn)實(shí)。我們應(yīng)該反省一下,為什么像這樣用心的、且被大家所認(rèn)可的項(xiàng)目往往帶來如此糟糕的體驗(yàn)。
代碼分析
事情出來第一時(shí)間,大家就審查了Akutar的合同代碼,這里借用@meows.eth的“審查摘要”說明一下主要漏洞。
總結(jié)一下就是:
漏洞一:processRefunds() 會卡住;
漏洞二:出價(jià)計(jì)數(shù)沒有隨著鑄幣量正確增加漏洞;
漏洞三:取款需要出價(jià)計(jì)數(shù)正確累加,這最終導(dǎo)致資金永遠(yuǎn)卡住。
我們先看看項(xiàng)目基本情況,這是ETHERSCAN上的頁面,大家眼睜睜看著11539.5個(gè)以太幣無能為力,有沒有覺得狠狠得心疼?
合約地址:0xF42c318dbfBaab0EEE040279C6a2588Fa01a961d
我們把合約代碼復(fù)制到REMIX,折疊一些不重要的,拉到最后。
這3個(gè)校驗(yàn)的目的是在合約層面限制項(xiàng)目方的提款權(quán)限,通過三層校檢使項(xiàng)目的可信度更高。
為什么我說這個(gè)檢驗(yàn)的初心是非常好的,他要求所有沒中標(biāo)的用戶退款完成之后,才進(jìn)行提款功能,refundProgress >= totalBids ,從邏輯上是沒問題的,提高了項(xiàng)目的可信程度,保證了用戶的權(quán)益。
但為什么又會出現(xiàn)代幣鎖死而無法提取的情況呢?
原因就在于第2個(gè)校驗(yàn)refundProgress在實(shí)現(xiàn)時(shí)存在錯誤,無法達(dá)到預(yù)期的目標(biāo)。
這里,refundProgress指處理的退款數(shù)量,即退款賬戶的數(shù)量,退款處理函數(shù) processRefunds代碼如下:
我們看到refundProgress的比較對象是bidIndex,這里的bidIndex指的是投標(biāo)賬戶的總數(shù),在bid函數(shù)中,每當(dāng)有一個(gè)賬戶投標(biāo),bitIndex就會加1,且不會重復(fù),代碼如下:
以上這些看起來都沒有問題,然而...
真正的問題出現(xiàn)在下面這個(gè)語句里:
在claimProjectFunds函數(shù)中,使用的是refundProgress >= totalBids,進(jìn)行退款校驗(yàn)比較。
這里的totalBids不是投標(biāo)賬戶的總數(shù),而是所有用戶總投標(biāo)的NFT總數(shù),如果1個(gè)賬戶只能投標(biāo)1個(gè)NFT,該比較在數(shù)量上不會有問題。
但是顯然這是不可能的,實(shí)際上在bid函數(shù)中,1個(gè)用戶可以投標(biāo)多個(gè)NFT。只要用一個(gè)用戶投標(biāo)1個(gè)以上的NFT,那totalBids > bitIndex。
所以在所有人完成退款之后,實(shí)際情況是:refundProgress == bitIndex < totalBids
實(shí)際拍賣結(jié)果refundProgress的數(shù)量是3669,而totalBids是5495
但大家還記得之前的提款要求嗎?是refundProgress >= totalBids
我想說到這里完全不懂代碼的朋友也發(fā)現(xiàn)問題了,這第二項(xiàng)代碼檢驗(yàn)refundProgress是不可能通過的,導(dǎo)致claimProjectFunds函數(shù)也不可能執(zhí)行。
提款這個(gè)行為自然永遠(yuǎn)不可能成功,這3400萬美元也就永遠(yuǎn)地鎖在了里面。
這個(gè)totalBids,原本應(yīng)該是bitIndex ,就是這一個(gè)單詞的錯誤,引起了一個(gè)3400萬美元的災(zāi)難。
沉痛反思
這是一個(gè)比較少見的,在宣發(fā)層面非常成功,但是代碼拉跨的項(xiàng)目。
Akutar作為一個(gè)優(yōu)質(zhì)項(xiàng)目,其實(shí)團(tuán)隊(duì)還是非常負(fù)責(zé)的,后續(xù)處理也非常積極,沒有擺爛。OP上稀有的Akutar甚至一度價(jià)格超過18e,大有起死回生的意思。
但實(shí)在太可惜了,項(xiàng)目方本可以規(guī)避這次風(fēng)險(xiǎn):
一、在項(xiàng)目初期尋找專業(yè)的代碼審計(jì)進(jìn)行風(fēng)險(xiǎn)規(guī)避;
二、不要將安全研究人員的擔(dān)憂視為沒有根據(jù)的FUD。
所有從事區(qū)塊鏈開發(fā)的人其實(shí)都明白,如果在這個(gè)行業(yè)太過謙遜,只會讓自己失去機(jī)會。所以不管技術(shù)有沒有到位,直接上手項(xiàng)目才是最好的選擇。
而這就是問題的癥結(jié)所在。
這也是為什么我們看到一些備受矚目的項(xiàng)目一遍又一遍犯下那些“不可思議”的災(zāi)難性錯誤。
這是血淋淋的典型案例。所有開發(fā)者和區(qū)塊鏈從業(yè)人員都應(yīng)該深入研究這個(gè)漏洞的二階后果,在之后的項(xiàng)目開發(fā)時(shí)更加完善自身的合約代碼。
讓投資者可以在更完善的審計(jì)和安全環(huán)境下,專注于項(xiàng)目本身的價(jià)值。
轉(zhuǎn)載請?jiān)谖恼麻_頭和結(jié)尾顯眼處標(biāo)注:作者、出處和鏈接。不按規(guī)范轉(zhuǎn)載侵權(quán)必究。
未經(jīng)授權(quán)嚴(yán)禁轉(zhuǎn)載,授權(quán)事宜請聯(lián)系作者本人,侵權(quán)必究。
本文禁止轉(zhuǎn)載,侵權(quán)必究。
授權(quán)事宜請至數(shù)英微信公眾號(ID: digitaling) 后臺授權(quán),侵權(quán)必究。
評論
評論
推薦評論
暫無評論哦,快來評論一下吧!
全部評論(0條)