L'attaque de prêt flash du 13 mars contre Euler Finance a entraîné des pertes de plus de 195 millions de dollars. Cela a provoqué une contagion à travers plusieurs protocoles de finance décentralisée (DeFi), et au moins 11 protocoles autres qu'Euler ont subi des pertes dues à l'attaque.

Au cours des 23 jours suivants, et au grand soulagement de nombreux utilisateurs d'Euler, l'attaquant a restitué tous les fonds exploités.

Mais même si la communauté crypto peut se réjouir du retour des fonds, la question reste de savoir si des attaques similaires pourraient entraîner des pertes massives à l’avenir.

Une analyse de la manière dont l’attaque s’est produite et de la possibilité pour les développeurs et les utilisateurs de faire quelque chose pour aider à prévenir ce type d’attaques à l’avenir peut être utile.

Heureusement, la documentation destinée aux développeurs d’Euler explique clairement le fonctionnement du protocole et la blockchain elle-même a conservé un enregistrement complet de l’attaque.

Comment fonctionne Euler Finance

Selon les documents officiels du protocole, Euler est une plateforme de prêt similaire à Compound ou Aave. Les utilisateurs peuvent déposer des crypto-monnaies et autoriser le protocole à les prêter à d’autres, ou ils peuvent utiliser un dépôt comme garantie pour emprunter des crypto-monnaies.

La valeur de la garantie d’un utilisateur doit toujours être supérieure à ce qu’il emprunte. Supposons que la garantie d’un utilisateur tombe en dessous d’un ratio spécifique entre la valeur de la garantie et la valeur de la dette. Dans ce cas, la plateforme lui permettra d’être « liquidé », ce qui signifie que sa garantie sera vendue pour rembourser ses dettes. Le montant exact de la garantie dont un utilisateur a besoin dépend de l’actif déposé par rapport à l’actif emprunté.

Les eTokens sont des actifs, tandis que les dTokens sont des dettes

Chaque fois que les utilisateurs effectuent un dépôt sur Euler, ils reçoivent des eTokens représentant les pièces déposées. Par exemple, si un utilisateur dépose 1 000 USD Coin (USDC), il recevra le même montant d'eUSDC en échange.

Étant donné qu’ils valent plus que les pièces sous-jacentes à mesure que le dépôt génère des intérêts, les eTokens n’ont pas de correspondance 1:1 avec l’actif sous-jacent en termes de valeur.

Euler permet également aux utilisateurs de bénéficier d'un effet de levier en créant des eTokens. Mais s'ils le font, le protocole leur enverra des jetons de dette (dTokens) pour équilibrer les actifs créés.

Par exemple, les documents indiquent que si un utilisateur dépose 1 000 USDC, il peut créer 5 000 eUSDC. Cependant, s'il le fait, le protocole lui enverra également 5 000 jetons de dette appelés « dUSDC ».

La fonction de transfert d'un dToken est écrite différemment de celle d'un jeton ERC-20 standard. Si vous possédez un jeton de dette, vous ne pouvez pas le transférer à une autre personne, mais n'importe qui peut vous prendre un dToken s'il le souhaite.

Selon les documents d'Euler, un utilisateur ne peut créer qu'autant d'eTokens qu'il aurait pu le faire en déposant et en empruntant encore et encore, comme il est indiqué : « La fonction Mint imite ce qui se passerait si un utilisateur déposait 1 000 USDC, puis empruntait 900 USDC, puis redéposait ces 900 USDC, pour emprunter 810 USDC supplémentaires, et ainsi de suite. »

Les utilisateurs sont liquidés si les scores de santé tombent à 1 ou moins

Selon un article de blog d’Euler, chaque utilisateur a un « score de santé » basé sur la valeur des eTokens détenus dans son portefeuille par rapport à la valeur des dTokens détenus. Un utilisateur doit avoir une valeur en dollars plus élevée d’eTokens que de dTokens, mais la valeur de cette valeur dépend des pièces particulières qu’il emprunte ou dépose. Quoi qu’il en soit, un utilisateur disposant de suffisamment d’eTokens aura un score de santé supérieur à 1.

Si l’utilisateur tombe à peine en dessous du nombre requis d’eTokens, son score de santé sera exactement de 1. Cela le soumettra à une « liquidation douce ». Les robots liquidateurs peuvent appeler une fonction pour transférer une partie des eTokens et des dTokens de l’utilisateur à eux-mêmes jusqu’à ce que le score de santé de l’emprunteur revienne à 1,25. Étant donné qu’un utilisateur qui est à peine en dessous des exigences de garantie aura toujours plus de garanties que de dettes, le liquidateur devrait tirer profit de cette transaction.

