Em 23 de novembro de 2023, ocorreu uma série de ataques direcionados ao KyberSwap. Esses ataques resultaram em uma perda total de mais de $48 milhões. O problema fundamental originou-se de uma direção de arredondamento incorreta durante o processo de reinvestimento do KyberSwap. Isso subsequentemente levou a cálculos de tick impróprios e, em última análise, à contagem dupla de liquidez.
Publicamos um relatório extenso, "Yet Another Tragedy of Precision Loss: An In-Depth Analysis of the KyberSwap Incident", que aprofunda os detalhes do evento. Para uma compreensão mais aprofundada, recomendamos a consulta à análise completa. A seguir, fornecemos uma introdução sucinta a este incidente, destacando-o como um dos dez principais incidentes de segurança de 2023.
Contexto
KyberSwap é uma plataforma descentralizada de formador de mercado automatizado (CLAMM). Para atender à demanda de mercado de liquidez concentrada, o KyberSwap Elastic foi lançado com base no Uniswap V3, com diversas melhorias, incluindo a curva de reinvestimento para permitir o auto-compounding dos rendimentos de provisão de liquidez.
1. Tick e Preço de Raiz Quadrada
O Tick em CLAMMs similares ao Uniswap V3 é utilizado para marcar o preço de forma discreta, de modo que os LPs possam fornecer liquidez dentro de um intervalo fixo em vez de todo o intervalo (daí o termo "concentrada").
A liquidez pode ser colocada em um intervalo entre quaisquer dois ticks (que não precisam ser adjacentes), ou seja, um par de índices de tick (um tick inferior e um tick superior). Especificamente, o preço de cada tick (em um índice inteiro i) é definido da seguinte forma:
Na prática, o preço de raiz quadrada (denotado como sqrtP ou sqrtPrice) é utilizado:
Também é possível calcular o tick atual com base no preço de raiz quadrada atual:
Obviamente, enquanto apenas um único preço de raiz quadrada é calculado para um dado tick, múltiplos preços de raiz quadrada podem apontar para o mesmo tick. Para uma explicação mais detalhada, consulte a documentação do Uniswap V3 e do KyberSwap.
2. Curva de Reinvestimento
O CLAMM baseado no Uniswap V3 sofre com a baixa utilização do pool pelas taxas de LP e com as significativas taxas de gas necessárias para o reinvestimento. Portanto, o KyberSwap adotou a curva de reinvestimento para resolver o problema.
A chave da curva de reinvestimento é que as taxas coletadas em cada swap são acumuladas como liquidez adicional no pool como a liquidez de reinvestimento dentro de um intervalo infinito. Os tokens de reinvestimento são emitidos para os LPs e a liquidez de reinvestimento acumulada é alocada aos LPs de acordo. Além disso, a liquidez de reinvestimento também participa do processo de swap e cálculo de preço.
O código correspondente aos cálculos introduzidos acima é exibido na função computeSwapStep no seguinte trecho de código do pool correspondente.

Deve-se observar que, devido à liquidez de reinvestimento, a liquidity nesta função é a soma de dois componentes: baseL para a liquidez base e reinvestL para a liquidez acumulada para o reinvestimento.
3. Swap no KyberSwap
A implementação da função swap do pool do KyberSwap discutida anteriormente pode ser abstraída no diagrama abaixo:

A lógica crucial relacionada ao cálculo do tick reside dentro do loop while de swap, destacado pelo retângulo azul. Especificamente, a lógica principal envolve a função computeSwapStep e a função _updateLiquidityAndCrossTick. A primeira calcula estados-chave, como quantidades de entrada e saída para o swap dado e nextSqrtP, enquanto a segunda lida com casos em que um cross-tick ocorre.
Tradicionalmente, quando o preço aumenta, nos referimos a isso como deslocar o tick para a direita/para cima; caso contrário, dizemos que o tick se move para a esquerda/para baixo.
Para melhor compreender a vulnerabilidade que será discutida adiante, é essencial explorarmos a lógica de código relevante da função computeSwapStep, conforme ilustrado na figura a seguir:

Especificamente, a função calcReachAmount calcula os tokens de entrada necessários para o preço alvo targetSqrtP (linhas 50-57). Se o usedAmount for maior que specifiedAmount, o tick não é cruzado e nextSqrtP é calculado a partir de deltaL (ou seja, o delta de liquidez, linhas 59-62). O deltaL é determinado usando a função estimateIncrementalLiquidity, e o preço final nextSqrtP é calculado com a função calcFinalPrice (linhas 70-79). Se menos entrada for necessária, nextSqrtP é definido como o preço do próximo tick, mas esse caso não é usado no ataque.
Os passos descritos acima deixam claro que, se o tick não for cruzado, o nextSqrtP retornado por computeSwapStep não deve ser maior que o sqrtP do próximo tick. No entanto, devido à dependência do preço em relação à liquidez (liquidez base e delta de liquidez) e à perda de precisão, os atacantes conseguem manipular o nextSqrtP para ser maior enquanto o tick não é cruzado.
Análise de Vulnerabilidade
A causa raiz reside no cálculo de tick defeituoso causado pela direção de arredondamento incorreta dentro do cálculo do delta de liquidez (ou seja, a função estimateIncrementalLiquidity) do contrato SwapMath (que é invocado pela função computeSwapStep). Isso, por sua vez, afeta impropriamente o cálculo do tick posteriormente.

