CoinEx中文官方
CoinEx中文官方

CoinEx成立於2017年12月,是一家面向全球的專業數字資產交易服務商。聚集創新數字資產為核心,多年來良好的專案服務水準及優質資產篩選能力,為全球用戶提供全面且優質的投資選擇。 CoinEx中文繁體群:https://t.me/CoinExGlobalChinese

深入淺出智能合約常見漏洞與攻擊

以太坊有兩個常見的帳戶類型:分別是外部擁有帳戶(EOA)智慧合約帳戶(SCA)。

EOA非常類似於我們常用的電子金融帳戶,都用於存放著資金以及和各種不同的應用交互,例如用戶透過Paypal存放法幣,同時可以和各種網站、商城、APP交互並完成付款。 而Defi礦工常見的操作也是透過自己的EOA帳戶存放各種數位貨幣,透過和一些Defi Dapps交互,將資金放入Dapps賺取收益;但EOA也擁有電子金融帳戶所不具備的特性,就是用戶必須 透過私鑰的所有權來驗證其對EOA的控制,not your keys not your coins。

SCA也是一個帳戶,它本質上是和一段可執行的字節碼(也就是Smart Contract)關聯在一起,Smart Contract描述的是各種各樣的業務邏輯,它也成為Dapps的後端。 但也由於Smart Contract準圖靈完備的自由度(相對傳統圖靈完備的開發語言來說,限制比較多),很多大大小小的漏洞以及隨之而來的攻擊,不斷給區塊鏈產業造成 創傷。

常見的智能合約攻擊

1. 重入攻擊

重入攻擊是最常見也是最名聲在外的攻擊方式,它是以太坊分叉出以太坊經典的罪魁禍首——2016年黑客通過對The DAO 合約的重入攻擊,盜走3,600,000 枚ETH,當時價值 超過$150M。 由於彼時以太坊還在生態早期,這波攻擊對以太坊造成非常嚴重的破壞,投資者的信任也被擊碎,進而產生了分叉。

具體邏輯

在此,我們舉個例子讓大家更深入理解重入攻擊的原理。 B銀行之前借了一部分錢給A銀行,這一天B銀行向A銀行發起轉賬,要求轉移所有的錢回到B銀行。 正常情況下的路徑如下:

B銀行請求提領資金→A銀行將資金轉帳至B銀行→A銀行向B銀行確認轉帳成功→A銀行更新B銀行的帳戶餘額。

然而如果B銀行在第2步操作後埋了個個坑,在第3步未確認的前提下繼續請求從A銀行提取所有錢,由於第3步未確認的前提下,B銀行在A銀行的 帳戶餘額始終不變,這種循環呼叫將把A銀行的資產全部搬空。

相關智能合約

A銀行合約包含2個函數:

●deposit():存款函數,將錢存入A銀行,並更新使用者的餘額;

●withdraw():提款函數,使用者提取所有在A銀行的資金。

B銀行的攻擊合約主要是透過1次存款→1次提款→觸發receive()這種callback函數循環呼叫提款掏空A銀行資產→最後更新B在A銀行的餘額,其中包含2個函數:

●receive(): callback函數,在接收ETH時被觸發,並循環呼叫Bank合約的withdraw()函數提款;

●attack():先呼叫Bank合約的deposit()函數存款刷新餘額,然後呼叫withdraw()方法發起第一次提款,之後觸發receive()這種callback函數循環呼叫withdraw()提款,將Bank 合約的資產提空。

解決方法

設定重入鎖

重入鎖是一種防重入的修飾器(modifier),目的就是確保一次調用必須完整執行完畢,才可以再次調用,例如B銀行的攻擊方法需要多次調用Bank合約的withdraw()方法,他 的攻擊就會完全失敗。

使用方式

2. tx.origin誤用

tx.origin在Smart Contract 中主要作用是去獲取啟動Smart Contract交易的最初帳戶。 這裡我們主要來探討Smart Contract中兩個常見的變數:msg.sender以及tx.origin。 msg.sender取得的是直接呼叫Smart Contract的帳戶;而在區塊鏈世界裡,因為不同的Smart Contract可以層層嵌套、互相呼叫(例如Defi樂高),這樣就需要透過tx.origin去取得啟動 交易的最初帳戶。 這裡一個漏洞攻擊就是來自Dapp開發者在程式碼中只去驗證tx.origin的安全性,忽略了攻擊者部署中間合約進而跳過tx.origin的安全性驗證,發動攻擊。

