• 【超完整懶人包】認識比特幣!原理與應用全面解析|動區新手村
  • Account
  • Account
  • BlockTempo Beginner – 動區新手村
  • Change Password
  • Forgot Password?
  • Home 3
  • Login
  • Login
  • Logout
  • Members
  • Password Reset
  • Register
  • Register
  • Reset Password
  • User
  • 不只加密貨幣,談談那些你不知道的區塊鏈應用|動區新手村
  • 動區動趨 BlockTempo – 最有影響力的區塊鏈新聞媒體 (比特幣, 加密貨幣)
  • 所有文章
  • 最完整的「區塊鏈入門懶人包」|動區新手村
  • 服務條款 (Terms of Use)
  • 關於 BlockTempo
  • 隱私政策政策頁面 / Privacy Policy
動區動趨-最具影響力的區塊鏈新聞媒體
  • 所有文章
  • 搶先看
  • 🔥動區專題
  • 🔥Tempo 30 Award
  • 加密貨幣市場
    • 市場分析
    • 交易所
    • 投資分析
    • 創投
    • RootData
  • 區塊鏈商業應用
    • 金融市場
    • 銀行
    • 錢包
    • 支付
    • defi
    • 區塊鏈平台
    • 挖礦
    • 供應鏈
    • 遊戲
    • dApps
  • 技術
    • 比特幣
    • 以太坊
    • 分散式帳本技術
    • 其他幣別
    • 數據報告
      • 私人機構報告
      • 評級報告
  • 法規
    • 央行
    • 管制
    • 犯罪
    • 稅務
  • 區塊鏈新手教學
  • 人物專訪
    • 獨立觀點
  • 懶人包
    • 比特幣概念入門
    • 從零開始認識區塊鏈
    • 區塊鏈應用
  • 登入
No Result
View All Result
  • 所有文章
  • 搶先看
  • 🔥動區專題
  • 🔥Tempo 30 Award
  • 加密貨幣市場
    • 市場分析
    • 交易所
    • 投資分析
    • 創投
    • RootData
  • 區塊鏈商業應用
    • 金融市場
    • 銀行
    • 錢包
    • 支付
    • defi
    • 區塊鏈平台
    • 挖礦
    • 供應鏈
    • 遊戲
    • dApps
  • 技術
    • 比特幣
    • 以太坊
    • 分散式帳本技術
    • 其他幣別
    • 數據報告
      • 私人機構報告
      • 評級報告
  • 法規
    • 央行
    • 管制
    • 犯罪
    • 稅務
  • 區塊鏈新手教學
  • 人物專訪
    • 獨立觀點
  • 懶人包
    • 比特幣概念入門
    • 從零開始認識區塊鏈
    • 區塊鏈應用
  • 登入
No Result
View All Result
動區動趨-最具影響力的區塊鏈新聞媒體
No Result
View All Result
Home 區塊鏈商業應用 defi

全解析 | 不可不知的 3種「Defi重入攻擊」: 基本概念、背後細節、手法 — Amber資安負責人

Vincent Lai by Vincent Lai
2021-09-01
in defi, 交易所, 安全, 犯罪, 美國
A A
全解析 | 不可不知的 3種「Defi重入攻擊」: 基本概念、背後細節、手法 — Amber資安負責人
232
SHARES
分享至Facebook分享至Twitter

在區塊鏈短短的歷史上發生過跟智能合約相關的攻擊事件中,重入攻擊無疑是最廣為人知的一種類型,在以太坊新創時期,2016 年 7 月的 TheDAO 事件甚至直接造成了以太坊硬分叉為以太經典 (ETC) 及現在大部分人熟知的以太坊 (ETH)。這次將由 Amber Group 區塊鏈安全團隊負責人 Chiachih Wu 博士,步步深入三種重入攻擊的基本概念、背後細節與手法。
(前情提要:乾貨 | Amber 安全專家吳博士:剖析 BSC 的閃電貸攻擊手法,如何再引發 3 個分叉項目連環爆?)

本文目錄

  • 經典案例分析
  • Uniswap 遭重入攻擊
  • DeFiPIE 重入攻擊
  • CREAM 遭同樣攻擊
    • 乾貨 | Amber 安全專家吳博士:剖析 BSC 的閃電貸攻擊手法,如何再引發 3 個分叉項目連環爆?
    • 台灣Defi | Cream Finance再遭閃電貸駭客攻擊,損失1,800萬美元的 ETH, AMP
    • BSC首現閃電貸攻擊/技術解析 Spartan Protocol 遭駭手法,造成 3 千萬美元損失

 

