Análise de vulnerabilidade do balanceador

fundo

Em 22 de agosto, o Balancer anunciou oficialmente que recebeu relatórios de vulnerabilidades graves que afetaram vários pools do V2 Boost. Apenas 1,4% do TVL foi afetado. Vários pools foram suspensos e os usuários foram notificados para retirar o LP de liquidez o mais rápido possível. [1] [2]

Em 27 de agosto, o sistema SlowMist MistEye descobriu uma transação de ataque suspeita de explorar a vulnerabilidade do Balancer. [3]

Como o pool não pode ser suspenso e alguns fundos ainda são afetados pelo ataque, os funcionários do Balancer mais uma vez lembram os usuários de recuperar o LP do pool afetado. [4] Posteriormente, o Balancer divulgou oficialmente os detalhes da vulnerabilidade divulgada em agosto no Medium. [5] , a equipe de segurança do SlowMist revisou, os detalhes são os seguintes:

Introdução

Os responsáveis do balanceador simplesmente apontaram em sua divulgação que o problema desta vez é que o arredondamento para baixo do pool linear e a oferta virtual do pool combinável fizeram com que bptSupply fosse 0. Primeiro, vamos entender brevemente o conteúdo do protocolo Balancer relacionado a esta vulnerabilidade.

Cofre do Balanceador V2

Balanceador V2 [6] O protocolo é um protocolo descentralizado de criador de mercado automatizado (AMM) baseado em Ethereum que representa um bloco de construção flexível para liquidez programável. Seu componente principal é o contrato Vault, que mantém registros de todos os pools e gerencia a contabilidade e transferência de tokens, incluindo até mesmo o empacotamento e desempacotamento de ETH nativo. Em outras palavras, o Vault é implementado para separar a contabilidade e o gerenciamento de tokens da lógica do pool.

Existem quatro interfaces no Vault, nomeadamente joinPool, exitPool, swap e batchSwap (juntar, sair e trocar são chamadas separadas e não há combinação em uma única chamada). Um dos recursos mais destacados é o batchSwap, que pode realizar múltiplas trocas atômicas entre vários pools e conectar a saída de uma troca de pool à entrada de outro pool (GiveIn e GiveOut). O sistema também introduz trocas relâmpago [7] , semelhante a um empréstimo instantâneo interno.

Piscinas Lineares Piscina Linear

A fim de melhorar a eficiência de capital do LP e o problema de alta sobrecarga de warp e unwarp, a Balancer lançou o pool linear como uma solução em V2, introduzindo assim o token BPT (ERC20 Balancer Pool Token).

piscina linear [8] Incluindo o token principal (ativo subjacente), o token encapsulado (token encapsulado) e o token BPT, os ativos e suas contrapartes agrupadas com retornos são trocados por meio de taxas de câmbio conhecidas. Quanto maior a proporção de tokens empacotados, maior será o rendimento e a eficiência de capital do pool. Durante o processo de warp, fatores de escala são geralmente usados para garantir que diferentes tokens sejam calculados com a mesma precisão.

Pools combináveis Pool combinável

Todos os pools do Balancer são pools combináveis que contêm outros tokens e o próprio pool também possui seus próprios tokens. Entre eles, a moeda BPT refere-se ao token de pool balanceado ERC20, que é a base de todos os pools. Os usuários podem combinar livremente tokens BPT em outros pools para resgate. O resgate sempre envolve um pool e dois tokens: GiveIn e GiveOut. In significa enviar tokens de componentes e receber BPT, enquanto Out significa enviar BPT e receber tokens de componentes. Se o próprio BPT fosse um token componente, ele poderia ser trocado como outros tokens. Tal implementação constitui um caminho batchSwap simples entre os ativos subjacentes e tokens no pool externo. Os usuários podem usar o BPT para trocar pelos ativos subjacentes do pool linear. Este também é o Balancer Boosted Pool. [9] Fundação.