Si le score de santé d'un utilisateur tombe en dessous de 1, une remise croissante est accordée au liquidateur en fonction de la gravité du score de santé. Plus le score de santé est mauvais, plus la remise accordée au liquidateur est importante. Cette mesure vise à garantir que quelqu'un liquidera toujours un compte avant qu'il n'accumule trop de créances irrécouvrables.

Le message d’Euler affirme que d’autres protocoles offrent une « remise fixe » pour la liquidation et explique pourquoi il pense que les remises variables sont supérieures.

Comment s'est produite l'attaque d'Euler

Les données de la blockchain révèlent que l'attaquant s'est livré à une série d'attaques qui ont drainé divers jetons du protocole. La première attaque a drainé environ 8,9 millions de dollars de Dai (DAI) du pool de dépôt Dai. Elle a ensuite été répétée encore et encore pour d'autres pools de dépôt jusqu'à ce que le montant total soit épuisé.

L'attaquant a utilisé trois adresses Ethereum différentes pour mener l'attaque. La première était un contrat intelligent, qu'Etherscan a baptisé « Euler Exploit Contract 1 », utilisé pour emprunter à Aave. La deuxième adresse a été utilisée pour déposer et emprunter à Euler, et la troisième a été utilisée pour effectuer une liquidation.

Pour éviter d'avoir à indiquer à plusieurs reprises les adresses qu'Etherscan n'a pas étiquetées, le deuxième compte sera appelé « Emprunteur » et le troisième compte « Liquidateur », comme indiqué ci-dessous :

Adresses Ethereum utilisées par le pirate. Source : Etherscan

La première attaque consistait en 20 transactions dans le même bloc.

Dans un premier temps, Euler Exploit Contract 1 a emprunté 30 millions de DAI à Aave sous forme de prêt flash. Il a ensuite envoyé ce prêt sur le compte de l'emprunteur.

Après avoir reçu les 30 millions de DAI, l'emprunteur en a déposé 20 millions auprès d'Euler. Euler a ensuite réagi en émettant environ 19,6 millions d'eDAI et en les envoyant à l'emprunteur.

Ces pièces eDAI étaient un reçu pour le dépôt, donc un montant correspondant de dDai n'a pas été frappé au cours du processus. Et comme chaque eDAI peut être échangé contre un peu plus d'un DAI, l'emprunteur n'a reçu que 19,6 millions au lieu des 20 millions.

Après avoir effectué ce dépôt initial, l'emprunteur a émis environ 195,7 millions d'eDAI. En réponse, Euler a émis 200 millions d'eDAI et les a envoyés à l'emprunteur.

À ce stade, l’emprunteur était proche de sa limite de mint eDAI, car il avait emprunté environ 10 fois le montant de DAI qu’il avait déposé. L’étape suivante consistait donc à rembourser une partie de ses dettes. Il a déposé les 10 millions de DAI restants qu’il avait conservés, remboursant ainsi 10 millions de dollars du prêt. En réponse, Euler a retiré 10 millions de dDAI du portefeuille de l’emprunteur et l’a brûlé, réduisant ainsi sa dette de 10 millions de dollars.

L'attaquant a ensuite pu créer davantage d'eDAI. L'emprunteur a ainsi créé 195,7 millions d'eDAI supplémentaires, portant son total d'eDAI à environ 391,4 millions. Les 19,6 millions d'eDAI des reçus de dépôt ont porté le total d'eDAI de l'emprunteur à environ 411 millions.

En réponse, Euler a émis 200 millions de dDai supplémentaires et les a envoyés à l’emprunteur, portant la dette totale de ce dernier à 400 millions de dollars.

Une fois que l'emprunteur a maximisé sa capacité de frappe d'eDAI, il a envoyé 100 millions d'eDai à l'adresse nulle, la détruisant ainsi efficacement.

Cela a fait passer leur score de santé bien en dessous de 1, car ils avaient désormais 400 millions de dollars de dettes contre environ 320 millions de dollars d’actifs.

C'est là qu'intervient le compte liquidateur. Il s'agit de la fonction de liquidation, qui saisit l'adresse de l'emprunteur comme compte à liquider.

Événement de liquidation émis lors de l'attaque d'Euler. Source : données de la blockchain Ethereum

En réponse, Euler a lancé le processus de liquidation. Il a d'abord pris environ 254 millions de dDAI à l'emprunteur et les a détruits, puis a émis 254 millions de nouveaux dDai et les a transférés au liquidateur. Ces deux étapes ont transféré 254 millions de dollars de dette de l'emprunteur au liquidateur.

Ensuite, Euler a émis 5,08 millions de dDAI supplémentaires et les a envoyés au liquidateur. La dette de ce dernier s’est ainsi élevée à 260 millions de dollars. Enfin, Euler a transféré environ 310,9 millions de dDAI de l’emprunteur au liquidateur, achevant ainsi le processus de liquidation.