本文為數位資產投資集團 Amber Group 的投稿,作者為該集團區塊鏈安全專家吳家志博士(Chiachih Wu),同時共同創辦了區塊鏈知名安全公司派頓(Peckshield)。


在 TheDAO 事件給以太坊重擊之後,開發者也多了一些方法來防範重入攻擊,例如,Checks-Effects-Interactions [1] 以及 Reentrancy Guard [2]。

然而,許多重入攻擊仍然持續發生,攻擊的形式也從通過 fallback 函數重入同函數轉變成通過不同的外部函數進入智能合約,造成合約狀態混亂以達成有效攻擊。

本文將介紹及重現發生於 2020 年 4 月 UniswapV1 的重入攻擊,2021 年 7 月發生在 BSC 上 DeFiPIE 項目的重入攻擊,以及近期發生於 C.R.E.A.M. 項目的 AMP 代幣重入攻擊 [8]。

延伸閱讀:DeFi | 拆解Cream.Finance「ERC-777重入攻擊」,駭客獲利1,880萬美元

延伸閱讀:勿輕信熱心網友!Board Ape投資者 78 萬鎂的NFT全被盜走:MetaMask也很有問題

經典案例分析

在進入案例分析之前,我們先介紹下重入攻擊的基本概念。

下面是 Solidity 網站上面介紹重入攻擊給的簡單案例 [3],事實上這個 Fund 合約,就是簡化過的 TheDAO 合約,在 withdraw () 函數裡我們可以看到 shares [msg.sender] 數量的 ETH 會透過 msg.sender.send() 發給 msg.sender,也就是 Fund.withdraw() 的 caller。

其中 shares[] 裡頭存的是每個 user 存入合約的 ETH 額度,因此在 user 成功取出 ETH 之後,shares[msg.sender] 會被清零,這個程式邏輯看起來沒有任何問題。
然而,上述的 caller (msg.sender) 可以是個惡意合約地址,如果惡意合約裡寫了 fallback function ,則 Fund.withdraw() 裡的 msg.sender.send() call 就可以被 hijack,在這個 fallback function 裡如果再次調用了 Fund.withdraw() ,則 shares[msg.sender] 數量的 ETH 就會在被清零之前被多次發送給 msg.sender,下面是一個示意圖:

攻擊者部署一個 Evil 合約,在 Evil.receive() (即 fallback function)檢查 Fund 的 ETH 足夠的情況下連續調用 Fund.withdraw() ,即可將 Fund 合約的 ETH 抽光,直到最後一次調用,shares[msg.sender] 才會被真正的清零。

這個簡單的重入攻擊案例有一個關鍵點:「清零」 發生在 「轉帳」 之後。

雖然這樣的寫法比較符合人類的邏輯,即『確認轉帳成功了,再把紀錄清掉』,但是在 EVM 的世界裡有點不同。其實先清零再轉帳也沒有什麼問題的,如果轉帳失敗了,清零的操作會自動回滾 (revert)。

而且把轉帳放到清零之後,反而可以避免重入攻擊,也就是 Checks-Effects-Interactions pattern。shares[msg.sender] 是 effects,msg.sender.send() 是 interactions,只要所有的 interactions 都在 effects 之後,即使重入了 Fund.withdraw() 也不會造成什麼影響。

延伸閱讀:被誤解的閃電貸:我只是一個工具….5月DeFi安全事件25起、BSC占15起

延伸閱讀:你的「紙錢包」可能不安全!私鑰盜竊問題叢生,資安新創 CYBAVO 詳列危險清單

Uniswap 遭重入攻擊

接下來,我們將介紹一個類似的案例,只是漏洞利用方式稍微複雜一點。2020 年 4 月 18 日下午,Twitter 上開始出現了關於 Uniswap imBTC pool 被攻擊的消息 [4]:

(編輯註:以下 Uniswap 攻擊模擬測試由 Amber Group「STAR-X實習計劃」 中來自卡內基梅隆大學的學生所做。目前新一期的 STAR-X 計畫已啟動。)

Uniswap 的創辦人 Hayden Adams 提到了 UniswapV1 不支持 ERC-777 並且附上了一個 ConsenSys Diligence blog 的連結[5]。事實上,這次攻擊符合 ConsenSys Diligence blog 裡的描述,而且這篇 blog 是差不多剛好一年之前寫的 (2019-4-20)。

關鍵點在 UniswapV1 的 tokenToEthInput() 函數與 ERC-777 token 的兼容性問題,從下面程式碼片段可以看到,tokenToEthInput() 函數基本上是符合 Checks-Effects-Interactions 的寫法,第 208 行合約給用戶發送 ETH,第 209 行用戶給合約發送 token,都在函數的最後面執行,如果從 UniswapV1 本身來看是沒有任何問題的。

