『冰封』合約背後的老牌勁敵|鏈安團隊漏洞分析連載第二期——拒絕服務漏洞

針對區塊鏈安全問題,鏈安科技團隊每一週都將出智能合約安全漏洞解析連載,希望能幫助程序員寫出更加安全牢固的合約,防患於未然。

引子:秦人不暇自哀,而後人哀之;後人哀之而不鑑之,亦使後人而復哀後人也。—— 《阿房宮賦》

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

上回講到 溢出漏洞引增發,幣值一落千萬丈,黑客造假本領大,SafeMath來救駕。

眼觀目前鏈圈幣圈行進的步伐越來越急促,似乎我們已無暇回首當初那些輝煌與挫敗,只能低著頭繼續跟從與追趕。回首2016年的戰場,似乎一切都已冰封,少有人記得這裡發生過什麼。

我們將當時的拒絕服務攻擊事件挖掘出來,並將原理分析和漏洞修復技巧與大家分享,時刻牢記過去的教訓。

事件回顧

2016年2月6日至8日The King of the Ether Throne(以下簡稱KotET)“紛爭時代”(Turbulent Age)期間,許多遊戲中的退位君王的補償和未接受款項無法退回用戶玩家的錢包[1]

具有諷刺意味的是同年6月,連龐氏騙局GovernMental的合約也遭遇DoS攻擊,當時1100以太幣是通過使用250萬gas交易獲得[2],這筆交易超出了合約能負荷的gas上限,帶來交易活動的暫停。

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

無論是蓄意破壞交易正常流程還是阻塞交易通道,都用到了一個互聯網時代已經盛行已久的攻擊方式——DoS,也就是我們所說的拒絕服務攻擊。這種攻擊方式可以讓合約執行的正常的交易操作被擾亂,中止,凍結,更嚴重的是讓合約本身的邏輯無法運行。

何為DoS

DoS 是DenialOfService,拒絕服務的縮寫[3],從字面上來理解,就是用戶所需要的服務請求無法被系統處理。

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

打個比方來形容DoS,火車站是為大家提供乘車服務的,如果想要DoS火車站的話,方法有很多,可以佔用過道不上車,堵住售票點不付錢,阻撓列車員或者司機不讓開車,甚至用破壞鐵軌等更加極端的手段來影響車站服務的正常運營。

過去針對互聯網的DoS有很多種方法,但基本分為三大類:利用軟件實現的缺陷,利用協議的漏洞,利用資源壓制[3]。

此外還有DDoS,稱為分佈式DoS,其區別就是攻擊者利用遠程操控的計算機同時向目標發起進攻,在上面的比喻中可以理解為僱傭了幾百個地痞流氓來做同樣的事影響車站的運作。

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

智能合約DoS攻擊原理分析及相應漏洞修復

無處不在的DoS當然也會對基於Solidity語言的以太坊合約產生威脅。

針對智能合約的DoS攻擊屬於利用協議漏洞進行的手段,具體的攻擊方法有三種[4],其目的是使合約在一段時間或者永久無法正常運行。通過DoS攻擊,可以使合約中的Ether永遠無法提取出來,區塊成為“冰凍廢土”。

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

在對於原始代碼進行分析後,我們發現KotET事件中對君王稱號進行鎖定的DoS攻擊屬於:

1.通過(Unexpected) Revert發動DoS

如果智能合約的狀態改變依賴於外部函數執行的結果,又未對執行一直失敗的情況做出防護,那麼該智能合約就可能遭受DOS攻擊[5]。

我們使用案例合約還原KotET的競拍機制,進行模擬分析:

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

以上案列合約是一個簡化版的KotET的競拍爭奪王位的合約,如果當前交易的攜帶的ether大於目前highestBid,那麼highestBid所對應的ether就退回給currentLeader,然後設置當前競拍者為currentLeader,currentLeader改為msg.value。但是當惡意攻擊者部署如下圖所示合約,並通過合約來競拍將會出現問題:

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

