Back to Blog

金融数组安全事件分析

Code Auditing
July 19, 2021
6 min read

在7月18日,我们的 DeFiRanger 系统 报告了几笔可疑交易。经过人工分析,我们确认这些交易是针对 Array Finance 的攻击。接下来,我们将以一笔攻击交易为例,说明攻击过程和漏洞的根本原因。

攻击交易

本文使用的攻击交易是: 0xa17bbc7c9ab17aa88fdb5de83b41de982845e9c9c072efff6709dd29febf0daa

攻击流程

Figure 1
Figure 1

如图 1 所示,我们发现攻击者在从 AAVE 借入闪电贷后,获得了 186.62 WETH 的利润(本文中不区分 WETH 和 ETH)。

Figure 2
Figure 2

图 2 展示了详细的攻击过程。

  • 首先,攻击者调用了 Array Finance 的 buy 函数。攻击者花费 45.91 WETH,铸造了 430 个 ARRAY 代币,并获得了这些代币。
  • 接着,攻击者调用了一个闭源合约(Array Collater - 0xa800cda5)的 joinPool 函数五次。他/她存入了 676,410.58 DAI + 679,080.46 USDC + 901.82 WETH + 20 WBTC + 20 renBTC,并获得了 726.38 个由 Array Collater 铸造的 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 代币并将铸造的 aBPT 代币转移给 msg.sender

请注意,arraySmartPool 继承自 PCToken。_mintPoolShare 函数调用 _mint 函数,如下所示。

_mint 函数会增加 varTotalSupply 变量,该变量直接由 totalSupply() 返回。因此,每次调用 joinPool 都会增加此值。

利润估算

总结

总而言之,攻击者利用了 Array Finance 的价格机制依赖于 aBPT 代币的 totalSupply,而 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 平台用于资金追踪和调查,以及 MetaDock 扩展,帮助 Web3 构建者在加密世界中高效冲浪。

截至目前,公司已为 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap 等 300 多家尊贵客户提供服务,并在两轮融资中从 Matrix Partners、Vitalbridge Capital 和 Fenbushi Capital 等知名投资者那里获得了数千万美元的投资。

官方网站:https://blocksec.com/

官方 Twitter 账号:https://twitter.com/BlockSecTeam

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit