Publication
Partagez vos connaissances.
Analyse de l'exploit du protocole Cetus sur Sui
Le 22 mai 2025, un exploit majeur a ciblé le protocole Cetus sur la blockchain Sui, entraînant des dommages estimés à 223 millions de dollars. Cet incident a immédiatement attiré l'attention de l'ensemble de l'écosystème, en particulier de la part des observateurs techniques en raison des mécanismes inhabituels impliqués. Ce qui suit est une analyse complète de l'attaque, allant des échanges de flash et des manipulations de ticks à une vulnérabilité silencieuse dans la logique de détection des débordements.
https://suiscan.xyz/mainnet/tx/DVMG3B2kocLEnVMDuQzTYRgjwuuFSfciawPvXXheB3x
La configuration
L'attaquant a lancé l'exploit en utilisant flash_swap pour emprunter une grande quantité de jetons SUI en échange de HasUI. Contrairement aux flashloans traditionnels, flash_swap dans Cetus permet à un utilisateur de recevoir token1 (SUI dans ce cas) à l'avance, puis de rembourser token0 (hasUI) dans le cadre de la même transaction. Ce mécanisme est au cœur de la configuration de l'attaquant.
Dans ce cas précis, l'attaquant a réussi à acquérir 5,76 millions de SUI et a été obligé de rembourser 10,02 millions de HASUI. Mais au cours de cet échange, le prix de HaSUI dans le pool de liquidités a été radicalement manipulé. Le cours du pool est passé d'un tick représentant un ratio de 1,056 à un tick si bas que le cours n'a atteint que 0,0000009977, soit une énorme dévaluation à 0,00009 % de son prix initial.
La fourchette de prix correspondant à la fourchette à cocher est la suivante :
Injection stratégique de liquidités
À la suite de cette chute des cours, l'attaquant a utilisé open_position pour créer une position de liquidité à fourchette étroite, en choisissant une fourchette de ticks très spécifique (TickLower : 300000, TickUpper : 300200). Dans cet environnement manipulé, ils ont injecté une quantité astronomique de liquidités : plus de 10^34 unités, toutes comprises dans la fourchette de prix ultra-compressée créée par l'effondrement des ticks.
Cela a été rendu possible par une fonction apparemment anodine : get_amount_by_liquidity. Dans des conditions normales, cette fonction calcule la quantité de jeton A et de jeton B nécessaire pour correspondre à un certain niveau de liquidité. Pour ce faire, il utilise des fonctions d'assistance telles que get_delta_a, qui repose sur get_sqrt_price_at_tick.
Cependant, étant donné que le tick actuel manipulé était de -138185 et que la plage de ticks choisie se situait bien en dehors de cette plage (à partir de 300 000), le chemin logique dans get_amount_by_liquidity garantissait que les calculs passeraient par une section vulnérable du code impliquant une opération de décalage vers la gauche (checked_shlw).
Débordement et troncature : la principale vulnérabilité
C'est là que l'exploit devient vraiment technique. La fonction checked_show est censée gérer le décalage de 64 bits vers la gauche d'un nombre de 256 bits. Dans les environnements similaires à Solidity, une telle opération est risquée car elle peut déborder. Cette implémentation particulière a tenté de détecter les débordements en vérifiant si l'entrée dépassait un seuil prédéfini : 0xffffffffffffff << 192.
Le seuil réel pour détecter un décalage sécurisé de 64 bits doit être de 2^ (256 - 64) - 1. Cependant, (0xffffffffffffffff << 192) est supérieur à 2^192. Cela signifie qu'une entrée soigneusement sélectionnée pourrait contourner le contrôle de débordement en étant inférieure au seuil utilisé dans le code, tout en restant suffisamment grande pour provoquer un débordement lors de l'exécution.
L'attaquant a fourni une telle entrée, où la multiplication de la liquidité et de la différence de prix a débordé silencieusement, renvoyant une valeur bien inférieure à celle prévue, presque nulle en fait.
En conséquence, le protocole a calculé que l'attaquant n'avait besoin que de payer un montant insignifiant de jeton, essentiellement une unité, pour ajouter des liquidités massives au pool. Cette erreur de calcul a permis à l'attaquant d'injecter des liquidités massives sans aucun coût réel.
Par la suite, l'attaquant a supprimé les liquidités supplémentaires via remove_liquidity et a terminé l'attaque en payant les jetons impayés de flash_swap via repay_flash_swap. L'attaquant a réalisé un bénéfice de 5 765 124 SUI et 10 024 321 HasUI. Enfin, l'équipe de Cetus a corrigé la vulnérabilité grâce à deux PR :
https://github.com/CetusProtocol/integer-mate/pull/6/files
Cetus a rapidement publié un correctif sur son référentiel Integer-Mate, la première pull request tentant d'affiner la détection des débordements. Cependant, ce correctif initial était inadéquat. Il a utilisé un masque de 1 << 192, ce qui laissait toujours passer les valeurs des majuscules.
Une deuxième demande d'extraction a suivi d'une comparaison plus stricte, vérifiant que l'entrée est supérieure ou égale à 2^192, garantissant ainsi des limites appropriées pour un décalage vers la gauche en toute sécurité. Ce n'est qu'avec cette correction que la vulnérabilité a été efficacement atténuée.
- Sui
La cause première n'était pas une erreur logique dans la mécanique DeFi, mais une incapacité à détecter correctement le comportement de débordement dans une opération arithmétique de bas niveau