7 月 18 日,我們的 DeFiRanger 系統報告了幾筆可疑交易。經過人工分析,我們確認這些交易是對 Array Finance 的攻擊。在下文中,我們將通過一筆攻擊交易來說明攻擊過程以及漏洞的根本原因。
攻擊交易
本部落格中使用的攻擊交易為: 0xa17bbc7c9ab17aa88fdb5de83b41de982845e9c9c072efff6709dd29febf0daa
攻擊流程

如圖 1 所示,我們發現攻擊者在從 AAVE 借出閃電貸後,獲得了 186.62 WETH 的利潤(在本部落格中,我們不嚴格區分 WETH 和 ETH)。

詳細的攻擊流程如圖 2 所示。
- 首先,攻擊者呼叫了 Array Finance 的
buy函式。攻擊者利用 45.91 WETH 從 Array Finance 鑄造並獲得了 430 個 ARRAY 代幣。 - 接著,攻擊者五次呼叫了一個閉源合約(Array Collater - 0xa800cda5)的
joinPool函式。他存入了 676,410.58 DAI + 679,080.46 USDC + 901.82 WETH + 20 WBTC + 20 renBTC,並獲得了 Array Collater 鑄造的 726.38 個 aBPT 代幣。 - 攻擊者呼叫
sell函式銷毀了 430 個 ARRAY 代幣,並獲得了 77.17 個 aBPT 代幣。 - 最後,攻擊者呼叫了 Array Collater 的
exitPool函式。他銷毀了在前兩步中獲得的 804.55 個 aBPT 代幣,並獲得了 748,271.55 DAI + 751,225.08 USDC + 997.62 WETH + 22.63 WBTC + 22.74 renBTC。
從圖 2 可以看出,攻擊者在第 5 步(圖 2:呼叫 sell 函式)獲得了利潤。這是因為所獲得的 77.17 個 aBPT 代幣比第 3 步(圖 2:呼叫 buy 函式)投入的 49.9142 WETH 價值更高。接下來,我們將分析代碼以了解攻擊發生的原因。
代碼漏洞
以下代碼展示了 Array Finance 的 sell 函式。在此函式中,Array Finance 使用攻擊者擁有的 ARRAY 代幣餘額,並呼叫內部 _sell 函式來計算透過賣出 ARRAY 代幣所能獲得的 aBPT 代幣數量。

以下是 _sell 函式的實作。它呼叫 calculateLPtokensGivenArrayTokens 來根據一定數量的 ARRAY 代幣獲取預期可獲得的 aBPT 代幣數量。然後,此函式銷毀 ARRAY 代幣並返回 aBPT 代幣。

以下展示了 calculateLPtokensGivenArrayTokens 函式的實作。

請注意,有四個參數會影響 amountLPToken 的計算。在閱讀 saleTargetAmount 後,我們推斷公式如下:
arraySmartPool.totalSupply() * (1 - (1 - amount / ARRAY.totalSupply()) ^ (1000000 / reseveRatio))
arraySmartPool 是 Array Collater 的智慧合約地址(0xa800cda5f3416a6fb64ef93d84d6298a685d190d)。當攻擊者將從閃電貸借入的資金存入 Array Collater 時,arraySmartPool.totalSupply() 的值會增加(如下表所示)。
TxnIndex: 64 arraySmartPool.totalSupply(): 110162296218708026400
TxnIndex: 107 arraySmartPool.totalSupply(): 165243444328062039600
TxnIndex: 150 arraySmartPool.totalSupply(): 247865166492093059400
TxnIndex: 193 arraySmartPool.totalSupply(): 371797749738139589100
TxnIndex: 236 arraySmartPool.totalSupply(): 557696624607209383650
TxnIndex: 280 arraySmartPool.totalSupply(): 836544936910814075475
在閱讀 arraySmartPool 的代碼後,我們可以確認這一邏輯。以下展示了 arraySmartPool 的 joinPool 函式。

該函式首先呼叫 SmartPoolManager 的 joinPool 函式,以計算需要從 msg.sender 獲取的代幣數量(actualAmountsIn)。然後,對於每個代幣,它呼叫 _pullUnderlying 函式將代幣存入 arraySmartPool。最後,它呼叫 _mintPoolShare 和 _pushPoolShare 來鑄造 aBPT 代幣並將其轉移給 msg.sender。
請注意,arraySmartPool 繼承自 PCToken。_mintPoolShare 函式呼叫了 _mint 函式,如下所示。
_mint 函式會增加 varTotalSupply 變數,該變數由 totalSupply() 直接返回。因此,每次呼叫 joinPool 時,此值都會增加。
利潤估算
| 攻擊地址 | 攻擊交易 | 利潤 (ETH) |
|---|---|---|
| 0x1337 | 0xa17bbc7c9ab17aa88fdb5de83b41de982845e9c9c072efff6709dd29febf0daa | 186.62073907323577 |
| 0x1b4fb735b51a25b280499710d02f50e4f772949664f9eb088e9d968b41ca2a1c | 59.338842936817095 | |
| 0x356ae8a278754551d9d2ae7dc0ea876b37c342ff2d010bee14aa253bb0b6030b | 18.827787420260467 | |
| 0x388fd59eab65b6034c96c01a21197eb2889d6507f84ff07e553749c541563962 | 5.880854505948256 | |
| 0xf4227ca3c8e8b5c8a0b10f034c6dee6556788c618e4cd289dc343b3247e85add | 0.4327422187881 | |
| 總計 | 271.1009661550497 | |
| 0x80d2 | 0xf061f8fc19c894ec37310ff59977ec97de55fd1494f1b1e66ae89188552d5c60 | 1.8414029470248867 |
| 總計 | 1.8414029470248867 | |
| 總計 | 272.9423691020746 |
總結
總之,攻擊者利用了 Array Finance 的價格機制依賴於可操縱的 aBPT 代幣 totalSupply 的漏洞。該漏洞已在我們的研究論文 DeFiRanger: Detecting Price Manipulation Attacks on DeFi Applications 中進行了討論。
鳴謝
Junjie Fei, Yufeng Hu, Ziling Lin, Siwei Wu, Lei Wu, Yajin Zhou @BlockSec
(按姓氏字母順序排列)
關於 BlockSec
BlockSec 是一家開創性的區塊鏈安全公司,由一群全球傑出的安全專家於 2021 年創立。公司致力於提升新興 Web3 世界的安全性和可用性,以促進其大規模採用。為此,BlockSec 提供智慧合約和 EVM 鏈安全審計服務、用於安全開發和主動攔截威脅的 Phalcon 平台、用於資金追蹤和調查的 MetaSleuth 平台,以及幫助 Web3 構建者在加密世界中高效航行的 MetaDock 擴充功能。
迄今為止,公司已為 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap 等 300 多家知名客戶提供服務,並獲得了包括矩陣夥伴 (Matrix Partners)、Vitalbridge Capital 和分佈式資本 (Fenbushi Capital) 在內的卓越投資者兩輪數千萬美元的融資。
官方 Twitter 帳號:https://twitter.com/BlockSecTeam