具體邏輯

在此,我們也舉個例子讓大家更深入了解常見的攻擊場景。 Bill有智慧錢包,每次Bill轉帳的時候,智慧錢包都會驗證轉帳的發起人是不是Bill本人。 有一次Bill在一個釣魚網站上面Mint一個NFT,這個Mint動作導致釣魚網站獲取到了Bill本人身份信息,並通過Bill本人身份信息在Bill的智能錢包發起轉賬,掏空資產。 正常情況下,一般不會上當,但是當用戶用錢包進行Dapp交互時,往往會忽略對交互彈窗的檢查,比如都是Mint() 方法,稍不注意就會落入釣魚陷阱中。 釣魚網站裡面的業務邏輯佈滿各種陷阱,平時互動使也需注意檢查交互彈窗是否有誤。

智慧錢包合約

智慧錢包合約包含1個函數:

●transfer():提款函數,只能是錢包owner才能發起提款,這裡owner就是Bill。

釣魚攻擊合約

透過釣魚方法Mint()誘導用戶轉帳給駭客地址,這裡包含1個函數:

●Mint(): 釣魚方法,誘導使用者呼叫此方法後,內部再執行Wallet合約的transfer()方法,由於最初的發起人就是使用者(這裡範例是Bill)本身,所以require(tx.origin == owner , "Not owner");這裡的驗證將會通過,但轉帳的目標地址早已篡改成駭客地址,所以資金被竊取。

解決方法

1.使用msg.sender代替tx.origin

這裡不管中間涉及多少個合約呼叫(A合約→B合約→…→目標合約),只管對msg.sender做驗證,也就是對直接呼叫者做驗證,這樣就可以避免攻擊合約混入中間造成的攻擊。

2.tx.origin == msg.sender 驗證

此方法可以避免攻擊合約混入中間,但是開發者需要結合自身業務需求,看是否做這樣的驗證,因為這樣的驗證方式也等於隔絕了所有其他外部合約的調用。

3. 隨機數字攻擊

這個不得不追溯到2018-2019年的賭博或者博彩類Dapps熱潮,一般開發者都會選用Smart Contract中一些種子去生成隨機數,用於開獎時候選擇獲勝者,常見的種子有block.number,block. timestamp,blockhash,keccak256。 但是這些種子可由礦工完全控制,惡意礦工可以操縱變數以成為最終獲勝者。

常見Dice合約

Dice合約包含1個函數:

●Bet():下注函數,使用者輸入下注數字,並支付一個ETH,透過多個種子產生隨機數,如果下注數字等於隨機數,則贏得整個獎金池的資金。

礦工的攻擊合約

礦工只要事先計算相同的獲勝隨機數,並在同一個區塊執行,即可獲勝,其中包含1個函數:

●attack(): 下注攻擊函數,礦工提前計算出獲勝隨機數,由於在同一個區塊執行,所以blockhash(block.number - 1)與block.timestamp是一致的,隨後調用Dice合約的Bet( )方法,完成攻擊;

解決方法

使用預言機項目提供的鏈下隨機數

透過使用Chainlink等預言機專案的服務,將鏈上隨機數注入到鏈上合約中,確保隨機性以及安全性。 然而,預言機也會有中心化風險,因此需要更成熟的預言機服務。

4. 重施攻擊

重施攻擊是利用已經使用過的簽章重新發動交易,進而竊取資金。 近幾年最著名的重播攻擊,莫過於Optimism的做市商Wintermute被盜20M的$OP代幣這個事件,對應的攻擊方式屬於跨鏈重播攻擊。 攻擊者利用Wintermute在以太坊部署多簽地址這筆交易的簽名,在Optimism鏈重新執行了相同的交易,進而獲取了Optimism鏈上多簽錢包帳戶的控制權,本質還是因為Wintermute多簽錢包帳戶暫時 只部署在以太坊主網路上。 多簽錢包帳戶本質上也是一個SCA,這也提現了SCA和EOA的一個顯著差別,對於EOA來說,正常用戶只用一把私鑰就可以控制以太坊以及EVM兼容鏈上所有地址(地址字符 串完全一致),而SCA一次部署只能在一條鏈上生效。