攻擊者先通過攻擊合約向案例合約轉賬成為currentLeader,然後新的bider競標的時候,執行到require(currentLeader.send(highestBid))會因為攻擊合約的fallback函數(這裡指functionexternal payable函數)無法接收ether而一直為false,最後攻擊合約以較低的ether贏得競標。

漏洞修復

如果需要對外部函數調用的結果進行處理才能進入新的狀態,請考慮外部調用可能一直失敗的情況,也可以添加基於時間的操作,防止外部函數調用一直無法滿足require判斷。

對GovernMental事件中交易的gas值遠遠超出天際的原理分析,其屬於通過區塊Gas Limit發動DoS。

2. 通過區塊Gas Limit發動DoS

一次性向所有人轉賬,很可能會導致達到以太坊區塊gas limit的上限。以太坊規定了每一個區塊所能花費的gas limit,如果超過交易便會失敗。

即使沒有故意的攻擊,這也可能導致問題。然而,最為糟糕的是如果gas的花費被攻擊者操控。在先前的例子中,如果攻擊者增加一部分收款名單,並設置每一個收款地址都接收少量的退款。這樣一來,更多的gas將會被花費從而導致達到區塊gas limit的上限,整個轉賬的操作也會以失敗告終。如以下簡化版案例合約所示:

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

這個案例合約遍歷可被人為操縱的investors數組。攻擊者可以創建許多賬戶,使得investors數組變的很大,使得執行for循環所消耗的gas超過塊gas極限,使得distribute函數一直處於out-of-gas(OOG)狀態,而一直無法執行成功,合約正常功能實現受到影響。

漏洞修復

合約不應該循環對可以被外部用戶人為操縱的數據結構進行批量操作,建議使用取回模式而不是發送模式,每個投資者可以使用withdrawFunds取回自己應得的代幣;

如果實在必須通過遍歷一個變長數組來進行轉賬,最好估計完成它們大概需要多少個區塊以及多少筆交易。然後你還必須能夠追蹤得到當前進行到哪以便當操作失敗時從那裡開始恢復,舉個例子:

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

3.所有者操作發動DoS

另外, 我們聯繫之前提到的Owner權限過大,“超中心化”的問題,發現目前很多代幣合約都有一個Owner賬戶,其擁有開啟/暫停交易的權限,如果對owner保管不善,代幣合約可能被一直凍結交易,導致非主觀的拒絕服務攻擊,例如如下owner權限中的功能:

此owner權限的侷限性在於,在ICO結束後,如果特權用戶丟失其私鑰或變為非活動狀態,Owner無法調用finalize,用戶則一直不可以發送代幣,即令牌生態系統的整個操作取決於一個地址。

漏洞修復

可以設置多個擁有owner權限的地址,或者設置暫停交易的期限,超過期限就可以恢復交易,如:require(msg.sender == owner || now > unlockTime)

‘冰封’合约背后的老牌劲敌|链安团队漏洞分析连载第二期——拒绝服务漏洞

以銅為鏡,可以正衣冠;以古為鏡,可以知興替;以人為鏡,可以明得失

1.對於調用外部函數的代碼一定要考慮周全,對於例外情況的判定要加入代碼中。

2.遍歷變長數組來逐個支付的方法需要全方位考慮和估計。合約中不應存在外部人員操縱的成分。

3.強調再三的去中心化特徵也應該應用到Owner權限這個概念上來。

從被DoS到交易系統異常,到項目被冰封直至被遺忘,以上的例子也經歷了互聯網發展初期所遭受的苦難,但是隻要我們銘記教訓,就能穩固地保持區塊鏈技術的發展。

引用:

1.Post-Mortem Investigation https://www.kingoftheether.com/postmortem.html

2.A survey of attacks on Ethereum smart contract https://eprint.iacr.org/2016/1007.pdf

3.張昆蒼等.操作系統原理 DOS 篇(第2版):清華大學出版社,2000 年9月

4.https://blog.sigmaprime.io/solidity-security.html#dos

5.以太坊智能合約 --- 最佳安全開發指南 通過(Unexpected)Throw發動DoS

6.以太坊智能合約 --- 最佳安全開發指南 通過區塊GasLimit發動DoS


分享到:


相關文章: