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的智能合约地址(0xa800cda5)。当攻击者将从闪电贷借入的资金存入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代币并将铸造的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