Curiosamente, ao examinar o comentário na linha 188 (destacado pelo retângulo azul), descobrimos que deltaL deve ser arredondado para cima a fim de arredondar para baixo o nextSqrtP. No entanto, deltaL é erroneamente arredondado para baixo devido ao uso da função mulDivFloor na linha 189. Consequentemente, nextSqrtP é incorretamente arredondado para cima.
Análise do Ataque
Os atacantes iniciaram múltiplas transações de ataque, com cada transação drenando múltiplos pools. Por simplicidade, a discussão a seguir é baseada no primeiro ataque dentro da transação de ataque.
A lógica central do ataque consiste nas seguintes seis etapas:
-
Empréstimo de 2.000 WETH via flash loan do AAVE.
-
Troca de 6,850 WETH por 6,371 frxETH no pool vítima 0xfd7b. Esta etapa é usada para empurrar o tick atual e o
currentSqrtPpara uma posição onde atualmente não há liquidez presente.
currentSqrtPparece ser escolhido aleatoriamente pelo atacante, e o swap para exatamente nesse preço.- A liquidez base (
baseL) é zero após esta etapa, mas a liquidez de reinvestimento (reinvestL) é diferente de zero.
- Adição de liquidez ao pool e em seguida remoção de parte da liquidez. Esta etapa é usada para controlar o intervalo e a liquidez total para um valor desejado.
- O intervalo de tick é escolhido com base no
currentSqrtP. - A liquidez desejada para o ataque pode ser derivada do intervalo de tick, embora a lógica de cálculo correspondente requeira exploração adicional.
- Troca de 387,170 WETH por 0,06 frxETH no pool. Esta etapa é usada para manipular o tick atual de modo que
nextTick==currentTick. Especificamente, o swap na etapa 4 engana astuciosamente o pool para acreditar que o tick 111.310 não é cruzado. No entanto, na realidade, ocurrentSqrtPé de fato maior que osqrtPdo tick 111.310.
- Troca de 0,06 frxETH por 396,244 WETH no pool. Observe que a direção do swap é oposta em comparação com a etapa anterior. Nesta etapa, a liquidez é contada duplamente para tornar o swap lucrativo e, consequentemente, drenar o pool.
- Repagamento do flash loan e coleta de 6,364 WETH e 1,117 frxETH.
Para um exame aprofundado, consulte nossa análise abrangente, que inclui mais detalhes com cálculos e figuras.
Resumo
O problema fundamental neste incidente decorre do arredondamento incorreto durante o processo de reinvestimento do KyberSwap, levando a cálculos de tick imprecisos e, em última análise, à contagem dupla de liquidez. Este incidente destaca a natureza intrincada e evasiva dos problemas de perda de precisão dentro dos protocolos DeFi, representando um sério desafio para toda a comunidade.
Este ataque de 2023 se destaca por sua complexidade, com cálculos excepcionalmente refinados, servindo como um exemplo primordial dos muitos incidentes de segurança relacionados à precisão que testaram significativamente a comunidade. Além disso, após extensas negociações com as autoridades, o atacante emitiu uma mensagem de tom provocador ao público, afirmando uma exigência de controle total sobre o protocolo.
Leia outros artigos desta série:
- Introdução: Os Dez Principais Incidentes de Segurança "Incríveis" de 2023
- #1: Colhendo MEV Bots Explorando Vulnerabilidades no Flashbots Relay
- #2: Incidente Euler Finance: O Maior Hack de 2023
- #4: Incidente Curve: Erro de Compilador Produz Bytecode Defeituoso a Partir de Código-Fonte Inocente
- #5: Platypus Finance: Sobrevivendo a Três Ataques com um Golpe de Sorte
- #6: Incidente Hundred Finance: Catalisando a Onda de Exploits Relacionados à Precisão em Protocolos Bifurcados Vulneráveis
- #7: Incidente ParaSpace: Uma Corrida Contra o Tempo para Deter o Ataque Mais Crítico da Indústria
- #8: Incidente SushiSwap: Uma Tentativa de Resgate Desajeitada Leva a uma Série de Ataques Imitadores
- #9: MEV Bot 0xd61492: De Predador a Presa em um Exploit Engenhoso
- #10: Incidente ThirdWeb: Incompatibilidade Entre Módulos Confiáveis Expõe Vulnerabilidade