Au final, l'emprunteur s'est retrouvé sans eDAI, sans DAI et avec 146 millions de dDAI. Cela signifie que le compte n'avait aucun actif et une dette d'une valeur de 146 millions de dollars.

D'autre part, le liquidateur disposait d'environ 310,9 millions d'eDAI et seulement 260 millions de dDAI.

Une fois la liquidation terminée, le liquidateur a racheté 38 millions d'eDAI (38,9 millions de dollars), recevant en échange 38,9 millions de DAI. Il a ensuite restitué 30 millions de DAI plus les intérêts à Euler Exploiter Contract 1, que le contrat a utilisé pour rembourser le prêt d'Aave.

Au final, le liquidateur s'est retrouvé avec environ 8,9 millions de dollars de bénéfices qui ont été exploités auprès d'autres utilisateurs du protocole.

Cette attaque a été répétée pour plusieurs autres jetons, dont Wrapped Bitcoin (WBTC), Staked Ether (stETH) et USDC, pour un montant de 197 millions de dollars en crypto-monnaies exploitées.

Pertes dues à l'attaque d'Euler. Source : Blocksec Qu'est-ce qui s'est passé lors de l'attaque d'Euler ?

Les sociétés de sécurité blockchain Omniscia et SlowMist ont analysé l'attaque pour tenter de déterminer ce qui aurait pu l'empêcher.

Selon un rapport du 13 mars d’Omniscia, le principal problème d’Euler était sa fonction « donateToReserves ». Cette fonction permettait à l’attaquant de faire don de son eDAI aux réserves d’Euler, supprimant ainsi des actifs de son portefeuille sans supprimer le montant correspondant de la dette. Omnisica indique que cette fonction n’était pas présente dans la version originale d’Euler mais qu’elle a été introduite dans la proposition d’amélioration d’Euler 14 (eIP-14).

Le code de l'eIP-14 révèle qu'il a créé une fonction appelée donateToReserves, qui permet à l'utilisateur de transférer des jetons de son propre solde vers une variable de protocole appelée « assetStorage.reserveBalance ». Chaque fois que cette fonction est appelée, le contrat émet un événement « RequestDonate » qui fournit des informations sur la transaction.

Les données de la blockchain montrent que cet événement RequestDonate a été émis pour une valeur de 100 millions de jetons. C'est le montant exact qui, selon Etherscan, a été brûlé, poussant le compte vers l'insolvabilité.

L'événement RequestDonate d'Euler est émis pendant l'attaque. Source : données de la blockchain Ethereum

Dans leur analyse du 15 mars, SlowMist a convenu avec Omniscia de l'importance de la fonction donateToReserve, déclarant :

« Le fait de ne pas vérifier si l’utilisateur était en état de liquidation après avoir fait don de fonds à l’adresse de réserve a entraîné le déclenchement direct du mécanisme de liquidation douce. »

L'attaquant aurait également pu mener l'attaque même si la fonction de don n'avait pas existé. Le code du contrat Euler « EToken.sol » sur GitHub contient une fonction « transfer » ERC-20 standard. Cela semble impliquer que l'attaquant aurait pu transférer ses eTokens à un autre utilisateur aléatoire ou à l'adresse nulle au lieu de faire un don, se mettant de toute façon en faillite.

Fonction de transfert de contrat Euler eToken. Source : GitHub

Cependant, l’attaquant a choisi de faire don des fonds plutôt que de les transférer, ce qui suggère que le transfert n’aurait pas fonctionné.

Cointelegraph a contacté Omniscia, SlowMist et l'équipe d'Euler pour savoir si la fonction donateToReserves était essentielle à l'attaque. Cependant, aucune réponse n'a été reçue au moment de la publication.

Les deux entreprises ont convenu qu’une autre vulnérabilité majeure d’Euler était les rabais importants offerts aux liquidateurs. Selon SlowMist, lorsqu’un protocole de prêt dispose d’un « mécanisme de liquidation qui met à jour dynamiquement les rabais », il « crée des opportunités d’arbitrage lucratives pour les attaquants qui peuvent siphonner une grande quantité de garanties sans avoir besoin de garanties ou de remboursement de dettes ». Omniscia a fait des observations similaires, déclarant :

« Lorsque le contrevenant se liquide, une décote basée sur un pourcentage est appliquée [...] garantissant qu'il sera « hors d'eau » et qu'il n'encourra que la dette correspondant à la garantie qu'il acquerra. »

Comment prévenir une future attaque d'Euler

Dans son analyse, SlowMist a conseillé aux développeurs comment prévenir une nouvelle attaque de type Euler à l'avenir. L'entreprise a fait valoir que les protocoles de prêt ne devraient pas permettre aux utilisateurs de détruire des actifs si cela les amène à créer de mauvaises créances, et a affirmé que les développeurs devraient être prudents lorsqu'ils utilisent plusieurs modules qui peuvent interagir les uns avec les autres de manière inattendue :