然而,DeFi 世界就像是一個金融樂高遊樂場,209 行發送的 token 本身也是一個智能合約,在這個合約肚子裡存在一個 effects after interactions 的場景。
下面是某個 ERC-777 token contract 的 transferFrom() 函數底層實現,第 866 行有一個 callback interface 可以用來通知 holder ,只要 holder 是一個合約地址,並且按照 ERC-1820 註冊了 tokensToSend() 函數。

而第 868 行的 _move() 才是真正更新 token balances 的地方。因此,如果攻擊者在 _callTokensToSend() 時重入了 UniswapV1 的 tokenToEthInput(),可以造成 UniswapV1 pool 本身 token balance 增加之前,多次兌換成 ETH。即第 204 行的 token_reserve 永遠不變。
簡單的說,在重入攻擊發生的情況下,第 204 取出的 token_reserve 可能跟上一層調用是一樣的,在 Uniswap xy=k 的設定下,如果可以用同樣的 token_reserve 多次交易,等於是可以持續用較高的價格賣出 token 把流通性提供方 (LP) 的代幣消耗殆盡。

下面是我們利用 eth-brownie 回到案發之前的 2020-2-15 區塊高度 9488451 重現這次攻擊的程式碼:

首先是透過 ERC-1820 合約註冊 tokensToSend() callback function,註冊完成之後所有兼容 ERC-777 的 token transfer 發生時,如果目標地址是攻擊合約本身,則合約的 tokensToSend() external function 會被調用。接下來介紹攻擊發起函數 trigger():

上面這短短 10 行原始碼只做了四件事,第 38 行將 ETH 換成 token,第 39 行將上一步換出來的 token 又換回 ETH,第 40 行將一部分 ETH 換成 token,第 43-44 行將所有的 ETH 及 token 轉給 owner,也就是攻擊者錢包地址。

其中,第 39 行有一個比較特別的點,只有 1/32 的 token 被換回 ETH,按照這樣的寫法肯定是會虧錢的。其實另外的 31/32 置換是在上述的 callback function 裡頭完成,程式碼如下:
從上面的程式碼可以看到 entry 會計算現在是第幾次進入 tokensToSend() 然後在第 57 行完成另外 31 次兌換,每次也是 1/32 的 token balance。

透過這 31 次重入,攻擊者可以用較好的價錢賣出 token 並且破壞 UniswapV1 pool 裡的平衡狀態,即 xy=k 的 k 值改變,因此最終 pool 裡的 ETH 會變得很少 token 很多,ETH 相對於 token 的價值極高,所以上面 trigger() 函數的第 40 行,攻擊者可以用很少的 ETH 把大部分 pool 裡的 token 買回來。下面是攻擊原始碼執行的結果:

原本 pool 裡頭有 718 ETH + 19.59 imBTC,攻擊完成之後只剩下 0.013 ETH + 0.019 imBTC,幾乎是掏空了 pool。

DeFiPIE 重入攻擊

上述 UniswapV1 + ERC-777 的例子其實跟 TheDAO 的案例類似,都屬於同一個函數的重入,下面介紹一個多函數參與的案例,是近期發生在 BSC 上的 DeFiPIE 攻擊事件。

在第一眼看到 DeFiPIE 原始碼時,有一種熟悉感,與老牌 DeFi 項目 Compound 有 87% 的相似度,直覺聯想起了 2020-4-19 的 Lendf.Me $25M Better future 事件 [6]。仔細分析之後發現,問題的根源確實如出一轍,都是透過重入攻擊造成內部記帳錯誤,達成獲利。

從上面 DeFiPIE 的 PToken 合約程式碼片段中可以看到,borrowFresh() 函數會在把資產發給 borrower 之後才將因為這次借款造成的狀態改變寫入合約的 storage,所以又是一個 effects after interactions 的案例。

由於借款的上限取決於抵押資產的價值,正常情況下,某一次借款把額度用完之後,在歸還借款之前應該就借不出任何資產了。

但由於上述情況數據沒有及時更新,重入後的第二次借款仍然可以使用跟第一次借款發生前一樣的額度,因此理論上是可以無限嵌套,多次利用有限額度,最終攻擊者可透過清算自己以較低成本創造的負債獲利。

在 Lendf.Me 事件中,攻擊者是透過 imBTC 的 ERC-777 內建機制攔截 transferFrom() 完成重入攻擊。在 DeFiPIE ,對於 token 本身並沒有任何限制,可以隨意創建 token 合約納入借貸體系。

如上圖所示,任何人都可以創建一個惡意的 EvilToken 並且人工製造一個攔截 transfer() 的機制以達成重入攻擊,下面介紹我們如何 reproduce 針對 DeFiPIE 的攻擊,由於這個攻擊比較複雜,我們會依序從各個模組介紹,最後介紹如何組裝使用。

先從惡意 token contract 開始,現在要寫一個 ERC-20 合約基本上只要繼承 OpenZeppelin 的 template[7] 自行修改 token name 以及 symbol 就行。

在上面的 X token contract 裡可以看到,第 233 行的 transfer() 我們加入了一個開關 optIn,在開關打開的情況下 (optIn == true),Lib.shellcode() 會被調用執行重入攻擊任務,這就是上面說到的人工創建攔截 transfer() 的機制。其他如 mint(), setup(), start() 就是一些方便使用的外部函數。

第二個模組是 Lib.shellcode() 函數,也就是上述 transfer() 被攔截後發起重入攻擊的地方,在這次模擬中,我們嵌套了三層,依序調用了自行創建的 PToken (pX[1], pX[2]) 並且在第三層從 pBUSD 真正的借出了 21,000 BUSD,在這過程中實現了『三個罈子一個蓋』。

第三個模組是獲利的關鍵,清算者 (Liquidator)。在上面的 Liquidator.trigger() 函數可以看到,清算者使用 x 代幣調用 pX 合約的 liquidateBorrow() 獲取質押品 colleteral(即 pCAKE),隨後在第 66-67 行將 pCAKE 換成 CAKE 並轉給 owner(即 Lib 合約)。

mint() 函數的作用是提供足夠的 x 給 pX 合約,讓上述 Lib 合約能夠調用 pX.borrow() 借出資產。

接下來就是組裝上面三個模組搭配閃電貸取得獲利,首先是創建三個 X tokens 及 Lib 合約。Lib 合約的 constructor 創建了 Liquidator 合約。

第 272-278 行鑄造了X tokens給 Liquidator 及 Lib,第 280-284 行將 X tokens 與 Lib 互相關聯上。第 285 行觸發 Lib 合約啟動後續流程,最後在第 288 行將獲利的 WBNB 轉給 owner (即攻擊者錢包地址)。

Lib.trigger() 實際上就做了一個兩層的 PancakeSwap 閃電貸,第 116 行可以看到 154.5 WBNB 被借出,在回調函數 pancakeCall() 裡又借了 2,900 CAKE。主要的攻擊流程在 pancakeCall() 的後半段。

在進入第二層 pancakeCall() 時,就是真正攻擊流程的開始,首先是使用 x[0], x[1], x[2] 這三個 X tokens 創建三個 pToken (pX[0], pX[1], pX[2])。

要創建 pToken 需要預先在 Uniswap 創建交易對並且注入流通性(第 136-142行),pX[i] 創建完畢後,即可取出流通性(第 149 行)以方便重複使用前面借出的 WBNB,最後觸發 Liquidator 存入足夠的 x[i] 讓 pX[i] 能夠被 borrow() (第 152 行)。

第二步是觸發 pX.borrow() 前的準備工作,第 156-162 行調用了 Controller.enterMarkets() 將 pX[0], pX[1], pX[2], pCAKE 等 pToken 納入 DeFiPIE 體系,以便後續操作。第 166 行將前面閃電貸借出的 2,900 CAKE 全數注入 pCAKE 合約充當後續借貸的抵押品。

第三步打開 x[0], x[1], x[2] 的 transfer() 攔截機制(第 170-172 行),並且觸發 pX[0].borrow(),由於上述 Lib.shellcode() 的作用下,最終會拿到 21,000 BUSD,並且創造了不良資產。

第四步觸發 Liquidator 清算不良資產,獲得 CAKE。

清償完閃電貸後,在測試環境中最終獲利 66 WBNB。雖然數額不大,但這個案例涉及到代幣合約,清算合約等較複雜的漏洞利用過程,值得研究分享。

CREAM 遭同樣攻擊

2021 年 8 月 30 日下午,就在這篇文章完稿之際,C.R.E.A.M. 項目傳出了遭遇攻擊損失 $18M [9]。筆者短暫分析攻擊交易後發現這次攻擊與上述 DeFiPIE 遭遇的攻擊手法極其類似,決定復現此案例並加入本文。