具體邏輯

這裡我們舉一個普通重播攻擊(同鏈重播攻擊)的例子。 Bill有個智慧錢包,每次轉帳前必須先錄入自己的電子簽名,才能執行轉帳;此時駭客Lucy盜取了Bill的電子簽名,無限發起轉帳掏空Bill的智慧錢包。

漏洞合約實例

漏洞合約包含3個函數:

●checkSig():ECDSA驗證函數,保證驗證結果是原先設定的signer;

●getMsgHash():產生hash的函數,將to和amount組成hash;

●transfer():轉帳函數,用戶提取資金池的資金,這邊由於未對簽名進行限制,導致同樣的簽名可以復用,黑客獲取到後可以不斷竊取資金。

解決方法

將nonce放入簽章組合中,這樣可以防止重施攻擊,加入該參數的原理:

●nonce:描述EOA在區塊鏈網路中交易數的變量,具有順序和唯一性,每增加一筆交易,nonce值就會加1,且區塊鏈網路會檢查該交易的nonce與帳戶當前的 nonce是否一致,所以一旦駭客利用已經使用過的簽名,將會失敗,因為該簽名組合中的nonce值會小於目前EOA的nonce值;

5. 拒絕服務攻擊

傳統Web2世界中就存在拒絕服務攻擊即DoS攻擊,全稱為Denial of Service,任何對伺服器的干涉例如發送大量垃圾訊息或乾擾訊息,導致其可用性降低或失去可用性的行為均稱為拒絕服務。 而在智能合約中,也存在這類攻擊,本質就是讓智能合約無法正常運作。

具體邏輯

在此,我們繼續舉例讓大家更深入了解常見的攻擊場景。 A專案方舉行協議代幣公募,所有用戶都可以往資金池(Smart Contract)中打入資金以購買額度,先到先得,最終超出公募的部分將會返還給參與者。 駭客Alice利用攻擊合約參與公募,一旦資金池返還資金給到Alice的攻擊合約,就會觸發攻擊合約的DoS攻擊,導致返還的動作永遠無法實現,最終結果就是大批量資金鎖在智能合約中。

公募合約實例

公募合約包含2個函數:

●deposit():存款函數,記錄存款人的地址和參與金額;

●refund():退款函數,專案方將資金回饋給投資者。

DoS攻擊合約

DoS攻擊合約包含1個函數:

●attack(): 攻擊函數,雖然為攻擊函數,但是方法本身並沒有任何問題,主要是Hacker 合約本身內置的receive()收款回調方法中,加入了異常判定,只要有外部合約往Hacker 合約轉賬 ,就會透過revert()方法拋出異常,進而導致操作無法完成;

解決方法

1.涉及外部合約呼叫時避免重要功能卡死

上述PublicSale合約的refund()方法中,可以把require(success, "Refund Fail!"); 去掉,這樣可以保證單一地址退款失敗時整個退款仍能運作。

2.方法解耦

上述PublicSale合約的refund()方法,可以讓使用者自行領取,而非專案方主動發放,盡量減少潛在和外部合約不必要的互動。

6.permit攻擊

permit 攻擊具體邏輯是A帳戶提前給授權對象簽名,B帳戶取得到簽名後,就可以完成授權轉帳的動作,竊取一定額度的代幣。 這裡我們主要來探討Smart Contract中代幣授權常見的兩個方法:approve()以及permit()。

在常見的ERC20合約中,A帳戶可以呼叫approve()方法給B帳戶授權一定的代幣額度,這樣B帳戶就可以轉移A帳戶的這部分額度的代幣;而permit() 在EIP-2612 被 引入到ERC20 的合約中,另外,Uniswap 已於2022年11月發布了新的Token 授權標準Permit2。

具體邏輯

在此,我們也舉個例子讓大家更深入了解常見的攻擊場景。 Bill有一天瀏覽一個區塊鏈資訊的網站,突然間網站彈出一個Metamask的簽名彈窗,由於很多區塊鏈網站或應用程式都是透過簽名來驗證用戶登錄,所以Bill不以為意,直接完成了簽名 ,5分鐘後,Bill的Metamask資產全部被轉移走,Bill隨後在區塊鏈瀏覽器發現了一個不知名地址先發起了permit()交易,隨後發起了transferFrom()交易將其錢包資金提空。