« L’équipe de sécurité de SlowMist recommande que les protocoles de prêt intègrent les contrôles de santé nécessaires dans les fonctions impliquant les fonds des utilisateurs, tout en tenant compte des risques de sécurité qui peuvent découler de la combinaison de différents modules. Cela permettra de concevoir des modèles économiques sûrs et viables qui atténueront efficacement de telles attaques à l’avenir. »

Un représentant du développeur DeFi Spool a déclaré à Cointelegraph que le risque technologique est une caractéristique intrinsèque de l’écosystème DeFi. Bien qu’il ne puisse pas être éliminé, il peut être atténué grâce à des modèles qui évaluent correctement les risques des protocoles.

Selon le livre blanc sur la gestion des risques de Spool, l’entreprise utilise une « matrice de risques » pour déterminer le niveau de risque des protocoles. Cette matrice prend en compte des facteurs tels que le rendement annuel en pourcentage (APY) du protocole, les audits effectués sur ses contrats, le temps écoulé depuis son déploiement, la valeur totale bloquée (TVL) et d’autres facteurs pour créer une évaluation du risque. Les utilisateurs de Spool peuvent utiliser cette matrice pour diversifier les investissements DeFi et limiter les risques.

Le représentant a déclaré à Cointelegraph que la matrice de Spool avait considérablement réduit les pertes des investisseurs suite à l'incident d'Euler.

« Dans cet incident, les coffres-forts intelligents les plus touchés, ceux conçus par les utilisateurs pour rechercher des rendements plus élevés (et plus risqués), n'ont été affectés qu'à hauteur de 35 %. Le coffre-fort le moins touché, exposé aux stratégies Euler (via Harvest ou Idle), en comparaison, n'a été affecté que de 6 %. Certains coffres-forts n'avaient aucune exposition et n'ont donc pas été impactés », ont-ils déclaré.

Spool a poursuivi : « Bien que cela ne soit pas idéal, cela démontre clairement la capacité des Smart Vaults à fournir des modèles de risque personnalisés et à répartir les fonds des utilisateurs entre plusieurs sources de rendement. »

Cointelegraph a reçu une réponse similaire de SwissBorg, un autre protocole DeFi qui vise à aider les utilisateurs à limiter les risques grâce à la diversification. Le PDG de SwissBorg, Cyrus Fazel, a déclaré que l'application SwissBorg propose « différentes stratégies de rendement basées sur le rapport risque/temps/APY ».

Certaines stratégies sont répertoriées comme « 1 : cœur = faible », tandis que d’autres sont répertoriées comme « 2 : aventureux = risqué ». Comme Euler a reçu une note de « 2 », les pertes du protocole ont été limitées à une petite partie de la valeur totale bloquée de SwissBorg, a déclaré Fazel.

Nicolas Rémond, responsable de l'ingénierie de SwissBorg, a également précisé que l'équipe utilise des critères sophistiqués pour déterminer quels protocoles peuvent être répertoriés dans l'application SwissBorg.

« Nous avons un processus de due diligence pour toutes les plateformes DeFi avant d’entrer dans une position. Et puis, une fois que nous y sommes, nous avons des procédures opérationnelles », a-t-il déclaré, ajoutant : « La due diligence concerne la TVL, l’équipe, les audits, le code open source, la TVL, les attaques de manipulation d’oracle, etc. […] La procédure opérationnelle concerne la surveillance de la plateforme, la surveillance des médias sociaux et certaines mesures d’urgence. Certaines sont encore manuelles, mais nous investissons pour tout automatiser afin de pouvoir être extrêmement réactifs. »

Dans un fil Twitter du 13 mars, l'équipe de SwissBorg a déclaré que même si le protocole avait perdu 2,2 % des fonds d'un pool et 29,52 % d'un autre, tous les utilisateurs seraient indemnisés par SwissBorg si les fonds n'étaient pas récupérables auprès d'Euler.

L'attaque d'Euler a été la pire exploitation DeFi du premier trimestre 2023. Heureusement, l'attaquant a restitué la plupart des fonds, et la plupart des utilisateurs ne devraient subir aucune perte au final. Mais l'attaque soulève des questions sur la manière dont les développeurs et les utilisateurs peuvent limiter les risques alors que l'écosystème DeFi continue de se développer.

Une combinaison de diligence des développeurs et de diversification des investisseurs pourrait être la solution au problème. Mais quoi qu’il en soit, le piratage d’Euler pourrait continuer à faire l’objet de discussions à l’avenir, ne serait-ce que pour son ampleur et son illustration des risques des exploits DeFi.