Através da combinação acima, o pool combinável do Balancer é formado. Um pool estável combinável bb-a-USD consiste em três pools lineares, enquanto envia liquidez ociosa para o protocolo externo (Aave). Por exemplo, bb-a-DAI é um pool linear contendo DAI e waDAI (aDAI encapsulado). Quando o usuário precisa fazer batchSwap (como alterar USDT para DAI), o exemplo do caminho de troca é o seguinte:

  1. No pool linear do USDT, troque o USDT por bb-a-USDT (entre no pool linear do USDT);

  2. Em bb-a-USD, bb-a-USDT é trocado por bb-a-DAI (troca entre BPT linear);

  3. No pool linear DAI, bb-a-DAI é trocado por DAI (saída do pool linear DAI).

Após compreender brevemente os pré-requisitos de conhecimento acima, entramos no link de análise de vulnerabilidade.

analisar

Em 27 de agosto, a equipe de segurança do SlowMist recebeu a identificação do sistema MistEye de que uma suspeita vulnerabilidade do Balancer foi explorada em estado selvagem. troca [3] do seguinte modo:

O invasor primeiro pegou emprestado 300.000 USDC da AAVE por meio de um empréstimo instantâneo. Em seguida, a operação batchSwap do Vault é chamada para realizar o cálculo de troca de tokens BPT através do pool estável combinável bb-a-USD.Finalmente, 94.508 USDC são trocados por 59.964 bb-a-USDC, 68.201 bb-a-DAI e 74.280 bb-a-USDT. Por fim, os tokens BPT obtidos sairão do pool através do contrato exitPool do Vault em troca de ativos subjacentes, reembolsarão o empréstimo instantâneo e sairão do mercado com um lucro de aproximadamente US$ 108.843,7.

Pode-se ver que a chave para este ataque está no batchSwap, e o que exatamente aconteceu no batchSwap? Vamos olhar mais de perto.

Durante todo o processo batchSwap, o invasor primeiro resgatou USDC no pool bb-a-USDC e depois trocou tokens BPT, trocando bb-a-USDC por bb-a-DAI, bb-a-USDT e USDC. Finalmente, o token principal subjacente USDC é trocado por bb-a-USDT. Em outras palavras, bb-a-USDC, como token chave do BPT, serve como token componente de GiveOut e GiveIn.

Na primeira etapa, o invasor troca tokens BPT por tokens principais USDC no pool linear bb-a-USDC com um fator de escala fixo, e o valor aumentado é registrado no bptBalance no pool. Mas após a segunda troca onSwap, descobrimos que o valor amountOut de USDC trocado foi 0 durante o mesmo processo de troca. Por que é isso?

Indo mais fundo na função onSwap, descobrimos que neste processo, a precisão será processada para nominal e o fator de escala do token correspondente será calculado. Quando a função _downscaleDown for chamada em seguida, amountOut será arredondado para baixo. Se amountOut e scalingFactors [indexOut] A diferença entre os valores é grande e o valor calculado de _downscaleDown é zero.

Ou seja, quando usamos tokens BPT para resgatar tokens principais, se amountOut for muito pequeno, o valor de retorno será arredondado para zero, e esse valor é menor que 1e12 calculado por scalingFactors. No entanto, o valor de bb-a-USDC proveniente de amountIn ainda será adicionado ao valor virtual bptBalance, e esta operação aumentará o saldo no pool bb-a-USDC, o que pode ser considerado como uma adição unilateral de bb -a-Liquidez USDC.

Em seguida, usando as características do pool estável combinável, por meio da conversão mútua entre tokens BPT, primeiro troque bb-a-USDC por outros tokens BPT. Para seguir esse processo de troca, você pode combinar o seguinte caminho de chamada do pool estável: bb-a-DAI onSwap -> _swapGivenIn -> _onSwapGivenIn. Primeiro, substitua bb-a-USDC por bb-a-DAI e bb- a-USDT em sequência. Ao contrário dos pools lineares online, os pools estáveis combináveis exigem atualizações de cache da taxa de câmbio antes das operações onSwap. A partir do código, podemos ver que no pool de combinação, onSwap determinará primeiro se a taxa de câmbio do token em cache precisa ser atualizada.