approve()& permit()合約方法實例

2個函數如下:

●approve():常規授權函數,A帳戶將一定的資金額度授權給B帳戶;

●permit():簽名授權函數,B帳戶透過從A帳戶取得的簽名,提交完成簽名驗證,取得A授權的資金額度,參數包括授權者owner、被授權者spender、授權金額amount、簽名截止時間deadline 、授權者的簽章資料v、r、s。

解決方法

1.注意鏈上互動的每個簽名

儘管某些錢包在解碼和展示 approve() 授權簽名資訊時採取了一些措施,但對於 permit() 簽名釣魚,錢包幾乎沒有提供足夠的警告,這增加了用戶受到攻擊的風險。 因此,強烈建議對於每個未知簽名都進行嚴格檢查,確保其是否是針對 permit() 函數的簽名。

2.常規交互錢包和資產存放錢包做到分離

這對幣圈的用戶,特別是空投獵人極為重要,因為幣圈用戶每天交互的Dapp或網站不可計數,不可避免會踩到陷阱,保證少量的金額在常規交互錢包中,才能保證自己資產損失在 可控範圍。

7.蜜罐攻擊

蜜罐攻擊(Honeypot)在區塊鏈產業中指的就是一類項目方部署的惡意代幣合約,合約只給予了專案方賣出權限,而一般用戶只能買不能賣,而蒙受損失。

具體邏輯

在此,我們也舉個例子讓大家更深入了解常見的攻擊場景。 A專案方在Telegram完成Announcement宣發,告知用戶已在主網部署代幣,大夥則可以參與交易。 由於代幣只能買不能賣,代幣前期價格不斷飛漲,用戶也不斷fomo買入,直到一段時間後有用戶發現賣出一直失敗,專案方趁機將手中的大量代幣賣出,將價格 砸下去並獲利。

蜜罐攻擊代幣合約實例

核心函數:

●_beforeTokenTransfer():代幣轉帳會呼叫的內部方法,只有呼叫者為owner的時候能夠成功,其他帳戶呼叫都會失敗。

解決方法

使用安全檢測工具

a.以太坊鏈 Token Sniffer

b.其他鏈 Ave Check

c.行情網站自帶偵測 Dextools

分數低的,盡量別參與交易。

8.搶跑攻擊

搶跑最初誕生於傳統金融市場,金融市場中的信息差給了金融中介機構生存和發展的機會,他們通過優先獲得特定行業信息並迅速採取行動來實現盈利;而區塊鏈行業裡的搶跑 主要來自於鏈上搶跑,即透過讓礦工優先打包的方式,搶先讓自己的交易上鍊,從而實現盈利。

在區塊鏈領域中,礦工可以透過操作他們打包區塊中的交易來獲得利潤,這包括排除某些交易、重新排序交易等等,而MEV則是衡量這種利潤的指標。 在使用者的交易被打包加入到以太坊主網之前,大部分交易會被匯集到交易記憶體池(Mempool)中。 礦工在這個記憶體池中尋找提供較高手續費(gas price)的交易,並優先進行打包,以最大化自身利益。 一般來說,手續費(gas price)越高的交易越容易被礦工打包。 同時,一些MEV機器人也會搜尋交易內存池中具有可獲利潛力的交易。

具體邏輯

在此,我們也舉個例子讓大家更深入了解常見的攻擊場景。 Bill發現了一個新的熱門代幣,代幣波動非常大,所以Bill在Uniswap上設置了非常大的滑點範圍以保證代幣交易能成功,但是Alice的MEV機器人此時在Mempool發現了這筆 交易,於是立即提高gas費在Bill發起交易前率先發起一筆買入交易,同時在Bill這筆交易之後插入賣出交易,由於在同一個區塊完成上述交易,區塊確認後,造成了Bill 巨大的滑點損失,Alice則完成低買高賣的套利操作。

簡化合約實例

函數如下:

●solve():猜謎函數,任何人都可以提交答案,如果提交的答案等於目標答案,就可獲得10 ether;

