Back to Blog

A Análise do Incidente de Segurança do Array Finance

Code Auditing
July 19, 2021
5 min read

Em 18 de julho, nosso sistema DeFiRanger reportou algumas transações suspeitas. Após análise manual, confirmamos que essas transações são ataques à Array Finance. A seguir, usaremos uma transação de ataque para ilustrar o processo de ataque e a causa raiz da vulnerabilidade.

Transação de Ataque

A transação de ataque utilizada neste blog é: 0xa17bbc7c9ab17aa88fdb5de83b41de982845e9c9c072efff6709dd29febf0daa

Fluxo do Ataque

Figura 1
Figura 1

Conforme mostrado na Figura 1, descobrimos que o atacante obteve um lucro de 186,62 WETH (não distinguimos explicitamente entre WETH e ETH neste blog) após tomar emprestado o flash loan da AAVE.

Figura 2
Figura 2

O processo detalhado do ataque é mostrado na Figura 2.

  • Primeiro, o atacante invocou a função buy da Array Finance. O atacante obteve 430 tokens ARRAY cunhados pela Array Finance usando 45,91 WETH.
  • Em seguida, o atacante invocou a função joinPool de um contrato de código fechado (Array Collater - 0xa800cda5) cinco vezes. Ele/ela depositou 676.410,58 DAI + 679.080,46 USDC + 901,82 WETH + 20 WBTC + 20 renBTC e obteve 726,38 tokens aBPT cunhados pelo Array Collater.
  • O atacante invocou a função sell para queimar 430 tokens ARRAY e obteve 77,17 tokens aBPT.
  • Por fim, o atacante invocou a função exitPool do Array Collater. Ele/ela queimou 804,55 tokens aBPT obtidos nas duas etapas anteriores e obteve 748.271,55 DAI + 751.225,08 USDC + 997,62 WETH + 22,63 WBTC + 22,74 renBTC.

Pela Figura 2, podemos ver que o atacante obtém lucros na etapa 5 (Figura 2: Invocar a função sell). Isso ocorre porque os 77,17 tokens aBPT obtidos são mais valiosos do que os 49,9142 WETH depositados na etapa 3 (Figura 2: Invocar a função buy). A seguir, analisaremos o código para entender por que esse ataque pode acontecer.

Vulnerabilidade no Código

O código a seguir mostra a função sell da Array Finance. Nesta função, a Array Finance usa o saldo do token ARRAY de propriedade do atacante e invoca a função interna _sell para calcular o número de tokens aBPT que podem ser obtidos ao vender o token ARRAY.

A seguir está a implementação da função _sell. Ela invoca a calculateLPtokensGivenArrayTokens para obter o número de tokens aBPT que podem ser ganhos dado um certo número de tokens ARRAY. Em seguida, essa função queima o token ARRAY e retorna o token aBPT.

A seguir está a implementação da função calculateLPtokensGivenArrayTokens.

Observe que há quatro argumentos que podem afetar o cálculo de amountLPToken. Após ler o saleTargetAmount, inferimos que a fórmula é a seguinte:

arraySmartPool.totalSupply() * (1 - (1 - amount / ARRAY.totalSupply()) ^ (1000000 / reseveRatio))
 

O arraySmartPool é o endereço do contrato inteligente do Array Collater (0xa800cda5f3416a6fb64ef93d84d6298a685d190d). O valor de arraySmartPool.totalSupply() aumentará quando o atacante depositar fundos emprestados do flash loan no Array Collater (mostrado na tabela a seguir).

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

Podemos confirmar essa lógica após ler o código do arraySmartPool. A seguir está a função joinPool do arraySmartPool.

Essa função primeiro invoca a função SmartPoolManager.joinPool para calcular o número de tokens (actualAmountsIn) que precisam ser obtidos do msg.sender. Em seguida, para cada token, ela invoca a função _pullUnderlying para depositar o token no arraySmartPool. Por fim, ela invoca o _mintPoolShare e o _pushPoolShare para cunhar o token aBPT e transferir o token aBPT cunhado para o msg.sender.

Observe que o arraySmartPool herda do PCToken. A função _mintPoolShare invoca a função _mint, que é mostrada a seguir.

A função _mint aumentará a variável varTotalSupply, que é retornada diretamente pelo totalSupply(). Portanto, esse valor é incrementado a cada invocação do joinPool.

Estimativa de Lucro

Resumo

Em resumo, o atacante explora a vulnerabilidade de que o mecanismo de preço da Array Finance depende do totalSupply do token aBPT, que é manipulável. A vulnerabilidade foi discutida em nosso artigo de pesquisa DeFiRanger: Detecting Price Manipulation Attacks on DeFi Applications.

Créditos

Junjie Fei, Yufeng Hu, Ziling Lin, Siwei Wu, Lei Wu, Yajin Zhou @BlockSec

(Em ordem alfabética pelo sobrenome)

Sobre a BlockSec

A BlockSec é uma empresa pioneira em segurança blockchain estabelecida em 2021 por um grupo de especialistas em segurança de renome mundial. A empresa está comprometida em aprimorar a segurança e a usabilidade para o emergente mundo Web3, a fim de facilitar sua adoção em massa. Para isso, a BlockSec oferece serviços de auditoria de contratos inteligentes e segurança de redes EVM, a plataforma Phalcon para desenvolvimento seguro e bloqueio proativo de ameaças, a plataforma MetaSleuth para rastreamento e investigação de fundos, e a extensão MetaDock para construtores web3 navegando com eficiência no mundo cripto.

Até o momento, a empresa atendeu mais de 300 clientes renomados, como MetaMask, Uniswap Foundation, Compound, Forta e PancakeSwap, e recebeu dezenas de milhões de dólares americanos em duas rodadas de financiamento de investidores proeminentes, incluindo Matrix Partners, Vitalbridge Capital e Fenbushi Capital.

Site oficial: https://blocksec.com/

Conta oficial no 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