Após a troca anterior, o valor de bb-a-USDC mudou, e o valor total real após a nominalização por meio de _toNominal é totalBalance 994.010.000.000, e o fornecimento virtual de tokens BPT é 20.000.000.000. Pode-se calcular que a taxa de câmbio atualizada é quase 45 vezes a taxa de câmbio do cache original do pool linear anterior de 1.100.443.876.587.504.549, que é 49.700.500.000.000.000.000.

Posteriormente, bb-a-USDC é trocado por USDC no pool linear. No entanto, esta troca é igual à segunda troca, o que novamente faz com que amountOut seja arredondado para 0, e o caminho de troca é o mesmo de antes.

A próxima troca é reverter USDC para bb-a-USDC, e o caminho de troca é onSwap -> onSwapGivenIn -> _swapGivenMainIn. Durante esse processo, constatamos que ao calcular o amountOut que precisa ser resgatado, o cálculo do fornecimento virtual é baseado na diferença entre o fornecimento total do token BPT resgatado e o valor restante no pool, que é 0.

Isso ocorre porque bptSupply é 0 e a função _toNominal é chamada diretamente ao calcular o BPT Out, e a chamada desse caminho torna a relação de troca de USDC para bb-a-USDC próxima de 1:1.

Resumir

batchSwap conecta a saída da troca de um pool à entrada de outro pool (tokenIn e tokenOut) por meio de múltiplas trocas atômicas entre vários pools e converte USDC em tokens BPT. Neste batchSwap, nenhuma transferência real de token ocorre, mas o valor final da troca é confirmado registrando o valor transferido de entrada e saída. E como o pool linear é trocado por meio do token do ativo subjacente, o método de troca consiste em calcular a taxa por meio de uma oferta virtual e de um algoritmo fixo. Portanto, existem duas falhas de segurança no batchSwap:

O primeiro é o problema de arredondamento para baixo do pool linear: o invasor adiciona unilateralmente tokens principais ao pool por meio de arredondamento para aumentar a proporção de tokens armazenados em cache, manipulando assim a taxa de câmbio do token no pool combinável correspondente;

Em segundo lugar, devido às características de fornecimento virtual do pool combinável, o fornecimento virtual é calculado subtraindo o saldo do pool do token BPT.Se GiveIn for um token BPT no momento do resgate, esta parte será deduzida do subsequente fornecimento. , o invasor só precisa trocar o BPT como GiveIn, e primeiro manipular seu fornecimento para 0, e depois realizar a troca reversa, ou seja, o BPT é então usado como o lado GiveOut. Neste momento, como o fornecimento é 0, o o algoritmo será próximo de 1: A proporção de 1 é menor que a proporção de resgate do pool linear para resgate real, o que faz com que o número de tokens BPT do GiveOut seja indiretamente manipulado.

Podemos descobrir que a vulnerabilidade um aumenta a taxa de câmbio, enquanto a vulnerabilidade dois reduz a taxa de câmbio na direção inversa.O invasor aproveitou o buff duplo para obter lucro e sair.

Link de referência:

[1]

[2]

[3]

[4]

[5]

[6]

[7]

[8]

[9]

Ver original
Esta página pode conter conteúdo de terceiros, que é fornecido apenas para fins informativos (não para representações/garantias) e não deve ser considerada como um endosso de suas opiniões pela Gate nem como aconselhamento financeiro ou profissional. Consulte a Isenção de responsabilidade para obter detalhes.
  • Recompensa
  • Comentário
  • Compartilhar
Comentário
0/400
Sem comentários
Faça trade de criptomoedas em qualquer lugar e a qualquer hora
qrCode
Escaneie o código para baixar o app da Gate
Comunidade
Português (Brasil)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)