具體流程:

1.Bill 找到正確的答案;

2.Alice 監控 Mempool,等待有人提交正確的答案;

3.Bill 呼叫 solve()方法提交答案並將 Gas 價格設定為 100 Gwei;

4.Alice 看到 Bill 發送的交易並發現了答案,她設定比 Bill 更高的 Gas Price(200 Gwei),呼叫 solve() 方法;

5.Alice 的交易先於 Bill 的交易被礦工打包;

6.Alice 贏得了 10 個以太幣的獎勵。

解決方法

3個主要函數如下:

●commitSolution():提交結果函數,將使用者提交的答案solutionHash、提交時間commitTime以及狀態revealed,都放入結構體Commit中;

●getMySolution():取得結果函數,使用者可以查看自己已經提交的答案以及相關信息,包括使用者提交的答案solutionHash、提交時間commitTime以及狀態revealed;

●revealSolution():猜謎領獎函數,傳入答案和自己設定的密碼,領取獎勵。

具體流程:

1.Bill 找到正確的答案;

2.Bill 呼叫 commitSolution()方法,提交正確答案;

3.Bill 在下個區塊呼叫 revealSolution() 方法,傳入答案和自己設定的密碼,領取獎勵。

首先,在commitSolution()方法中,Bill提交的是密文字串,其他人無法得知Bill提交的明文資料是什麼。 在這一步,也記錄了提交的區塊時間commitTime。 接下來,在revealSolution()方法中,首先會檢查區塊時間,這樣可以防止在同一個區塊中被搶跑。 因為呼叫revealSolution()時需要傳入明文答案。 最後,使用Bill輸入的答案和密碼驗證與先前提交的solutionHash雜湊是否匹配。 這一步是為了防止有人不透過commitSolution()直接呼叫revealSolution()。 驗證成功後,會檢查答案是否正確,最後發放獎勵。

總括

智能合約在區塊鏈技術中扮演著至關重要的角色,它們具有許多優點。 首先,智能合約實現了去中心化的自動執行,在不需要第三方的情況下,能夠確保交易的安全性和可靠性。 其次,智能合約能夠減少交易的中間環節和成本,並提高交易效率。

儘管智能合約有許多好處,但遺憾的是,它也會面臨一些合約攻擊的風險。 這些攻擊可能會導致用戶的資金損失,因此作為鏈上用戶,有一些重要的習慣需要養成。 首先,使用者應該始終審慎選擇要互動的Dapp,並仔細閱讀合約的程式碼和相關規則。 此外,用戶還應該定期更新並使用安全的錢包和合約互動工具,以降低被駭客攻擊的風險。 此外,建議用戶將資金分散存放在多個地址中,以降低合約攻擊可能帶來的損失。

作為行業建設者,確保智能合約的安全性和穩定性同樣至關重要。 首先,應該加強智能合約的審計工作,以發現和修復潛在的漏洞和安全隱患。 其次,建造者也應該積極關注區塊鏈產業的訊息,學習關於合約攻擊的最新技術進展,並實施相應的安全措施。 此外,產業建設者應該加強對使用者的教育和宣傳,並提倡正確的使用智慧合約的方法和安全意識。

總之,儘管智能合約存在一些安全風險,但透過使用者和產業建設者的共同努力,可以最大程度地降低這些風險。 使用者應該養成謹慎選擇合約、保護好個人資產的習慣,而產業建構者應該加強合約審計、專注於技術進展,並提供使用者教育和宣傳,以推動智慧合約的安全可靠發展。




參考連結:

Solidity by 範例

https://solidity-by-example.org/

慢霧區塊鏈安全科普

https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU4ODQ3NTM2OA==&action=getalbum&album_id=1378673890158936067&scene=173&from_msgid=2247498135749

Chainlink - Top 10 DeFi Security Best Practices

https://blog.chain.link/defi-security-best-practices/#post-title

WTF - Solidity 104 合約安全

https://www.wtf.academy/solidity-104/

詳解DeFi協定智能合約漏洞:4大分類與38種情況

https://www.weiyangx.com/381670.html

OpenZeppelin

https://github.com/OpenZeppelin/

CC BY-NC-ND 4.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论