成都鏈安:Balancer 項目漏洞分析

成都鏈安:Balancer 項目漏洞分析

一、事件背景

Balancer 官網(https://balancer.finance/)上對於其具體功能的描述爲『Easily swap ERC20 tokens. Exchange tokens without deposits, bids/asks, and order management. All on-chain.』。簡單來說 Balancer 就是提供在鏈上進行 tokens 交換的區塊鏈智能合約應用。

2020 年 6 月 29 日凌晨(北京時間),Balancer 項目的兩個資金池遭受攻擊。攻擊者在此次事件中獲利約 46 萬美元,資金池市商損失約 50 萬美元。

根據此次安全事件的具體過程,可以將此次事件比喻爲攻擊者『偷樑換柱』。

二、抽絲剝繭還原攻擊者『偷樑換柱』經過

2.1、安全事件概述

▷根據鏈上交易數據顯示:

1、 攻擊者利用自建合約

(0x81d73c55458f024cdc82bbf27468a2deaa631407)對存在通縮貨幣 STA 的資產池

(0x0e511Aa1a137AaD267dfe3a6bFCa0b856C1a3682)進行了攻擊;

2、 攻擊者利用自建合約

(0xab9a95521107bc40dfa2e795059319f8b1302866)對存在通縮貨幣 STONK 的資產池

(0xb9eaf49d9f913bC1314e37bb5482891840c8e3C1)進行了攻擊。

2.2、攻擊步驟簡介

攻擊者首先通過閃電貸借款大量 WETH,而後使用借得的 WETH 將被攻擊資金池中的通縮貨幣(STA 或 STONK)兌換出來,僅留下 1e-18 個通縮貨幣。完成上述準備工作後,攻擊者開始發動攻擊,不斷使用 1e-18 個通縮貨幣(STA 或 STONK)兌換資金池內的其他代幣,以達到 『偷樑換柱』 的目的。直到池內資金基本被轉移完後,攻擊者將獲利存入如下地址:

0xBF675C80540111A310B06e1482f9127eF4E7469A

攻擊過程如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 1

此次事件發生後,Balancer 團隊表示已對資產池進行審計,正在進行第三次審計,並將在 UI 界面啓用通縮貨幣黑名單,禁止用戶建立存在通縮貨幣的資產池。

2.3、漏洞原理詳細分析

在分析漏洞具體信息之前我們需要知道以下兩點:

1、Balancer 項目允許個人建立資金池。 資金池本質上是一個智能合約,用戶可以調用資金池的函數進行代幣兌換。資金池中可以存在多種貨幣,用戶可以使用資金池中存在的貨幣進行兌換,兌換的比例按照一種固定的算法,如圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 2

我們以用 STA 兌換 WETH 爲例:

▷TokenAmountOut 表示可以兌換出的 WETH 的值

▷TokenBalanceOut 表示當前池內的 WETH 的值

▷TokenBalanceIn 表示當前池子內的 STA 的值

▷TokenAmountIn 表示用戶輸入的 STA 的值

▷TokenweightIn 表示 STA 的權重,爲一個固定值,只能由資金池的管理者更改

▷TokenweightOut 表示 WETH 的權重,爲一個固定值,只能由資金池的管理者更改

▷SwapFee 表示手續費,爲一個固定值,只能由資金池的管理者更改

綜上所述,當一種貨幣 STA 在一個資金池中的存量較少時,也就是 bI 較小時,就可以使用 STA 兌換更多的 WETH。

2、STA 代幣是一種通縮貨幣,當進行轉賬操作時,會自動銷燬一定量的 STA。 如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 3

tokensToBurn 即爲每次交易銷燬的值,其銷燬數額是轉賬數額的 1/100 (向上取整),如當數值爲 1e-18 時,其銷燬值也是 1e-18。銷燬值的計算源碼如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 4

成都鏈安:Balancer 項目漏洞分析

△圖 5

接下來我們對本次攻擊事件進行分析,以存在 STA 的被攻擊資金池爲例。攻擊者向自建合約

(0x81d73c55458f024cdc82bbf27468a2deaa631407)發起了一筆交易

(0x013be97768b702fe8eccef1a40544d5ecb3c1961ad5f87fee4d16fdc08c78106)。在此筆交易中,攻擊者首先從閃電貸借出了 104331 個 WETH,如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 6

而後使用借來的 WETH 兌換被攻擊資產池中的 STA,因爲 STA 是通縮貨幣,每次 transfer 都會使得 STA 銷燬轉賬金額的 1/100 (向上取整)。如下圖爲一次兌換:

成都鏈安:Balancer 項目漏洞分析

△圖 7

這筆交易共進行了 20 餘次兌換,使得被攻擊資金池中的 STA 餘量爲一個極小值(10-18)後開始使用 STA 兌換其他代幣(WETH),如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 8

我們可以發現,在此筆交易中,攻擊者轉給被攻擊合約的 STA 個數是『0』,但卻扣除了 1e-18 個 STA,這不符合正常兌換情況。於是我們對此進行深入分析,通過事件日誌確定攻擊者發送了 1e-18 個 STA。如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 9

由此可得出結論,在發送過程中,因爲 STA 的通縮機制,發送給資金池的 STA 會被銷燬,導致被攻擊資金池無法收到 STA,但資金池合約仍然會認爲收到了 1e-18 個 STA,並更新 STA 的存量(inRecord.balance)。如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 10

如果 STA 的存量增加,就會使得 STA 能夠兌換其他代幣的比例下降,因此攻擊者又調用了 gulp() 方法來更新 STA 的餘額,使得資金池的 STA 餘額等於實際餘額。如圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 11

每進行一次兌換,攻擊者就會調用一次 gulp() 對 STA 的餘額進行更新,這樣使得 STA 的餘額始終爲 1e-18 個,因此每次攻擊取出餘額的比例都是不變的(1/2),如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 12

攻擊者使用這種方式,將資金池中的所有代幣以每次 1/2 的比例進行兌換,最終幾乎將資金池中的所有代幣全部提出。

2.4、攻擊事件總結

根據我們日常智能合約安全審計經驗來看,本次事件產生的原因,可能是資金池合約對流入資金的處理方式不夠完善,並沒有考慮到通縮性代幣的情況,在計算應當輸出的值 tokenAmountOut 和貨幣餘額 inRecord.balance 的增減時,都是使用由用戶控制的 tokenAmountIn 參數,而不是實際收到的代幣數,導致實際池中的流入資金與記錄資金不相符,如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 13

另外,用於更新代幣餘額的 gulp ()函數的權限是 external,這兩點組合起來,導致了本次事件漏洞的產生,如下圖所示:

成都鏈安:Balancer 項目漏洞分析

△圖 14

成都鏈安:Balancer 項目漏洞分析

成都鏈安:Balancer 項目漏洞分析

成都鏈安:Balancer 項目漏洞分析

成都鏈安:Balancer 項目漏洞分析

成都鏈安:Balancer 項目漏洞分析

來源鏈接:mp.weixin.qq.com