漏洞的原理其實不需要贅述,跟 DeFiPIE 基本是一樣的,攻擊者通過 AMP 代幣自身的回調機制實現了『兩個罈子一個蓋』,用同一筆 ETH 質押品借出了 AMP 及 ETH,最終透過另一個合約清算自己的不量債務獲利。下面直接介紹攻擊合約的各個模組以及最後的組裝使用:

首先是註冊 callback function,跟前面 UniswapV1 的情況類似,攻擊者通過 ERC-1820 合約註冊一個 tokensReceived() 函數,當有人往攻擊合約發送 AMP tokens 時,callback function 會被觸發。

而 callback function 本身就是一個針對 crETH 合約的 borrow() 調用,攻擊者的預期是在 crAMP.borrow() 的調用過程中利用同樣的抵押品再借一筆 ETH。

第三個模組是 Liquidator 合約,與上述 DeFiPIE 的 Liquidator 類似,在上圖 Liquidator.trigger() 函數裡,攻擊者用 AMP 清算了自身創造的不良資產獲得 crETH 抵押品(第 60 行),隨後將 crETH 換成 ETH(第 61 行),並發回給 owner,即攻擊合約。

最後就是組裝執行攻擊了,上圖是 Exp.trigger() 函數,在第 94 行先是一個 UniswapV2 的閃電貸,借出了 500 WETH,後面的 uniswapV2Call() 函數才是真正的流程。

首先是一些準備工作,由於閃電貸借的是 WETH 而 crETH 需要使用 ETH 才能鑄造,因此在第 105 行,先將 WETH 換成 ETH,接下來將換出的 ETH 全數發給 crETH 合約鑄造出 crETH cTokens。與前面 DeFiPIE 攻擊一樣,需要調用一次 Comptroller.enterMarkets() 將 crETH 開啟以便後續的操作。

第二步就是利用上面存入的 500 ETH,借出 AMP tokens,在 crAMP.borrow() 的過程中 crAMP 合約把 AMP 轉給攻擊合約,由於前面 ERC-1820 的機制,這次轉帳會被攔截並另外借出 355 ETH。

第三步通過 Liquidator 合約清算債務,將部分質押品取回。從上圖可以看到攻擊者將前面借出的一半 AMP 發給 Liquidator,換回足夠支付閃電貸的 ETH,保留剩下的 AMP。

最終將 ETH 都換成 WETH 支付閃電貸後,帶走 41 WETH + 9.74M AMP。

若以『幣圈一天,人間一年』給區塊鏈世界計時,重入攻擊算是上古時期的物種了,開發者還需多從歷史上發生過的案例中吸取經驗,形成肌肉記憶,避免受到傷害。


.Reference.
[1] https://docs.soliditylang.org/en/v0.4.21/security-considerations.html#use-the-checks-effects-interactions-pattern
[2] https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard
[3] https://docs.soliditylang.org/en/v0.4.21/security-considerations.html#re-entrancy
[4] https://twitter.com/_prestwich/status/1251382098188877824
[5] https://medium.com/consensys-diligence/uniswap-audit-b90335ac007
[6] https://peckshield.medium.com/uniswap-lendf-me-hacks-root-cause-and-loss-analysis-50f3263dcc09
[7] https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol
[8] https://twitter.com/CreamdotFinance/status/1432249771750686721
[9] https://twitter.com/ICO_Analytics/status/1432234014878879744

📍相關報導📍

乾貨 | Amber 安全專家吳博士:剖析 BSC 的閃電貸攻擊手法,如何再引發 3 個分叉項目連環爆?

台灣Defi | Cream Finance再遭閃電貸駭客攻擊,損失1,800萬美元的 ETH, AMP

BSC首現閃電貸攻擊/技術解析 Spartan Protocol 遭駭手法,造成 3 千萬美元損失


讓動區 Telegram 新聞頻道再次強大!!立即加入獲得第一手區塊鏈、加密貨幣新聞報導。

LINE 與 Messenger 不定期為大家服務

加入好友

加入好友

Tags: ethereum以太坊安全重入攻擊

關於我們

動區動趨

為您帶來最即時最全面
區塊鏈世界脈動剖析
之動感新聞站

訂閱我們的最新消息

動區精選-為您整理一週間的國際動態

戰略夥伴

Foresight Ventures Foresight News

主題分類

  • 關於 BlockTempo

動區動趨 BlockTempo © All Rights Reserved.

No Result
View All Result
  • 所有文章
  • 搶先看
  • 市場脈動
  • 商業應用
  • 區塊鏈新手教學
  • 區塊鏈技術
  • 數據洞察
  • 政府法規
  • RootData
  • 登入

動區動趨 BlockTempo © All Rights Reserved.